home *** CD-ROM | disk | FTP | other *** search
- /* Authentication functions, to keep everything secure
-
- ©1998, 1999 Joseph Walton
-
- This software is distributed under the terms of the GNU General Public
- License; either version 2 of the License, or (at your option) any
- later version.
- */
-
- /*
- AmigaOS has no intrinsic concept of permissions, other than the single
- user ones. Therefore it's up to us to reimplement Unix-style
- protection throughout. There are many gotchas we have to take
- care of, and protection probably needs to be more integrated.
- */
-
- /*
- 24-Aug-1999 - Some changes to the semantics of root's permissions.
- 30-Nov-1999 - Changes to support new RPC code.
- */
-
- #include "auth.h"
- #include "rpc.h"
- #include "nfs.h"
- #include "config.h"
- #include "handle_list.h"
-
- #include <dos/dos.h>
-
- #include <proto/socket.h>
- #include <stdio.h>
-
- #include <dos/dos.h>
- #include <exec/lists.h>
-
- BOOL allow_root = FALSE; /* This may be changed by nfsd.c */
- BOOL allow_nonpriv_port = FALSE;
-
- /* This is the One True definition of being root - a UID of zero */
- #define ROOT_UID (0)
-
- extern struct List cfg_list; /* In config.c */
- extern struct FileInfoBlock fib; /* In nfs_functions.c */
-
- BOOL is_group_member(UWORD gid, struct authunix *auth);
-
- /* A simple front-end that does the most common checkings
- It assumes the file has been Examine()'d */
- nfsstat check_permission(struct Call *call, struct LocalFile *lf,
- ULONG permission)
- {
- nfsstat status;
-
- /* First, is this allowed by the exports? */
- status = does_mount_permit(call, lf->lf_Name, permission);
-
- /* Does the file itself allow this operation? */
- if (status == NFS_OK) {
- status = does_file_allow(call,
- (lf->lf_ForcedUID != -1) ? lf->lf_ForcedUID : fib.fib_OwnerUID,
- (lf->lf_ForcedGID != -1) ? lf->lf_ForcedGID : fib.fib_OwnerGID,
- ((lf->lf_ForcedProtection != -1)
- ? lf->lf_ForcedProtection
- : fib.fib_Protection),
- permission);
- }else
- puts("Export file does not allow that operation");
-
- return status;
- }
-
- /* Is this operation allowed according to the user-configured exports? */
- nfsstat does_mount_permit(struct Call *call,
- STRPTR path, ULONG permission)
- {
- nfsstat result = NFSERR_ACCES;
-
- struct ConfigEntry *ce;
-
- struct sockaddr_in *client_addr = &(call->c_from);
-
- /* First of all, is this from a non-privileged port? */
- if ((ntohs(client_addr->sin_port) >= IPPORT_RESERVED)
- && !allow_nonpriv_port)
- {
- return result;
- }
-
- ce = cfg_list.lh_Head;
-
- while (ce->ce_Node.mln_Succ) {
- /* Does this entry concern this path? */
-
- /* Is ce->ce_Path a prefix of path? */
- if ((STRPTR)strstr(path, ce->ce_Path) == path) {
- /* Does this line export to this IP address? */
- if (0 == ((ntohl(client_addr->sin_addr.s_addr) ^ ce->ce_ExportIP) & ce->ce_IPMask)) {
- /* Is this export as writeable as needs be? */
- switch (permission) {
- case ALLOW_READ:
- case ALLOW_GETATTRS:
- return NFS_OK;
-
- case ALLOW_WRITE:
- case ALLOW_SETATTRS:
- if (ce->ce_ReadWrite)
- return NFS_OK;
- /* Otherwise, keep trying, but if we fail then this is why */
- result = NFSERR_ROFS;
- break;
-
- default:
- result = NFSERR_ACCES; /* WHAT are they trying? */
- }
- }
- }
-
- ce = (struct ConfigEntry *)ce->ce_Node.mln_Succ;
- }
-
- /* We've failed, but this error code should explain why */
- return result;
- }
-
- #define ID_MATCH(a,b) (((a) == (b)) && (allow_root || ((a) != 0)))
-
- /* Is this operation allowed according to file ownership and
- permissions? */
- nfsstat does_file_allow(struct Call *call, UWORD uid, UWORD gid,
- LONG prot, ULONG permission)
- {
- struct authunix *auth = &(call->c_auth);
-
- /* We need UNIX authentication for this - otherwise we reject */
- if (!auth->isUnix)
- return NFSERR_ACCES;
-
- #define RV(x) ((x)?NFS_OK:NFSERR_ACCES)
-
- /* First of all, are they root? (And are we accepting root access?) */
- if (allow_root && (uid == ROOT_UID)) {
- switch (permission) {
- case ALLOW_READ:
- case ALLOW_WRITE:
- case ALLOW_GETATTRS:
- case ALLOW_SETATTRS:
- return RV(TRUE); /* root can do anything */
-
- default:
- return RV(FALSE);
- }
- }
-
- /* Now, do they own this file? */
- if (ID_MATCH(uid, auth->uid)) {
- switch (permission) {
- case ALLOW_READ:
- return RV((prot & FIBF_READ) == 0);
-
- case ALLOW_WRITE:
- return RV((prot & FIBF_WRITE) == 0);
-
- case ALLOW_GETATTRS:
- case ALLOW_SETATTRS:
- return RV(TRUE);
-
- default:
- return RV(FALSE);
- }
- }
-
- /* Soo... are they a member of the group? */
- if (is_group_member(gid, auth)) {
- switch (permission) {
- case ALLOW_READ:
- case ALLOW_GETATTRS:
- return RV(prot & FIBF_GRP_READ);
-
- case ALLOW_WRITE:
- return RV(prot & FIBF_GRP_WRITE);
-
- case ALLOW_SETATTRS: /* I'm not sure about this one... */
- return RV(FALSE);
-
- default:
- return RV(FALSE);
- }
- }
-
- /* Then they're "other" */
- switch (permission) {
- case ALLOW_READ:
- case ALLOW_GETATTRS:
- return RV(prot & FIBF_OTR_READ);
-
- case ALLOW_WRITE:
- return RV(prot & FIBF_OTR_WRITE);
-
- case ALLOW_SETATTRS: /* Nor this one... */
- return RV(FALSE);
-
- default:
- return RV(FALSE);
- }
-
- #undef RV
- }
-
- BOOL is_group_member(UWORD gid, struct authunix *auth)
- {
- int i;
-
- /* First, is it their primary group? */
-
- if (ID_MATCH(gid, auth->gid))
- return TRUE;
-
- /* Is it one of their supplementary groups? */
- for (i = 0 ; i < auth->numGids ; i++) {
- if (ID_MATCH(gid, auth->gids[i]))
- return TRUE;
- }
-
- /* Nope - not a member */
- return FALSE;
- }
-
- #undef ID_MATCH
-
- /* This gets the owner we should attribute this request to */
- LONG owner_of(struct Call *call)
- {
- if (call && call->c_auth.isUnix) {
- return ((call->c_auth.uid << 16) | call->c_auth.gid);
- }
-
- /* Fall through, and give it to root */
- return ROOT_UID;
- }
-
- /* This summarises the Unix authentication being offered */
- void print_auth(struct Call *call)
- {
- struct sockaddr_in *addr = &(call->c_from);
-
- /* This could probably be done in a more elegant fashion */
- printf("%s:%d ", Inet_NtoA(addr->sin_addr.s_addr), ntohs(addr->sin_port));
-
- /* Hey - let's summarise the authentication! */
- struct authunix *auth = &(call->c_auth);
- if (auth->isUnix) {
- printf("[UID %ld, GID %ld, %ld other groups]\n",
- auth->uid, auth->gid, auth->numGids);
-
- /* This bit is a little too verbose... */
- /* for (int i = 0 ; i < auth->numGids ; i++) {
- printf("Member of %d\n", auth->gids[i]);
- } */
- } else
- puts("[Was not AUTH_UNIX]");
-
- /* If this is set some routines may wish to avoid printing it again */
- call->c_hasBeenPrinted = TRUE;
- }
-
- /* Print authorisation, unless it has already been printed */
- void print_auth_once(struct Call *call)
- {
- if (!call->c_hasBeenPrinted) {
- print_auth(call);
- }
- }
-
- /* Impose any constraints dictated by the configuration on this LocalFile */
- void impose_configuration(struct LocalFile *lf)
- {
- struct ConfigEntry *ce;
- STRPTR path;
-
- if (!lf)
- return;
-
- path = lf->lf_Name;
-
- ce = cfg_list.lh_Head;
-
- while (ce->ce_Node.mln_Succ) {
- /* Is ce->ce_Path a prefix of path? */
- if ((STRPTR)strstr(path, ce->ce_Path) == path) {
- /* Is this configuration entry ForceAll'd? */
- if (ce->ce_ForceAll) {
- lf->lf_ForcedUID = ce->ce_UID;
- lf->lf_ForcedGID = ce->ce_GID;
- lf->lf_ForcedProtection = ce->ce_Protection;
- }
- }
- ce = (struct ConfigEntry *)ce->ce_Node.mln_Succ;
- }
- }
-
-