Пример #1
0
/* prelude_perm_check()
 *
 * this really just marks the spot where we would want to do
 * permission checking, it will be replaced by a couple of states that
 * actually perform this task later
 */
static PINT_sm_action prelude_perm_check(
        struct PINT_smcb *smcb, job_status_s *js_p)
{
    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
    PVFS_object_attr *obj_attr = NULL;
    PVFS_ds_attributes *ds_attr = NULL;
    PVFS_uid translated_uid = s_op->req->credentials.uid;
    PVFS_gid translated_gid = s_op->req->credentials.gid;
    PVFS_fs_id  fsid = PVFS_FS_ID_NULL;
    int squashed_flag = 0;
    int skip_acl_flag = 0;

    /* moved gossip server debug output to end of state, so we can report
     * resulting status value.
     */

    /*
      first we translate the dspace attributes into a more convenient
      server use-able format.  i.e. a PVFS_object_attr
    */
    ds_attr = &s_op->ds_attr;
    obj_attr = &s_op->attr;
    PVFS_ds_attr_to_object_attr(ds_attr, obj_attr);
    s_op->attr.mask = PVFS_ATTR_COMMON_ALL;
    /* Set the target object attribute pointer.. used later by the acl check */
    s_op->target_object_attr = obj_attr;

    if (s_op->target_fs_id != PVFS_FS_ID_NULL)
    {
        /*
         * if we are exporting a volume readonly, disallow any operation that modifies
         * the state of the file-system.
         */
        if (permit_operation(
                s_op->target_fs_id, s_op->access_type, s_op->addr) < 0)
        {
            js_p->error_code = -PVFS_EROFS;
            return SM_ACTION_COMPLETE;
        }
        else 
        {
            /* Translate the uid and gid's in case we need to do some squashing based on the export and the client address */
            if (translate_ids(fsid, s_op->req->credentials.uid, s_op->req->credentials.gid,
                &translated_uid, &translated_gid, s_op->addr) == 1)
            {
                squashed_flag = 1;
                s_op->req->credentials.uid = translated_uid;
                s_op->req->credentials.gid = translated_gid;
                /* in the case of a setattr, translate the ids as well right here */
                if (s_op->req->op == PVFS_SERV_SETATTR)
                {
                    s_op->req->u.setattr.attr.owner = translated_uid;
                    s_op->req->u.setattr.attr.group = translated_gid;
                }
                else if (s_op->req->op == PVFS_SERV_MKDIR)
                {
                    s_op->req->u.mkdir.attr.owner = translated_uid;
                    s_op->req->u.mkdir.attr.group = translated_gid;
                }
            }
       }
    }

    /* anything else we treat as a real error */
    if (js_p->error_code)
    {
        js_p->error_code = -PVFS_ERROR_CODE(-js_p->error_code);
        return SM_ACTION_COMPLETE;
    }

    gossip_debug(
        GOSSIP_PERMISSIONS_DEBUG, "PVFS operation \"%s\" got "
        "attr mask %d\n\t(attr_uid_valid? %s, attr_owner = "
        "%d, credentials_uid = %d)\n\t(attr_gid_valid? %s, attr_group = "
        "%d, credentials.gid = %d)\n",
        PINT_map_server_op_to_string(s_op->req->op), s_op->attr.mask,
        ((s_op->attr.mask & PVFS_ATTR_COMMON_UID) ? "yes" : "no"),
        s_op->attr.owner, translated_uid,
        ((s_op->attr.mask & PVFS_ATTR_COMMON_GID) ? "yes" : "no"),
        s_op->attr.group, translated_gid);
    
    switch(PINT_server_req_get_perms(s_op->req))
    {
        case PINT_SERVER_CHECK_WRITE:
            js_p->error_code = PINT_check_mode(
                &(s_op->attr), translated_uid,
                translated_gid, PINT_ACCESS_WRITABLE);
            break;
        case PINT_SERVER_CHECK_READ:
            js_p->error_code = PINT_check_mode(
                &(s_op->attr), translated_uid,
                translated_gid, PINT_ACCESS_READABLE);
            break;
        case PINT_SERVER_CHECK_CRDIRENT:
            /* must also check executable after writable */
            js_p->error_code = PINT_check_mode(
                &(s_op->attr), translated_uid,
                translated_gid, PINT_ACCESS_WRITABLE);
            if(js_p->error_code == 0)
            {
                js_p->error_code = PINT_check_mode(
                    &(s_op->attr), translated_uid,
                    translated_gid, PINT_ACCESS_EXECUTABLE);
            }
            break;
        case PINT_SERVER_CHECK_ATTR:
            /* let datafiles pass through the attr check */
            if (s_op->attr.objtype == PVFS_TYPE_DATAFILE)
            {
                js_p->error_code = 0;
            }
            /* for now we'll assume extended attribs are treated
             * the same as regular attribs as far as permissions
             */
	    else if (s_op->req->op == PVFS_SERV_GETATTR ||
                    s_op->req->op == PVFS_SERV_GETEATTR ||
                    s_op->req->op == PVFS_SERV_LISTEATTR)
	    {
		/* getting or listing attributes is always ok -- permission
		 * is checked on the parent directory at read time
		 */
		js_p->error_code = 0;
	    }
            else /* setattr, seteattr, seteattr_list */
            {
                if(s_op->attr.perms == 0 && s_op->attr.objtype ==
                    PVFS_TYPE_SYMLINK)
                {
                    /* if the object is of type symlink but has empty perms,
                     * then it must be a newly created symlink object that
                     * does not have its true attributes set yet.  Let this
                     * operation through.
                     */
                    js_p->error_code = 0;
                }
                else if(s_op->attr.owner == translated_uid || translated_uid
                    == 0)
                {
                    /* owner of file and root can always set attributes (see
                     * iozone, which does a setattr as part of truncating a
                     * file with permission mask set to 0
                     */
                    js_p->error_code = 0;
                }
                else
                {
                    /* normal setattr requires write permissions on existing
                     * objects
                     */
                    js_p->error_code = PINT_check_mode(
                        &(s_op->attr), translated_uid,
                        translated_gid, PINT_ACCESS_WRITABLE);
                }
            }
            break;
        case PINT_SERVER_CHECK_NONE:
            if(squashed_flag &&
               PINT_server_req_get_access_type(s_op->req) == PINT_SERVER_REQ_MODIFY &&
               ((s_op->req->op == PVFS_SERV_IO) ||
                (s_op->req->op == PVFS_SERV_SMALL_IO) ||
                (s_op->req->op == PVFS_SERV_TRUNCATE)))
            {
                /* special case:
                 * If we have been squashed, deny write permission to the
                 * file system.  At the datafile level we don't have enough
                 * attribute information to figure out if the nobody/guest
                 * user has permission to write or not, so we disallow all
                 * writes to be safe.  Not perfect semantics, but better
                 * than being too permissive.
                 */
                skip_acl_flag = 1;
                js_p->error_code = -PVFS_EACCES;
            }
            else
            {
                js_p->error_code = 0;
            }
            break;
        case PINT_SERVER_CHECK_INVALID:
            js_p->error_code = -PVFS_EINVAL;
            break;
    }

