home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / nfsd / src / auth.c next >
Encoding:
C/C++ Source or Header  |  1999-11-30  |  8.2 KB  |  301 lines

  1. /*  Authentication functions, to keep everything secure
  2.  
  3.     ©1998, 1999 Joseph Walton
  4.  
  5.     This software is distributed under the terms of the GNU General Public
  6.     License; either version 2 of the License, or (at your option) any
  7.     later version.
  8. */
  9.  
  10. /*
  11.    AmigaOS has no intrinsic concept of permissions, other than the single
  12.     user ones. Therefore it's up to us to reimplement Unix-style
  13.     protection throughout. There are many gotchas we have to take
  14.     care of, and protection probably needs to be more integrated.
  15. */
  16.  
  17. /*
  18.     24-Aug-1999 - Some changes to the semantics of root's permissions.
  19.     30-Nov-1999 - Changes to support new RPC code.
  20. */
  21.  
  22. #include "auth.h"
  23. #include "rpc.h"
  24. #include "nfs.h"
  25. #include "config.h"
  26. #include "handle_list.h"
  27.  
  28. #include <dos/dos.h>
  29.  
  30. #include <proto/socket.h>
  31. #include <stdio.h>
  32.  
  33. #include <dos/dos.h>
  34. #include <exec/lists.h>
  35.  
  36. BOOL allow_root = FALSE; /* This may be changed by nfsd.c */
  37. BOOL allow_nonpriv_port = FALSE;
  38.  
  39. /* This is the One True definition of being root - a UID of zero */
  40. #define ROOT_UID (0)
  41.  
  42. extern struct List cfg_list; /* In config.c */
  43. extern struct FileInfoBlock fib; /* In nfs_functions.c */
  44.  
  45. BOOL is_group_member(UWORD gid, struct authunix *auth);
  46.  
  47. /* A simple front-end that does the most common checkings
  48.     It assumes the file has been Examine()'d */
  49. nfsstat check_permission(struct Call *call, struct LocalFile *lf,
  50.     ULONG permission)
  51. {
  52.     nfsstat status;
  53.  
  54.     /* First, is this allowed by the exports? */
  55.     status = does_mount_permit(call, lf->lf_Name, permission);
  56.  
  57.     /* Does the file itself allow this operation? */
  58.     if (status == NFS_OK) {
  59.         status = does_file_allow(call,
  60.             (lf->lf_ForcedUID != -1) ? lf->lf_ForcedUID : fib.fib_OwnerUID,
  61.             (lf->lf_ForcedGID != -1) ? lf->lf_ForcedGID : fib.fib_OwnerGID,
  62.             ((lf->lf_ForcedProtection != -1)
  63.                 ? lf->lf_ForcedProtection
  64.                 : fib.fib_Protection),
  65.             permission);
  66.     }else
  67.         puts("Export file does not allow that operation");
  68.  
  69.     return status;
  70. }
  71.  
  72. /* Is this operation allowed according to the user-configured exports? */
  73. nfsstat does_mount_permit(struct Call *call,
  74.     STRPTR path, ULONG permission)
  75. {
  76.     nfsstat result = NFSERR_ACCES;
  77.  
  78.     struct ConfigEntry *ce;
  79.  
  80.     struct sockaddr_in *client_addr = &(call->c_from);
  81.  
  82.     /* First of all, is this from a non-privileged port? */
  83.     if ((ntohs(client_addr->sin_port) >= IPPORT_RESERVED)
  84.         && !allow_nonpriv_port)
  85.     {
  86.         return result;
  87.     }
  88.  
  89.     ce = cfg_list.lh_Head;
  90.  
  91.     while (ce->ce_Node.mln_Succ) {
  92.         /* Does this entry concern this path? */
  93.  
  94.         /* Is ce->ce_Path a prefix of path? */
  95.         if ((STRPTR)strstr(path, ce->ce_Path) == path) {
  96.             /* Does this line export to this IP address? */
  97.             if (0 == ((ntohl(client_addr->sin_addr.s_addr) ^ ce->ce_ExportIP) & ce->ce_IPMask)) {
  98.                 /* Is this export as writeable as needs be? */
  99.                 switch (permission) {
  100.                     case ALLOW_READ:
  101.                     case ALLOW_GETATTRS:
  102.                         return NFS_OK;
  103.  
  104.                     case ALLOW_WRITE:
  105.                     case ALLOW_SETATTRS:
  106.                        if (ce->ce_ReadWrite)
  107.                             return NFS_OK;
  108.                        /* Otherwise, keep trying, but if we fail then this is why */
  109.                        result = NFSERR_ROFS;
  110.                        break;
  111.  
  112.                     default:
  113.                         result = NFSERR_ACCES; /* WHAT are they trying? */
  114.                 }
  115.             }
  116.         }
  117.  
  118.         ce = (struct ConfigEntry *)ce->ce_Node.mln_Succ;
  119.     }
  120.  
  121.     /* We've failed, but this error code should explain why */
  122.     return result;
  123. }
  124.  
  125. #define ID_MATCH(a,b) (((a) == (b)) && (allow_root || ((a) != 0)))
  126.  
  127. /* Is this operation allowed according to file ownership and
  128.     permissions? */
  129. nfsstat does_file_allow(struct Call *call, UWORD uid, UWORD gid,
  130.     LONG prot, ULONG permission)
  131. {
  132.     struct authunix *auth = &(call->c_auth);
  133.  
  134.     /* We need UNIX authentication for this - otherwise we reject */
  135.     if (!auth->isUnix)
  136.         return NFSERR_ACCES;
  137.  
  138.     #define RV(x) ((x)?NFS_OK:NFSERR_ACCES)
  139.  
  140.     /* First of all, are they root? (And are we accepting root access?) */
  141.     if (allow_root && (uid == ROOT_UID)) {
  142.         switch (permission) {
  143.             case ALLOW_READ:
  144.             case ALLOW_WRITE:
  145.             case ALLOW_GETATTRS:
  146.             case ALLOW_SETATTRS:
  147.                 return RV(TRUE); /* root can do anything */
  148.  
  149.             default:
  150.                 return RV(FALSE);
  151.        }
  152.     }
  153.  
  154.     /* Now, do they own this file? */
  155.     if (ID_MATCH(uid, auth->uid)) {
  156.         switch (permission) {
  157.             case ALLOW_READ:
  158.                 return RV((prot & FIBF_READ) == 0);
  159.  
  160.             case ALLOW_WRITE:
  161.                 return RV((prot & FIBF_WRITE) == 0);
  162.  
  163.             case ALLOW_GETATTRS:
  164.             case ALLOW_SETATTRS:
  165.                 return RV(TRUE);
  166.  
  167.             default:
  168.                 return RV(FALSE);
  169.         }
  170.     }
  171.  
  172.     /* Soo... are they a member of the group? */
  173.     if (is_group_member(gid, auth)) {
  174.         switch (permission) {
  175.             case ALLOW_READ:
  176.             case ALLOW_GETATTRS:
  177.                 return RV(prot & FIBF_GRP_READ);
  178.  
  179.             case ALLOW_WRITE:
  180.                 return RV(prot & FIBF_GRP_WRITE);
  181.  
  182.             case ALLOW_SETATTRS: /* I'm not sure about this one... */
  183.                 return RV(FALSE);
  184.  
  185.             default:
  186.                 return RV(FALSE);
  187.         }
  188.     }
  189.  
  190.     /* Then they're "other" */
  191.     switch (permission) {
  192.         case ALLOW_READ:
  193.         case ALLOW_GETATTRS:
  194.             return RV(prot & FIBF_OTR_READ);
  195.  
  196.         case ALLOW_WRITE:
  197.             return RV(prot & FIBF_OTR_WRITE);
  198.  
  199.         case ALLOW_SETATTRS: /* Nor this one... */
  200.             return RV(FALSE);
  201.  
  202.         default:
  203.             return RV(FALSE);
  204.     }
  205.  
  206.     #undef RV
  207. }
  208.  
  209. BOOL is_group_member(UWORD gid, struct authunix *auth)
  210. {
  211.     int i;
  212.  
  213.     /* First, is it their primary group? */
  214.  
  215.     if (ID_MATCH(gid, auth->gid))
  216.         return TRUE;
  217.  
  218.     /* Is it one of their supplementary groups? */
  219.     for (i = 0 ; i < auth->numGids ; i++) {
  220.         if (ID_MATCH(gid, auth->gids[i]))
  221.             return TRUE;
  222.     }
  223.  
  224.     /* Nope - not a member */
  225.     return FALSE;
  226. }
  227.  
  228. #undef ID_MATCH
  229.  
  230. /* This gets the owner we should attribute this request to */
  231. LONG owner_of(struct Call *call)
  232. {
  233.     if (call && call->c_auth.isUnix) {
  234.         return ((call->c_auth.uid << 16) | call->c_auth.gid);
  235.     }
  236.  
  237.     /* Fall through, and give it to root */
  238.     return ROOT_UID;
  239. }
  240.  
  241. /* This summarises the Unix authentication being offered */
  242. void print_auth(struct Call *call)
  243. {
  244.     struct sockaddr_in *addr = &(call->c_from);
  245.  
  246.     /* This could probably be done in a more elegant fashion */
  247.     printf("%s:%d ", Inet_NtoA(addr->sin_addr.s_addr), ntohs(addr->sin_port));
  248.  
  249.     /* Hey - let's summarise the authentication! */
  250.     struct authunix *auth = &(call->c_auth);
  251.     if (auth->isUnix) {
  252.         printf("[UID %ld, GID %ld, %ld other groups]\n",
  253.             auth->uid, auth->gid, auth->numGids);
  254.  
  255. /* This bit is a little too verbose... */
  256. /*        for (int i = 0 ; i < auth->numGids ; i++) {
  257.               printf("Member of %d\n", auth->gids[i]);
  258.           } */
  259.     } else
  260.         puts("[Was not AUTH_UNIX]");
  261.  
  262.     /* If this is set some routines may wish to avoid printing it again */
  263.     call->c_hasBeenPrinted = TRUE;
  264. }
  265.  
  266. /* Print authorisation, unless it has already been printed */
  267. void print_auth_once(struct Call *call)
  268. {
  269.     if (!call->c_hasBeenPrinted) {
  270.         print_auth(call);
  271.     }
  272. }
  273.  
  274. /* Impose any constraints dictated by the configuration on this LocalFile */
  275. void impose_configuration(struct LocalFile *lf)
  276. {
  277.     struct ConfigEntry *ce;
  278.     STRPTR path;
  279.  
  280.     if (!lf)
  281.         return;
  282.  
  283.     path = lf->lf_Name;
  284.  
  285.     ce = cfg_list.lh_Head;
  286.  
  287.     while (ce->ce_Node.mln_Succ) {
  288.         /* Is ce->ce_Path a prefix of path? */
  289.         if ((STRPTR)strstr(path, ce->ce_Path) == path) {
  290.             /* Is this configuration entry ForceAll'd? */
  291.             if (ce->ce_ForceAll) {
  292.                 lf->lf_ForcedUID = ce->ce_UID;
  293.                 lf->lf_ForcedGID = ce->ce_GID;
  294.                 lf->lf_ForcedProtection = ce->ce_Protection;
  295.             }
  296.         }
  297.         ce = (struct ConfigEntry *)ce->ce_Node.mln_Succ;
  298.     }
  299. }
  300.  
  301.