home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / server / check.c < prev    next >
C/C++ Source or Header  |  2009-08-14  |  14KB  |  430 lines

  1. /*
  2.  * (C) 2001 Clemson University and The University of Chicago
  3.  *
  4.  * Changes by Acxiom Corporation to add PINT_check_mode() helper function
  5.  * as a replacement for check_mode() in permission checking, also added
  6.  * PINT_check_group() for supplimental group support 
  7.  * Copyright ┬⌐ Acxiom Corporation, 2005.
  8.  *
  9.  * See COPYING in top-level directory.
  10.  */
  11.  
  12. /*
  13.  * Server-specific utility functions, to check modes and ACLs.
  14.  */
  15. #include <string.h>
  16. #include <assert.h>
  17. #include <pwd.h>
  18. #include <grp.h>
  19.  
  20. #include "pvfs2-debug.h"
  21. #include "gen-locks.h"
  22. #include "gossip.h"
  23. #include "bmi-byteswap.h"
  24. #include "check.h"
  25.  
  26. static gen_mutex_t check_group_mutex = GEN_MUTEX_INITIALIZER;
  27. static int pw_buf_size = 1024;      // 1 KB
  28. static int gr_buf_size = 1024*1024; // 1 MB
  29. static char* check_group_pw_buffer = NULL;
  30. static char* check_group_gr_buffer = NULL;
  31. static int PINT_check_group(uid_t uid, gid_t gid);
  32.  
  33. /* PINT_check_mode()
  34.  *
  35.  * checks to see if the type of access described by "access_type" is permitted 
  36.  * for user "uid" of group "gid" on the object with attributes "attr"
  37.  *
  38.  * returns 0 on success, -PVFS_EACCES if permission is not granted
  39.  */
  40. int PINT_check_mode(
  41.     PVFS_object_attr *attr,
  42.     PVFS_uid uid, PVFS_gid gid,
  43.     enum PINT_access_type access_type)
  44. {
  45.     int in_group_flag = 0;
  46.     int ret = 0;
  47.  
  48.     /* if we don't have masks for the permission information that we
  49.      * need, then the system is broken
  50.      */
  51.     assert(attr->mask & PVFS_ATTR_COMMON_UID &&
  52.            attr->mask & PVFS_ATTR_COMMON_GID &&
  53.            attr->mask & PVFS_ATTR_COMMON_PERM);
  54.  
  55.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - check_mode called --- "
  56.                  "(uid=%d,gid=%d,access_type=%d)\n", uid, gid, access_type);
  57.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - object attributes --- "
  58.                  "(uid=%d,gid=%d,mode=%d)\n", attr->owner, attr->group,
  59.                  attr->perms);
  60.  
  61.     /* give root permission, no matter what */
  62.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG,
  63.                  " - checking if uid (%d) is root ...\n", uid);
  64.     if (uid == 0)
  65.     {
  66.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  67.         return 0;
  68.     }
  69.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  70.  
  71.     /* see if uid matches object owner */
  72.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if owner (%d) "
  73.         "matches uid (%d)...\n", attr->owner, uid);
  74.     if(attr->owner == uid)
  75.     {
  76.         /* see if object user permissions match access type */
  77.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  78.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
  79.             "(%d) allows access type (%d) for user...\n", attr->perms, access_type);
  80.         if(access_type == PINT_ACCESS_READABLE && (attr->perms &
  81.             PVFS_U_READ))
  82.         {
  83.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  84.             return(0);
  85.         }
  86.         if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
  87.             PVFS_U_WRITE))
  88.         {
  89.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  90.             return(0);
  91.         }
  92.         if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
  93.             PVFS_U_EXECUTE))
  94.         {
  95.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  96.             return(0);
  97.         }
  98.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  99.     }
  100.     else
  101.     {
  102.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  103.     }
  104.  
  105.     /* see if other bits allow access */
  106.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
  107.         "(%d) allows access type (%d) by others...\n", attr->perms, access_type);
  108.     if(access_type == PINT_ACCESS_READABLE && (attr->perms &
  109.         PVFS_O_READ))
  110.     {
  111.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  112.         return(0);
  113.     }
  114.     if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
  115.         PVFS_O_WRITE))
  116.     {
  117.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  118.         return(0);
  119.     }
  120.     if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
  121.         PVFS_O_EXECUTE))
  122.     {
  123.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  124.         return(0);
  125.     }
  126.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  127.  
  128.     /* see if gid matches object group */
  129.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if group (%d) "
  130.         "matches gid (%d)...\n", attr->group, gid);
  131.     if(attr->group == gid)
  132.     {
  133.         /* default group match */
  134.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  135.         in_group_flag = 1;
  136.     }
  137.     else
  138.     {
  139.         /* no default group match, check supplementary groups */
  140.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  141.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking for"
  142.             " supplementary group match...\n");
  143.         ret = PINT_check_group(uid, attr->group);
  144.         if(ret == 0)
  145.         {
  146.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  147.             in_group_flag = 1;
  148.         }
  149.         else
  150.         {
  151.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  152.             if(ret != -PVFS_ENOENT)
  153.             {
  154.                 /* system error; not just failed match */
  155.                 return(ret);
  156.             }
  157.         }
  158.     }
  159.  
  160.     if(in_group_flag)
  161.     {
  162.         /* see if object group permissions match access type */
  163.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
  164.             "(%d) allows access type (%d) for group...\n", attr->perms, access_type);
  165.         if(access_type == PINT_ACCESS_READABLE && (attr->perms &
  166.             PVFS_G_READ))
  167.         {
  168.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  169.             return(0);
  170.         }
  171.         if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
  172.             PVFS_G_WRITE))
  173.         {
  174.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  175.             return(0);
  176.         }
  177.         if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
  178.             PVFS_G_EXECUTE))
  179.         {
  180.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
  181.             return(0);
  182.         }
  183.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
  184.     }
  185.   
  186.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "******PINT_check_mode: denying access\n");
  187.     /* default case: access denied */
  188.     return -PVFS_EACCES;
  189. }
  190.  
  191. /* PINT_check_group()
  192.  *
  193.  * checks to see if uid is a member of gid
  194.  * 
  195.  * returns 0 on success, -PVFS_ENOENT if not a member, other PVFS error codes
  196.  * on system failure
  197.  */
  198. static int PINT_check_group(uid_t uid, gid_t gid)
  199. {
  200.     struct passwd pwd;
  201.     struct passwd* pwd_p = NULL;
  202.     struct group grp;
  203.     struct group* grp_p = NULL;
  204.     int i = 0;
  205.     int ret = -1;
  206.  
  207.     /* Explanation: 
  208.      *
  209.      * We use the _r variants of getpwuid and getgrgid in order to insure
  210.      * thread safety; particularly if this function ever gets called in a
  211.      * client side situation in which we can't prevent the application from
  212.      * making conflicting calls.
  213.      *
  214.      * These _r functions require that a buffer be supplied for the user and
  215.      * group information, however.  These buffers may be unconfortably large
  216.      * for the stack, so we malloc them on a static pointer and then mutex
  217.      * lock this function so that it can still be reentrant.
  218.      */
  219.  
  220.     gen_mutex_lock(&check_group_mutex);
  221.  
  222.     if(!check_group_pw_buffer)
  223.     {
  224.         check_group_pw_buffer = (char*)malloc(pw_buf_size);
  225.         check_group_gr_buffer = (char*)malloc(gr_buf_size);
  226.         if(!check_group_pw_buffer || !check_group_gr_buffer)
  227.         {
  228.             if(check_group_pw_buffer)
  229.             {
  230.                 free(check_group_pw_buffer);
  231.                 check_group_pw_buffer = NULL;
  232.             }
  233.             if(check_group_gr_buffer)
  234.             {
  235.                 free(check_group_gr_buffer);
  236.                 check_group_gr_buffer = NULL;
  237.             }
  238.             gen_mutex_unlock(&check_group_mutex);
  239.             return(-PVFS_ENOMEM);
  240.         }
  241.     }
  242.  
  243.     /* get user information */
  244.     ret = getpwuid_r(uid, &pwd, check_group_pw_buffer, pw_buf_size, &pwd_p);
  245.     if(ret != 0 || pwd_p == NULL)
  246.     {
  247.         gen_mutex_unlock(&check_group_mutex);
  248.         gossip_err("Get user info for (uid=%d) failed."
  249.                    "errno [%d] error_msg [%s]\n",
  250.                    uid, ret, strerror(ret));
  251.         return(-PVFS_EINVAL);
  252.     }
  253.  
  254.     /* check primary group */
  255.     if(pwd.pw_gid == gid)
  256.     {
  257.         gen_mutex_unlock(&check_group_mutex);
  258.         return 0;
  259.     }
  260.  
  261.     /* get the members of the group */
  262.     ret = getgrgid_r(gid, &grp, check_group_gr_buffer, gr_buf_size, &grp_p);
  263.     if(ret != 0 || grp_p == NULL)
  264.     {
  265.       gen_mutex_unlock(&check_group_mutex);
  266.       gossip_err("Get members for group (gid=%d) failed."
  267.                  "errno [%d] error_msg [%s]\n",
  268.                  gid, ret, strerror(ret));
  269.       return(-PVFS_EINVAL);
  270.     }
  271.  
  272.     for(i = 0; grp.gr_mem[i] != NULL; i++)
  273.     {
  274.         if(0 == strcmp(pwd.pw_name, grp.gr_mem[i]))
  275.         {
  276.             gen_mutex_unlock(&check_group_mutex);
  277.             return 0;
  278.         } 
  279.     }
  280.  
  281.     gen_mutex_unlock(&check_group_mutex);
  282.     return(-PVFS_ENOENT);
  283. }
  284.  
  285. /* Checks if a given user is part of any groups that matches the file gid */
  286. static int in_group_p(PVFS_uid uid, PVFS_gid gid, PVFS_gid attr_group)
  287. {
  288.     if (attr_group == gid)
  289.         return 1;
  290.     if (PINT_check_group(uid, attr_group) == 0)
  291.         return 1;
  292.     return 0;
  293. }
  294.  
  295. /*
  296.  * Return 0 if requesting clients is granted want access to the object
  297.  * by the acl. Returns -PVFS_E... otherwise.
  298.  */
  299. int PINT_check_acls(void *acl_buf, size_t acl_size, 
  300.     PVFS_object_attr *attr,
  301.     PVFS_uid uid, PVFS_gid gid, int want)
  302. {
  303.     pvfs2_acl_entry pe, *pa;
  304.     int i = 0, found = 0, count = 0;
  305.     assert(attr->mask & PVFS_ATTR_COMMON_UID &&
  306.            attr->mask & PVFS_ATTR_COMMON_GID &&
  307.            attr->mask & PVFS_ATTR_COMMON_PERM);
  308.  
  309.     if (acl_size == 0)
  310.     {
  311.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "no acl's present.. denying access\n");
  312.         return -PVFS_EACCES;
  313.     }
  314.  
  315.     /* keyval for ACLs includes a \0. so subtract the thingie */
  316.     acl_size--;
  317.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "PINT_check_acls: read keyval size "
  318.     " %d (%d acl entries)\n",
  319.         (int) acl_size, 
  320.         (int) (acl_size / sizeof(pvfs2_acl_entry)));
  321.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "uid = %d, gid = %d, want = %d\n",
  322.         uid, gid, want);
  323.  
  324.     assert(acl_buf);
  325.     /* if the acl format doesn't look valid, then return an error rather than
  326.      * asserting; we don't want the server to crash due to an invalid keyval
  327.      */
  328.     if((acl_size % sizeof(pvfs2_acl_entry)) != 0)
  329.     {
  330.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "invalid acls on object\n");
  331.         return(-PVFS_EACCES);
  332.     }
  333.     count = acl_size / sizeof(pvfs2_acl_entry);
  334.  
  335.     for (i = 0; i < count; i++)
  336.     {
  337.         pa = (pvfs2_acl_entry *) acl_buf + i;
  338.         /* 
  339.            NOTE: Remember that keyval is encoded as lebf, so convert it 
  340.            to host representation 
  341.         */
  342.         pe.p_tag  = bmitoh32(pa->p_tag);
  343.         pe.p_perm = bmitoh32(pa->p_perm);
  344.         pe.p_id   = bmitoh32(pa->p_id);
  345.         pa = &pe;
  346.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "Decoded ACL entry %d "
  347.             "(p_tag %d, p_perm %d, p_id %d)\n",
  348.             i, pa->p_tag, pa->p_perm, pa->p_id);
  349.         switch(pa->p_tag) 
  350.         {
  351.             case PVFS2_ACL_USER_OBJ:
  352.                 /* (May have been checked already) */
  353.                 if (attr->owner == uid)
  354.                     goto check_perm;
  355.                 break;
  356.             case PVFS2_ACL_USER:
  357.                 if (pa->p_id == uid)
  358.                     goto mask;
  359.                 break;
  360.             case PVFS2_ACL_GROUP_OBJ:
  361.                 if (in_group_p(uid, gid, attr->group)) 
  362.                 {
  363.                     found = 1;
  364.                     if ((pa->p_perm & want) == want)
  365.                         goto mask;
  366.                 }
  367.                 break;
  368.             case PVFS2_ACL_GROUP:
  369.                 if (in_group_p(uid, gid, pa->p_id)) {
  370.                     found = 1;
  371.                     if ((pa->p_perm & want) == want)
  372.                         goto mask;
  373.                 }
  374.                 break;
  375.             case PVFS2_ACL_MASK:
  376.                 break;
  377.             case PVFS2_ACL_OTHER:
  378.                 if (found)
  379.                 {
  380.                     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(1) PINT_check_acls:"
  381.                         "returning access denied\n");
  382.                     return -PVFS_EACCES;
  383.                 }
  384.                 else
  385.                     goto check_perm;
  386.             default:
  387.                 gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(2) PINT_check_acls: "
  388.                         "returning EIO\n");
  389.                 return -PVFS_EIO;
  390.         }
  391.     }
  392.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(3) PINT_check_acls: returning EIO\n");
  393.     return -PVFS_EIO;
  394. mask:
  395.     /* search the remaining entries */
  396.     i = i + 1;
  397.     for (; i < count; i++)
  398.     {
  399.         pvfs2_acl_entry me, *mask_obj = (pvfs2_acl_entry *) acl_buf + i;
  400.         
  401.         /* 
  402.           NOTE: Again, since pvfs2_acl_entry is in lebf, we need to
  403.           convert it to host endian format
  404.          */
  405.         me.p_tag  = bmitoh32(mask_obj->p_tag);
  406.         me.p_perm = bmitoh32(mask_obj->p_perm);
  407.         me.p_id   = bmitoh32(mask_obj->p_id);
  408.         mask_obj = &me;
  409.         gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "Decoded (mask) ACL entry %d "
  410.             "(p_tag %d, p_perm %d, p_id %d)\n",
  411.             i, mask_obj->p_tag, mask_obj->p_perm, mask_obj->p_id);
  412.         if (mask_obj->p_tag == PVFS2_ACL_MASK) 
  413.         {
  414.             if ((pa->p_perm & mask_obj->p_perm & want) == want)
  415.                 return 0;
  416.             gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(4) PINT_check_acls:"
  417.                 "returning access denied (mask)\n");
  418.             return -PVFS_EACCES;
  419.         }
  420.     }
  421.  
  422. check_perm:
  423.     if ((pa->p_perm & want) == want)
  424.         return 0;
  425.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(5) PINT_check_acls: returning"
  426.             "access denied\n");
  427.     return -PVFS_EACCES;
  428. }
  429.  
  430.