    gossip_debug(
        GOSSIP_PERMISSIONS_DEBUG, "Final permission check for \"%s\" set "
        "error code to %d\n", PINT_map_server_op_to_string(s_op->req->op),
        js_p->error_code);

    gossip_debug(GOSSIP_SERVER_DEBUG, 
        "(%p) %s (prelude sm) state: perm_check (status = %d)\n",
	s_op,
        PINT_map_server_op_to_string(s_op->req->op),
	js_p->error_code);
    /* If regular checks fail, we need to run acl checks */
    if (js_p->error_code == -PVFS_EACCES && !skip_acl_flag)
        js_p->error_code = PRELUDE_RUN_ACL_CHECKS;
    return SM_ACTION_COMPLETE;
}
Пример #2
0
/**
 * PVFSIOStore::Access: permission check
 *
 * @param path the path we are checking
 * @param mode the mode to check
 * @return PLFS_SUCCESS or PLFS_E* on error
 */
plfs_error_t PVFSIOStore::Access(const char* path, int mode)
{
    char *cpath;
    PVFS_object_ref ref;
    PVFS_credentials creds;
    int nev, pev;
    PVFS_sysresp_getattr rep;
    PVFS_uid auid;
    PVFS_gid agid;
    PVFS_permissions aperms;

    cpath = pvfsios_dedup_slash(path);
    if (cpath) {
        nev = pvfsios_get_object(this->fsid, cpath, &ref, &creds,
                                 PVFS2_LOOKUP_LINK_FOLLOW);
        free(cpath);
    } else {
        nev = -ENOMEM;
    }
    if (nev < 0) {
        return errno_to_plfs_error(-nev);
    }
    
    /* root or exist check */
    if (creds.uid == 0 || mode == F_OK) {
        return PLFS_SUCCESS;
    }
    
    pev = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL_NOHINT, &creds, &rep);
    if (pev < 0) {
        return errno_to_plfs_error(get_err(pev));
    }

#if 0
    /*
     * XXXCDC: we'd really like to call PINT_check_mode, but libpvfs2
     * includes don't provide a prototype for it even though it is
     * present in the lib.  does that mean it is a private interface?
     */
    pev = PINT_check_mode(&rep.attr, creds.uid, credis.gid, 0);
    PVFS_util_release_sys_attr(&rep.attr);  /* frees memory chained off ats */
    return(get_err(pev));
#endif
    
    /*
     * XXX: pvfs2fuse doesn't call PVFS_util_release_sys_attr on
     * repl.attr for access.  this seems like a memory leak mistake to
     * me.
     */
    auid = rep.attr.owner;
    agid = rep.attr.group;
    aperms = rep.attr.perms;
    PVFS_util_release_sys_attr(&rep.attr);  /* frees memory chained off ats */

    if (auid == creds.uid) {
        if ((mode & R_OK) && (aperms & PVFS_U_READ))
            return PLFS_SUCCESS;
        if ((mode & W_OK) && (aperms & PVFS_U_WRITE))
            return PLFS_SUCCESS;
        if ((mode & X_OK) && (aperms & PVFS_U_EXECUTE))
            return PLFS_SUCCESS;
    }
    /* XXXCDC: doesn't check group list, e.g. getgroups() */
    if (agid == creds.gid) {
        if ((mode & R_OK) && (aperms & PVFS_G_READ))
            return PLFS_SUCCESS;
        if ((mode & W_OK) && (aperms & PVFS_G_WRITE))
            return PLFS_SUCCESS;
        if ((mode & X_OK) && (aperms & PVFS_G_EXECUTE))
            return PLFS_SUCCESS;
    }
    if ((mode & R_OK) && (aperms & PVFS_O_READ))
        return PLFS_SUCCESS;
    if ((mode & W_OK) && (aperms & PVFS_O_WRITE))
        return PLFS_SUCCESS;
    if ((mode & X_OK) && (aperms & PVFS_O_EXECUTE))
        return PLFS_SUCCESS;

    return PLFS_EACCES;
}