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 / prelude.sm < prev    next >
Text File  |  2010-04-30  |  23KB  |  707 lines

  1. /* 
  2.  * (C) 2001 Clemson University and The University of Chicago 
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.  
  7. #include <string.h>
  8. #include <assert.h>
  9.  
  10. #include "server-config.h"
  11. #include "pvfs2-server.h"
  12. #include "pvfs2-attr.h"
  13. #include "src/server/request-scheduler/request-scheduler.h"
  14. #include "trove.h"
  15. #include "pint-util.h"
  16. #include "pvfs2-internal.h"
  17. #include "pint-perf-counter.h"
  18.  
  19. /* prelude state machine:
  20.  * This is a nested state machine that performs initial setup 
  21.  * steps that are common to many server operations.
  22.  * - post the request to the request scheduler
  23.  * - check permissions
  24.  */
  25. enum {
  26.     PRELUDE_RUN_ACL_CHECKS = 1,
  27. };
  28.  
  29. %%
  30.  
  31. nested machine pvfs2_prelude_work_sm
  32. {
  33.     state req_sched
  34.     {
  35.         run prelude_req_sched;
  36.         success => getattr_if_needed;
  37.         default => return;
  38.     }
  39.  
  40.     state getattr_if_needed
  41.     {
  42.         run prelude_getattr_if_needed;
  43.         default => perm_check;
  44.     }
  45.  
  46.     state perm_check
  47.     {
  48.         run prelude_perm_check;
  49.         PRELUDE_RUN_ACL_CHECKS => check_acls_if_needed;
  50.         default => return;
  51.     }
  52.  
  53.     state check_acls_if_needed
  54.     {
  55.         run prelude_check_acls_if_needed;
  56.         default => check_acls;
  57.     }
  58.  
  59.     state check_acls
  60.     {
  61.         run prelude_check_acls;
  62.         default => return;
  63.     }
  64. }
  65.  
  66. nested machine pvfs2_prelude_sm
  67. {
  68.     state setup
  69.     {
  70.         run prelude_setup;
  71.         default => prelude_work;
  72.     }
  73.  
  74.     state prelude_work
  75.     {
  76.         jump pvfs2_prelude_work_sm;
  77.         default => return;
  78.     }
  79. }
  80.  
  81. %%
  82.  
  83. static PINT_sm_action prelude_setup(
  84.         struct PINT_smcb *smcb, job_status_s *js_p)
  85. {
  86.  
  87.     gossip_debug(GOSSIP_MIRROR_DEBUG,"Executing pvfs2_prelude_sm:prelude_setup...\n");
  88.     gossip_debug(GOSSIP_MIRROR_DEBUG,"\tbase frame:%d\tframe count:%d\n"
  89.                                     ,smcb->base_frame,smcb->frame_count);
  90.     int ret;
  91.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  92.  
  93.     ret = PINT_server_req_get_object_ref(
  94.         s_op->req, &s_op->target_fs_id, &s_op->target_handle);
  95.     s_op->access_type = PINT_server_req_get_access_type(s_op->req);
  96.     s_op->sched_policy = PINT_server_req_get_sched_policy(s_op->req);
  97.  
  98.     return SM_ACTION_COMPLETE;
  99. }
  100.  
  101. /* prelude_req_sched()
  102.  *
  103.  * posts a request scheduler job
  104.  */
  105. static PINT_sm_action prelude_req_sched(
  106.         struct PINT_smcb *smcb, job_status_s *js_p)
  107. {
  108.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  109.     int ret = -PVFS_EINVAL;
  110.  
  111.     if (s_op->prelude_mask & PRELUDE_SCHEDULER_DONE) {
  112.         gossip_debug(GOSSIP_SERVER_DEBUG,
  113.                  "(%p) %s (prelude sm) state: req_sched already done... skipping.\n", s_op,
  114.                  PINT_map_server_op_to_string(s_op->req->op));
  115.         js_p->error_code = 0;
  116.         return SM_ACTION_COMPLETE;
  117.     }   
  118.  
  119.     gossip_debug(GOSSIP_MIRROR_DEBUG,"Executing pvfs2_prelude_work_sm:prelude_req_sched\n");
  120.     gossip_debug(GOSSIP_MIRROR_DEBUG,"\tbase_frame:%d\tframe_count:%d\n"
  121.                                     ,smcb->base_frame,smcb->frame_count);
  122.     gossip_debug(GOSSIP_SERVER_DEBUG,
  123.         "(%p) %s (prelude sm) state: req_sched\n", s_op,
  124.         PINT_map_server_op_to_string(s_op->req->op));
  125.  
  126.     PINT_ACCESS_DEBUG(s_op, GOSSIP_ACCESS_DETAIL_DEBUG, "request\n");
  127.  
  128.     ret = job_req_sched_post(s_op->op, s_op->target_fs_id, s_op->target_handle,
  129.                              s_op->access_type, s_op->sched_policy,
  130.                              smcb, 0, js_p,
  131.                              &(s_op->scheduled_id), server_job_context);
  132.  
  133.     PINT_perf_count(PINT_server_pc, PINT_PERF_REQSCHED, 1, PINT_PERF_ADD);
  134.     return ret;
  135. }
  136.  
  137. /* prelude_getattr_if_needed()
  138.  *
  139.  * reads basic attributes of target object, if there is a particular
  140.  * target object for the operation
  141.  */
  142. static PINT_sm_action prelude_getattr_if_needed(
  143.         struct PINT_smcb *smcb, job_status_s *js_p)
  144. {
  145.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  146.     int ret = -PVFS_EINVAL;
  147.     job_id_t tmp_id;
  148.  
  149.     if (s_op->prelude_mask & PRELUDE_GETATTR_DONE) {
  150.         gossip_debug(GOSSIP_SERVER_DEBUG,
  151.                  "(%p) %s (prelude sm) state: getattr already done... skipping.\n", s_op,
  152.                  PINT_map_server_op_to_string(s_op->req->op));
  153.         js_p->error_code = 0;
  154.         return SM_ACTION_COMPLETE;
  155.     }
  156.  
  157.     PINT_ACCESS_DEBUG(s_op, GOSSIP_ACCESS_DETAIL_DEBUG, "start\n");
  158.  
  159.     gossip_debug(GOSSIP_SERVER_DEBUG,
  160.                  "(%p) %s (prelude sm) state: getattr_if_needed\n", s_op,
  161.                  PINT_map_server_op_to_string(s_op->req->op));
  162.  
  163.     /* if the handle is 0, that indicates that the request does not
  164.      * operate on a specific handle, so there is nothing we can do
  165.      * here
  166.      */
  167.     if (s_op->target_handle == PVFS_HANDLE_NULL)
  168.     {
  169.  
  170.         js_p->error_code = 0;
  171.         return SM_ACTION_COMPLETE;
  172.     }
  173.  
  174.     /* all other operations fall to this point and read basic
  175.      * attribute information
  176.      */
  177.     memset(&(s_op->ds_attr), 0, sizeof(PVFS_ds_attributes));
  178.  
  179.     gossip_debug(GOSSIP_SERVER_DEBUG, "About to retrieve attributes "
  180.                  "for handle %llu\n", llu(s_op->target_handle));
  181.  
  182.     ret = job_trove_dspace_getattr(
  183.         s_op->target_fs_id, s_op->target_handle, smcb, &(s_op->ds_attr),
  184.         0, js_p, &tmp_id, server_job_context, s_op->req->hints);
  185.  
  186.     return ret;
  187. }
  188.  
  189. static void get_anon_ids(struct filesystem_configuration_s *fsconfig,
  190.     PVFS_uid *uid, PVFS_gid *gid)
  191. {
  192.     *uid = fsconfig->exp_anon_uid;
  193.     *gid = fsconfig->exp_anon_gid;
  194.     return;
  195. }
  196.  
  197. static int iterate_all_squash_wildcards(struct filesystem_configuration_s *fsconfig,
  198.     PVFS_BMI_addr_t client_addr)
  199. {
  200.     int i;
  201.  
  202.     for (i = 0; i < fsconfig->all_squash_count; i++)
  203.     {
  204.         gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %lld, %s\n",
  205.             lld(client_addr), fsconfig->all_squash_hosts[i]);
  206.         if (BMI_query_addr_range(client_addr, fsconfig->all_squash_hosts[i],
  207.                 fsconfig->all_squash_netmasks[i]) == 1)
  208.         {
  209.             return 1;
  210.         }
  211.     }
  212.     return 0;
  213. }
  214.  
  215. static int iterate_root_squash_wildcards(struct filesystem_configuration_s *fsconfig,
  216.     PVFS_BMI_addr_t client_addr)
  217. {
  218.     int i;
  219.  
  220.     /* check exceptions first */
  221.     for (i = 0; i < fsconfig->root_squash_exceptions_count; i++)
  222.     {
  223.         gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %lld, %s, netmask: %i\n",
  224.             lld(client_addr), fsconfig->root_squash_exceptions_hosts[i],
  225.             fsconfig->root_squash_exceptions_netmasks[i]);
  226.         if (BMI_query_addr_range(client_addr, fsconfig->root_squash_exceptions_hosts[i], 
  227.                 fsconfig->root_squash_exceptions_netmasks[i]) == 1)
  228.         {
  229.             /* in the exception list, do not squash */
  230.             return 0;
  231.         }
  232.     }
  233.  
  234.     for (i = 0; i < fsconfig->root_squash_count; i++)
  235.     {
  236.         gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %lld, %s, netmask: %i\n",
  237.             lld(client_addr), fsconfig->root_squash_hosts[i],
  238.             fsconfig->root_squash_netmasks[i]);
  239.         if (BMI_query_addr_range(client_addr, fsconfig->root_squash_hosts[i], 
  240.                 fsconfig->root_squash_netmasks[i]) == 1)
  241.         {
  242.             return 1;
  243.         }
  244.     }
  245.     return 0;
  246. }
  247.  
  248. /* Translate_ids will return 1 if it did some uid/gid squashing, 0 otherwise */
  249. static int translate_ids(PVFS_fs_id fsid, PVFS_uid uid, PVFS_gid gid, 
  250.     PVFS_uid *translated_uid, PVFS_gid *translated_gid, PVFS_BMI_addr_t client_addr)
  251. {
  252.     int exp_flags = 0;
  253.     struct server_configuration_s *serv_config = NULL;
  254.     struct filesystem_configuration_s * fsconfig = NULL;
  255.  
  256.     serv_config = PINT_get_server_config();
  257.     fsconfig = PINT_config_find_fs_id(serv_config, fsid);
  258.  
  259.     if (fsconfig == NULL)
  260.     {
  261.         return 0;
  262.     }
  263.     exp_flags = fsconfig->exp_flags;
  264.     /* If all squash was set */
  265.     if (exp_flags & TROVE_EXP_ALL_SQUASH)
  266.     {
  267.         if (iterate_all_squash_wildcards(fsconfig, client_addr) == 1)
  268.         {
  269.             get_anon_ids(fsconfig, translated_uid, translated_gid);
  270.             gossip_debug(GOSSIP_SERVER_DEBUG,
  271.                 "Translated ids from <%u:%u> to <%u:%u>\n",
  272.                 uid, gid, *translated_uid, *translated_gid);
  273.             return 1;
  274.         }
  275.     }
  276.     /* if only root squash was set translate uids for root alone*/
  277.     if (exp_flags & TROVE_EXP_ROOT_SQUASH)
  278.     {
  279.         if (uid == 0 || gid == 0)
  280.         {
  281.             if (iterate_root_squash_wildcards(fsconfig, client_addr) == 1)
  282.             {
  283.                 get_anon_ids(fsconfig, translated_uid, translated_gid);
  284.                 gossip_debug(GOSSIP_SERVER_DEBUG,
  285.                     "Translated ids from <%u:%u> to <%u:%u>\n",
  286.                     uid, gid, *translated_uid, *translated_gid);
  287.                 return 1;
  288.             }
  289.         }
  290.     }
  291.     /* no such translation required! */
  292.     *translated_uid = uid;
  293.     *translated_gid = gid;
  294.     return 0;
  295. }
  296.  
  297. static int iterate_ro_wildcards(struct filesystem_configuration_s *fsconfig, PVFS_BMI_addr_t client_addr)
  298. {
  299.     int i;
  300.  
  301.     for (i = 0; i < fsconfig->ro_count; i++)
  302.     {
  303.         gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %lld, %s\n",
  304.             lld(client_addr), fsconfig->ro_hosts[i]);
  305.         /* Does the client address match the wildcard specification and/or */
  306.         /* the netmask specification?                                      */
  307.         if (BMI_query_addr_range(client_addr, fsconfig->ro_hosts[i],
  308.                 fsconfig->ro_netmasks[i]) == 1)
  309.         {
  310.             return 1;
  311.         }
  312.     }
  313.     return 0;
  314. }
  315.  
  316. /*
  317.  * Return zero if this operation should be allowed.
  318.  */
  319. static int permit_operation(PVFS_fs_id fsid,
  320.                             enum PINT_server_req_access_type access_type,
  321.                             PVFS_BMI_addr_t client_addr)
  322.     int exp_flags = 0; 
  323.     struct server_configuration_s *serv_config = NULL;
  324.     struct filesystem_configuration_s * fsconfig = NULL;
  325.  
  326.     if (access_type == PINT_SERVER_REQ_READONLY)
  327.     {
  328.         return 0;  /* anything that doesn't modify state is okay */
  329.     }
  330.     serv_config = PINT_get_server_config();
  331.     fsconfig = PINT_config_find_fs_id(serv_config, fsid);
  332.  
  333.     if (fsconfig == NULL)
  334.     {
  335.         return 0;
  336.     }
  337.     exp_flags = fsconfig->exp_flags;
  338.  
  339.     /* cheap test to see if ReadOnly was even specified in the exportoptions */
  340.     if (!(exp_flags & TROVE_EXP_READ_ONLY))
  341.     {
  342.         return 0;
  343.     }
  344.     /* Drat. Iterate thru the list of wildcards specified in server_configuration and see
  345.      * the client address matches. if yes, then we deny permission
  346.      */
  347.     if (iterate_ro_wildcards(fsconfig, client_addr) == 1)
  348.     {
  349.         gossip_debug(GOSSIP_SERVER_DEBUG, 
  350.             "Disallowing read-write operation on a read-only exported file-system\n");
  351.         return -EROFS;
  352.     }
  353.     return 0;
  354. }
  355.  
  356. /* prelude_perm_check()
  357.  *
  358.  * this really just marks the spot where we would want to do
  359.  * permission checking, it will be replaced by a couple of states that
  360.  * actually perform this task later
  361.  */
  362. static PINT_sm_action prelude_perm_check(
  363.         struct PINT_smcb *smcb, job_status_s *js_p)
  364. {
  365.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  366.     PVFS_object_attr *obj_attr = NULL;
  367.     PVFS_ds_attributes *ds_attr = NULL;
  368.     PVFS_uid translated_uid = s_op->req->credentials.uid;
  369.     PVFS_gid translated_gid = s_op->req->credentials.gid;
  370.     PVFS_fs_id  fsid = PVFS_FS_ID_NULL;
  371.     int squashed_flag = 0;
  372.     int skip_acl_flag = 0;
  373.  
  374.     /* moved gossip server debug output to end of state, so we can report
  375.      * resulting status value.
  376.      */
  377.  
  378.     /*
  379.       first we translate the dspace attributes into a more convenient
  380.       server use-able format.  i.e. a PVFS_object_attr
  381.     */
  382.     ds_attr = &s_op->ds_attr;
  383.     obj_attr = &s_op->attr;
  384.     PVFS_ds_attr_to_object_attr(ds_attr, obj_attr);
  385.     s_op->attr.mask = PVFS_ATTR_COMMON_ALL;
  386.     /* Set the target object attribute pointer.. used later by the acl check */
  387.     s_op->target_object_attr = obj_attr;
  388.  
  389.     if (s_op->prelude_mask & PRELUDE_PERM_CHECK_DONE) {
  390.         gossip_debug(GOSSIP_SERVER_DEBUG,
  391.                  "(%p) %s (prelude sm) state: perm check already done... skipping.\n", s_op,
  392.                  PINT_map_server_op_to_string(s_op->req->op));
  393.         return SM_ACTION_COMPLETE;
  394.     }
  395.  
  396.     if (s_op->target_fs_id != PVFS_FS_ID_NULL)
  397.     {
  398.         /*
  399.          * if we are exporting a volume readonly, disallow any operation that modifies
  400.          * the state of the file-system.
  401.          */
  402.         if (permit_operation(
  403.                 s_op->target_fs_id, s_op->access_type, s_op->addr) < 0)
  404.         {
  405.             js_p->error_code = -PVFS_EROFS;
  406.             return SM_ACTION_COMPLETE;
  407.         }
  408.         else 
  409.         {
  410.             /* Translate the uid and gid's in case we need to do some squashing based on the export and the client address */
  411.             if (translate_ids(fsid, s_op->req->credentials.uid, s_op->req->credentials.gid,
  412.                 &translated_uid, &translated_gid, s_op->addr) == 1)
  413.             {
  414.                 squashed_flag = 1;
  415.                 s_op->req->credentials.uid = translated_uid;
  416.                 s_op->req->credentials.gid = translated_gid;
  417.                 /* in the case of a setattr, translate the ids as well right here */
  418.                 if (s_op->req->op == PVFS_SERV_SETATTR)
  419.                 {
  420.                     s_op->req->u.setattr.attr.owner = translated_uid;
  421.                     s_op->req->u.setattr.attr.group = translated_gid;
  422.                 }
  423.                 else if (s_op->req->op == PVFS_SERV_MKDIR)
  424.                 {
  425.                     s_op->req->u.mkdir.attr.owner = translated_uid;
  426.                     s_op->req->u.mkdir.attr.group = translated_gid;
  427.                 }
  428.             }
  429.        }
  430.     }
  431.  
  432.     /* anything else we treat as a real error */
  433.     if (js_p->error_code)
  434.     {
  435.         js_p->error_code = -PVFS_ERROR_CODE(-js_p->error_code);
  436.         return SM_ACTION_COMPLETE;
  437.     }
  438.  
  439.     gossip_debug(
  440.         GOSSIP_PERMISSIONS_DEBUG, "PVFS operation \"%s\" got "
  441.         "attr mask %d\n\t(attr_uid_valid? %s, attr_owner = "
  442.         "%d, credentials_uid = %d)\n\t(attr_gid_valid? %s, attr_group = "
  443.         "%d, credentials.gid = %d)\n",
  444.         PINT_map_server_op_to_string(s_op->req->op), s_op->attr.mask,
  445.         ((s_op->attr.mask & PVFS_ATTR_COMMON_UID) ? "yes" : "no"),
  446.         s_op->attr.owner, translated_uid,
  447.         ((s_op->attr.mask & PVFS_ATTR_COMMON_GID) ? "yes" : "no"),
  448.         s_op->attr.group, translated_gid);
  449.     
  450.     switch(PINT_server_req_get_perms(s_op->req))
  451.     {
  452.         case PINT_SERVER_CHECK_WRITE:
  453.             js_p->error_code = PINT_check_mode(
  454.                 &(s_op->attr), translated_uid,
  455.                 translated_gid, PINT_ACCESS_WRITABLE);
  456.             break;
  457.         case PINT_SERVER_CHECK_READ:
  458.             js_p->error_code = PINT_check_mode(
  459.                 &(s_op->attr), translated_uid,
  460.                 translated_gid, PINT_ACCESS_READABLE);
  461.             break;
  462.         case PINT_SERVER_CHECK_CRDIRENT:
  463.             /* must also check executable after writable */
  464.             js_p->error_code = PINT_check_mode(
  465.                 &(s_op->attr), translated_uid,
  466.                 translated_gid, PINT_ACCESS_WRITABLE);
  467.             if(js_p->error_code == 0)
  468.             {
  469.                 js_p->error_code = PINT_check_mode(
  470.                     &(s_op->attr), translated_uid,
  471.                     translated_gid, PINT_ACCESS_EXECUTABLE);
  472.             }
  473.             break;
  474.         case PINT_SERVER_CHECK_ATTR:
  475.             /* let datafiles pass through the attr check */
  476.             if (s_op->attr.objtype == PVFS_TYPE_DATAFILE)
  477.             {
  478.                 js_p->error_code = 0;
  479.             }
  480.             /* for now we'll assume extended attribs are treated
  481.              * the same as regular attribs as far as permissions
  482.              */
  483.         else if (s_op->req->op == PVFS_SERV_GETATTR ||
  484.                     s_op->req->op == PVFS_SERV_GETEATTR ||
  485.                     s_op->req->op == PVFS_SERV_LISTEATTR)
  486.         {
  487.         /* getting or listing attributes is always ok -- permission
  488.          * is checked on the parent directory at read time
  489.          */
  490.         js_p->error_code = 0;
  491.         }
  492.             else /* setattr, seteattr, seteattr_list */
  493.             {
  494.                 if(s_op->attr.perms == 0 && s_op->attr.objtype ==
  495.                     PVFS_TYPE_SYMLINK)
  496.                 {
  497.                     /* if the object is of type symlink but has empty perms,
  498.                      * then it must be a newly created symlink object that
  499.                      * does not have its true attributes set yet.  Let this
  500.                      * operation through.
  501.                      */
  502.                     js_p->error_code = 0;
  503.                 }
  504.                 else if(s_op->attr.owner == translated_uid || translated_uid
  505.                     == 0)
  506.                 {
  507.                     /* owner of file and root can always set attributes (see
  508.                      * iozone, which does a setattr as part of truncating a
  509.                      * file with permission mask set to 0
  510.                      */
  511.                     js_p->error_code = 0;
  512.                 }
  513.                 else
  514.                 {
  515.                     /* normal setattr requires write permissions on existing
  516.                      * objects
  517.                      */
  518.                     js_p->error_code = PINT_check_mode(
  519.                         &(s_op->attr), translated_uid,
  520.                         translated_gid, PINT_ACCESS_WRITABLE);
  521.                 }
  522.             }
  523.             break;
  524.         case PINT_SERVER_CHECK_NONE:
  525.             if(squashed_flag &&
  526.                PINT_server_req_get_access_type(s_op->req) == PINT_SERVER_REQ_MODIFY &&
  527.                ((s_op->req->op == PVFS_SERV_IO) ||
  528.                 (s_op->req->op == PVFS_SERV_SMALL_IO) ||
  529.                 (s_op->req->op == PVFS_SERV_TRUNCATE)))
  530.             {
  531.                 /* special case:
  532.                  * If we have been squashed, deny write permission to the
  533.                  * file system.  At the datafile level we don't have enough
  534.                  * attribute information to figure out if the nobody/guest
  535.                  * user has permission to write or not, so we disallow all
  536.                  * writes to be safe.  Not perfect semantics, but better
  537.                  * than being too permissive.
  538.                  */
  539.                 skip_acl_flag = 1;
  540.                 js_p->error_code = -PVFS_EACCES;
  541.             }
  542.             else
  543.             {
  544.                 js_p->error_code = 0;
  545.             }
  546.             break;
  547.         case PINT_SERVER_CHECK_INVALID:
  548.             js_p->error_code = -PVFS_EINVAL;
  549.             break;
  550.     }
  551.  
  552.     gossip_debug(
  553.         GOSSIP_PERMISSIONS_DEBUG, "Final permission check for \"%s\" set "
  554.         "error code to %d\n", PINT_map_server_op_to_string(s_op->req->op),
  555.         js_p->error_code);
  556.  
  557.     gossip_debug(GOSSIP_SERVER_DEBUG, 
  558.         "(%p) %s (prelude sm) state: perm_check (status = %d)\n",
  559.     s_op,
  560.         PINT_map_server_op_to_string(s_op->req->op),
  561.     js_p->error_code);
  562.     /* If regular checks fail, we need to run acl checks */
  563.     if (js_p->error_code == -PVFS_EACCES && !skip_acl_flag)
  564.         js_p->error_code = PRELUDE_RUN_ACL_CHECKS;
  565.     return SM_ACTION_COMPLETE;
  566. }
  567.  
  568.  
  569. static PINT_sm_action prelude_check_acls_if_needed(
  570.     struct PINT_smcb *smcb, job_status_s *js_p)
  571. {
  572.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  573.     int ret = -PVFS_EINVAL;
  574.     job_id_t i;
  575.  
  576.     gossip_debug(GOSSIP_SERVER_DEBUG,
  577.                  "(%p) %s (prelude sm) state: prelude_check_acls_if_needed\n", s_op,
  578.                  PINT_map_server_op_to_string(s_op->req->op));
  579.  
  580.     /* If we get here with an invalid fsid and handle, we have to
  581.      * return -PVFS_EACCESS 
  582.      */
  583.     if (s_op->target_fs_id == PVFS_FS_ID_NULL
  584.         || s_op->target_handle == PVFS_HANDLE_NULL)
  585.     {
  586.         js_p->error_code = -PVFS_EACCES;
  587.         return SM_ACTION_COMPLETE;
  588.     }
  589.     js_p->error_code = 0;
  590.  
  591.     memset(&s_op->key, 0, sizeof(PVFS_ds_keyval));
  592.     memset(&s_op->val, 0, sizeof(PVFS_ds_keyval));
  593.     s_op->key.buffer = "system.posix_acl_access";
  594.     s_op->key.buffer_sz = strlen(s_op->key.buffer) + 1;
  595.     s_op->val.buffer = (char *) malloc(PVFS_REQ_LIMIT_VAL_LEN);
  596.     if (!s_op->val.buffer)
  597.     {
  598.         js_p->error_code = -PVFS_ENOMEM;
  599.         return SM_ACTION_COMPLETE;
  600.     }
  601.     s_op->val.buffer_sz = PVFS_REQ_LIMIT_VAL_LEN;
  602.  
  603.     gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "About to retrieve acl keyvals "
  604.                  "for handle %llu\n", llu(s_op->target_handle));
  605.  
  606.     /* Read acl keys */
  607.     ret = job_trove_keyval_read(
  608.         s_op->target_fs_id,
  609.         s_op->target_handle,
  610.         &s_op->key,
  611.         &s_op->val,
  612.         0,
  613.         NULL,
  614.         smcb,
  615.         0,
  616.         js_p,
  617.         &i,
  618.         server_job_context,
  619.         s_op->req->hints);
  620.     return ret;
  621. }
  622.  
  623. static PINT_sm_action prelude_check_acls(
  624.     struct PINT_smcb *smcb, job_status_s *js_p)
  625. {
  626.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  627.     PVFS_object_attr *obj_attr = NULL;
  628.     int want = 0;
  629.  
  630.     /* The dspace attr must have been read at this point */
  631.     obj_attr = s_op->target_object_attr;
  632.     assert(obj_attr);
  633.  
  634.     /* if we didn't find the acl attributes, then just treat it as a
  635.      * permission denied case.
  636.      */
  637.     if (js_p->error_code == -TROVE_ENOENT)
  638.     {
  639.         js_p->error_code = -PVFS_EACCES;
  640.         goto cleanup;
  641.     }
  642.  
  643.     /* anything else non-zero we treat as a real error */
  644.     if (js_p->error_code)
  645.     {
  646.         goto cleanup;
  647.     }
  648.     /* make sure that we hit here only for metafiles, dirs and symlink objects */
  649.     if (obj_attr->objtype != PVFS_TYPE_METAFILE
  650.         && obj_attr->objtype != PVFS_TYPE_DIRECTORY
  651.         && obj_attr->objtype != PVFS_TYPE_SYMLINK)
  652.     {
  653.         gossip_err("prelude_check_acls hit invalid object type %d\n",
  654.             obj_attr->objtype);
  655.         js_p->error_code = -PVFS_EINVAL;
  656.         goto cleanup;
  657.     }
  658.     switch (PINT_server_req_get_perms(s_op->req))
  659.     {
  660.         case PINT_SERVER_CHECK_WRITE:
  661.         default:
  662.             want = PVFS2_ACL_WRITE;
  663.             break;
  664.         case PINT_SERVER_CHECK_READ:
  665.             want = PVFS2_ACL_READ;
  666.             break;
  667.         case PINT_SERVER_CHECK_CRDIRENT:
  668.             want = PVFS2_ACL_WRITE | PVFS2_ACL_EXECUTE;
  669.             break;
  670.         case PINT_SERVER_CHECK_NONE:
  671.             want = 0;
  672.             break;
  673.         case PINT_SERVER_CHECK_INVALID:
  674.             js_p->error_code = -PVFS_EINVAL;
  675.             goto cleanup;
  676.     }
  677.     js_p->error_code = PINT_check_acls(s_op->val.buffer,
  678.                         s_op->val.read_sz,
  679.                         obj_attr, 
  680.                         s_op->req->credentials.uid,
  681.                         s_op->req->credentials.gid,
  682.                         want);
  683. cleanup:
  684.     gossip_debug(
  685.         GOSSIP_PERMISSIONS_DEBUG, "Final permission check (after acls) \"%s\" set "
  686.         "error code to %d (want %x)\n",
  687.             PINT_map_server_op_to_string(s_op->req->op),
  688.             js_p->error_code, want);
  689.  
  690.     if (s_op->val.buffer) 
  691.         free(s_op->val.buffer);
  692.     memset(&s_op->key, 0, sizeof(PVFS_ds_keyval));
  693.     memset(&s_op->val, 0, sizeof(PVFS_ds_keyval));
  694.     return SM_ACTION_COMPLETE;
  695. }
  696.  
  697. /*
  698.  * Local variables:
  699.  *  mode: c
  700.  *  c-indent-level: 4
  701.  *  c-basic-offset: 4
  702.  * End:
  703.  *
  704.  * vim: ft=c ts=8 sts=4 sw=4 expandtab
  705.  */
  706.