Esempio n. 1
0
int ptlrpc_user_desc_do_idmap(struct ptlrpc_request *req,
                              struct ptlrpc_user_desc *pud)
{
        struct mdt_export_data    *med = mdt_req2med(req);
        struct lustre_idmap_table *idmap = med->med_idmap;
        uid_t uid, fsuid;
        gid_t gid, fsgid;

        /* Only remote client need desc_to_idmap. */
        if (!exp_connect_rmtclient(req->rq_export))
                return 0;

        uid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_uid);
        if (uid == CFS_IDMAP_NOTFOUND) {
                CDEBUG(D_SEC, "no mapping for uid %u\n", pud->pud_uid);
                return -EACCES;
        }

        if (pud->pud_uid == pud->pud_fsuid) {
                fsuid = uid;
        } else {
                fsuid = lustre_idmap_lookup_uid(NULL, idmap, 0, pud->pud_fsuid);
                if (fsuid == CFS_IDMAP_NOTFOUND) {
                        CDEBUG(D_SEC, "no mapping for fsuid %u\n",
                               pud->pud_fsuid);
                        return -EACCES;
                }
        }

        gid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_gid);
        if (gid == CFS_IDMAP_NOTFOUND) {
                CDEBUG(D_SEC, "no mapping for gid %u\n", pud->pud_gid);
                return -EACCES;
        }

        if (pud->pud_gid == pud->pud_fsgid) {
                fsgid = gid;
        } else {
                fsgid = lustre_idmap_lookup_gid(NULL, idmap, 0, pud->pud_fsgid);
                if (fsgid == CFS_IDMAP_NOTFOUND) {
                        CDEBUG(D_SEC, "no mapping for fsgid %u\n",
                               pud->pud_fsgid);
                        return -EACCES;
                }
        }

        pud->pud_uid = uid;
        pud->pud_gid = gid;
        pud->pud_fsuid = fsuid;
        pud->pud_fsgid = fsgid;

        return 0;
}
Esempio n. 2
0
/* Do not ignore root_squash for non-setattr case. */
int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op)
{
        struct ptlrpc_request     *req = mdt_info_req(info);
        struct md_ucred           *uc = mdt_ucred(info);
        struct lu_attr            *attr = &info->mti_attr.ma_attr;
        struct mdt_export_data    *med = mdt_req2med(req);
        struct lustre_idmap_table *idmap = med->med_idmap;

        if ((uc->mu_valid != UCRED_OLD) && (uc->mu_valid != UCRED_NEW))
                return -EINVAL;

        if (op != REINT_SETATTR) {
                if ((attr->la_valid & LA_UID) && (attr->la_uid != -1))
                        attr->la_uid = uc->mu_fsuid;
                /* for S_ISGID, inherit gid from his parent, such work will be
                 * done in cmm/mdd layer, here set all cases as uc->mu_fsgid. */
                if ((attr->la_valid & LA_GID) && (attr->la_gid != -1))
                        attr->la_gid = uc->mu_fsgid;
        } else if (exp_connect_rmtclient(info->mti_exp)) {
                /* NB: -1 case will be handled by mdt_fix_attr() later. */
                if ((attr->la_valid & LA_UID) && (attr->la_uid != -1)) {
                        uid_t uid = lustre_idmap_lookup_uid(uc, idmap, 0,
                                                            attr->la_uid);

                        if (uid == CFS_IDMAP_NOTFOUND) {
                                CDEBUG(D_SEC, "Deny chown to uid %u\n",
                                       attr->la_uid);
                                return -EPERM;
                        }

                        attr->la_uid = uid;
                }
                if ((attr->la_valid & LA_GID) && (attr->la_gid != -1)) {
                        gid_t gid = lustre_idmap_lookup_gid(uc, idmap, 0,
                                                            attr->la_gid);

                        if (gid == CFS_IDMAP_NOTFOUND) {
                                CDEBUG(D_SEC, "Deny chown to gid %u\n",
                                       attr->la_gid);
                                return -EPERM;
                        }

                        attr->la_gid = gid;
                }
        }

        return 0;
}
Esempio n. 3
0
static int
mdt_getxattr_one(struct mdt_thread_info *info,
		char *xattr_name, struct md_object *next,
		struct lu_buf *buf, struct mdt_export_data *med,
		struct lu_ucred *uc)
{
	__u32 remote = exp_connect_rmtclient(info->mti_exp);
	int flags = CFS_IC_NOTHING, rc;

	ENTRY;

	CDEBUG(D_INODE, "getxattr %s\n", xattr_name);

	rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
	if (rc < 0) {
		CERROR("getxattr failed: %d\n", rc);
		GOTO(out, rc);
	}

	if (info->mti_body->valid &
	    (OBD_MD_FLRMTLSETFACL | OBD_MD_FLRMTLGETFACL))
		flags = CFS_IC_ALL;
	else if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL)
		flags = CFS_IC_MAPPED;

	if (rc > 0 && flags != CFS_IC_NOTHING) {
		int rc1;

		if (unlikely(!remote))
			GOTO(out, rc = -EINVAL);

		rc1 = lustre_posix_acl_xattr_id2client(uc,
				med->med_idmap,
				(posix_acl_xattr_header *)(buf->lb_buf),
				rc, flags);
		if (unlikely(rc1 < 0))
			rc = rc1;
	}

out:
	return rc;
}
Esempio n. 4
0
int mdt_init_idmap(struct tgt_session_info *tsi)
{
	struct ptlrpc_request	*req = tgt_ses_req(tsi);
	struct mdt_export_data *med = mdt_req2med(req);
	struct obd_export *exp = req->rq_export;
	char *client = libcfs_nid2str(req->rq_peer.nid);
	int rc = 0;
	ENTRY;

	if (exp_connect_rmtclient(exp)) {
		mutex_lock(&med->med_idmap_mutex);
		if (!med->med_idmap)
			med->med_idmap = lustre_idmap_init();
		mutex_unlock(&med->med_idmap_mutex);

		if (IS_ERR(med->med_idmap)) {
			long err = PTR_ERR(med->med_idmap);

			med->med_idmap = NULL;
			CERROR("%s: client %s -> target %s "
			       "failed to init idmap [%ld]!\n",
			       tgt_name(tsi->tsi_tgt), client,
			       tgt_name(tsi->tsi_tgt), err);
			RETURN(err);
		} else if (!med->med_idmap) {
			CERROR("%s: client %s -> target %s "
			       "failed to init(2) idmap!\n",
			       tgt_name(tsi->tsi_tgt), client,
			       tgt_name(tsi->tsi_tgt));
			RETURN(-ENOMEM);
		}

		CDEBUG(D_SEC, "%s: client %s -> target %s is remote.\n",
			tgt_name(tsi->tsi_tgt), client,
			tgt_name(tsi->tsi_tgt));
		/* NB, MDS_CONNECT establish root idmap too! */
		rc = mdt_handle_idmap(tsi);
	}
	RETURN(rc);
}
Esempio n. 5
0
/*
 * Reverse mapping
 */
void mdt_body_reverse_idmap(struct mdt_thread_info *info, struct mdt_body *body)
{
        struct ptlrpc_request     *req = mdt_info_req(info);
	struct lu_ucred           *uc = mdt_ucred(info);
        struct mdt_export_data    *med = mdt_req2med(req);
        struct lustre_idmap_table *idmap = med->med_idmap;

        if (!exp_connect_rmtclient(info->mti_exp))
                return;

	if (body->mbo_valid & OBD_MD_FLUID) {
		uid_t uid;

		uid = lustre_idmap_lookup_uid(uc, idmap, 1, body->mbo_uid);

		if (uid == CFS_IDMAP_NOTFOUND) {
			uid = NOBODY_UID;
			if (body->mbo_valid & OBD_MD_FLMODE)
				body->mbo_mode = (body->mbo_mode & ~S_IRWXU) |
					     ((body->mbo_mode & S_IRWXO) << 6);
		}

		body->mbo_uid = uid;
	}

	if (body->mbo_valid & OBD_MD_FLGID) {
		gid_t gid;

		gid = lustre_idmap_lookup_gid(uc, idmap, 1, body->mbo_gid);

		if (gid == CFS_IDMAP_NOTFOUND) {
			gid = NOBODY_GID;
			if (body->mbo_valid & OBD_MD_FLMODE)
				body->mbo_mode = (body->mbo_mode & ~S_IRWXG) |
					     ((body->mbo_mode & S_IRWXO) << 3);
		}

		body->mbo_gid = gid;
        }
}
Esempio n. 6
0
int mdt_init_idmap(struct mdt_thread_info *info)
{
        struct ptlrpc_request *req = mdt_info_req(info);
        struct mdt_export_data *med = mdt_req2med(req);
        struct obd_export *exp = req->rq_export;
        char *client = libcfs_nid2str(req->rq_peer.nid);
        struct obd_device *obd = exp->exp_obd;
        int rc = 0;
        ENTRY;

        if (exp_connect_rmtclient(exp)) {
                cfs_down(&med->med_idmap_sem);
                if (!med->med_idmap)
                        med->med_idmap = lustre_idmap_init();
                cfs_up(&med->med_idmap_sem);

                if (IS_ERR(med->med_idmap)) {
                        long err = PTR_ERR(med->med_idmap);

                        med->med_idmap = NULL;
                        CERROR("client %s -> target %s "
                               "failed to init idmap [%ld]!\n",
                               client, obd->obd_name, err);
                        RETURN(err);
                } else if (!med->med_idmap) {
                        CERROR("client %s -> target %s "
                               "failed to init(2) idmap!\n",
                               client, obd->obd_name);
                        RETURN(-ENOMEM);
                }

                CDEBUG(D_SEC, "client %s -> target %s is remote.\n",
                       client, obd->obd_name);
                /* NB, MDS_CONNECT establish root idmap too! */
                rc = mdt_handle_idmap(info);
        }
        RETURN(rc);
}
Esempio n. 7
0
int mdt_reint_setxattr(struct mdt_thread_info *info,
                       struct mdt_lock_handle *unused)
{
        struct ptlrpc_request   *req = mdt_info_req(info);
        struct md_ucred         *uc  = mdt_ucred(info);
        struct mdt_lock_handle  *lh;
        const struct lu_env     *env  = info->mti_env;
        struct lu_buf           *buf  = &info->mti_buf;
        struct mdt_reint_record *rr   = &info->mti_rr;
        struct md_attr          *ma = &info->mti_attr;
        struct lu_attr          *attr = &info->mti_attr.ma_attr;
        struct mdt_object       *obj;
        struct md_object        *child;
        __u64                    valid = attr->la_valid;
        const char              *xattr_name = rr->rr_name;
        int                      xattr_len = rr->rr_eadatalen;
        __u64                    lockpart;
        int                      rc;
        posix_acl_xattr_header  *new_xattr = NULL;
        __u32                    remote = exp_connect_rmtclient(info->mti_exp);
        __u32                    perm;
        ENTRY;

        CDEBUG(D_INODE, "setxattr for "DFID"\n", PFID(rr->rr_fid1));

        if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SETXATTR))
                RETURN(err_serious(-ENOMEM));

        CDEBUG(D_INODE, "%s xattr %s\n",
               valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name);

        rc = mdt_init_ucred_reint(info);
        if (rc != 0)
                RETURN(rc);

        if (valid & OBD_MD_FLRMTRSETFACL) {
                if (unlikely(!remote))
                        GOTO(out, rc = err_serious(-EINVAL));

                perm = mdt_identity_get_perm(uc->mu_identity, remote,
                                             req->rq_peer.nid);
                if (!(perm & CFS_RMTACL_PERM))
                        GOTO(out, rc = err_serious(-EPERM));
        }

        if (strncmp(xattr_name, XATTR_USER_PREFIX,
                    sizeof(XATTR_USER_PREFIX) - 1) == 0) {
                if (!(req->rq_export->exp_connect_flags & OBD_CONNECT_XATTR))
                        GOTO(out, rc = -EOPNOTSUPP);
                if (strcmp(xattr_name, XATTR_NAME_LOV) == 0)
                        GOTO(out, rc = -EACCES);
                if (strcmp(xattr_name, XATTR_NAME_LMA) == 0)
                        GOTO(out, rc = 0);
                if (strcmp(xattr_name, XATTR_NAME_LINK) == 0)
                        GOTO(out, rc = 0);
        } else if ((valid & OBD_MD_FLXATTR) &&
                   (strncmp(xattr_name, XATTR_NAME_ACL_ACCESS,
                            sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0 ||
                    strncmp(xattr_name, XATTR_NAME_ACL_DEFAULT,
                            sizeof(XATTR_NAME_ACL_DEFAULT) - 1) == 0)) {
                /* currently lustre limit acl access size */
                if (xattr_len > LUSTRE_POSIX_ACL_MAX_SIZE)
                        GOTO(out, -ERANGE);
        }

        lockpart = MDS_INODELOCK_UPDATE;
        /* Revoke all clients' lookup lock, since the access
         * permissions for this inode is changed when ACL_ACCESS is
         * set. This isn't needed for ACL_DEFAULT, since that does
         * not change the access permissions of this inode, nor any
         * other existing inodes. It is setting the ACLs inherited
         * by new directories/files at create time. */
        if (!strcmp(xattr_name, XATTR_NAME_ACL_ACCESS))
                lockpart |= MDS_INODELOCK_LOOKUP;

        lh = &info->mti_lh[MDT_LH_PARENT];
        /* ACLs were sent to clients under LCK_CR locks, so taking LCK_EX
         * to cancel them. */
        mdt_lock_reg_init(lh, LCK_EX);
        obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart);
        if (IS_ERR(obj))
                GOTO(out, rc =  PTR_ERR(obj));

        info->mti_mos = obj;
        rc = mdt_version_get_check_save(info, obj, 0);
        if (rc)
                GOTO(out_unlock, rc);

        if (unlikely(!(valid & OBD_MD_FLCTIME))) {
                /* This isn't strictly an error, but all current clients
                 * should set OBD_MD_FLCTIME when setting attributes. */
                CWARN("%s: client miss to set OBD_MD_FLCTIME when "
                      "setxattr %s: [object "DFID"] [valid "LPU64"]\n",
                      info->mti_exp->exp_obd->obd_name, xattr_name,
                      PFID(rr->rr_fid1), valid);
                attr->la_ctime = cfs_time_current_sec();
        }
        attr->la_valid = LA_CTIME;
        child = mdt_object_child(obj);
        if (valid & OBD_MD_FLXATTR) {
                char *xattr = (void *)rr->rr_eadata;

                if (xattr_len > 0) {
                        int flags = 0;

                        if (valid & OBD_MD_FLRMTLSETFACL) {
                                if (unlikely(!remote))
                                        GOTO(out_unlock, rc = -EINVAL);

                                xattr_len = mdt_rmtlsetfacl(info, child,
                                                xattr_name,
                                                (ext_acl_xattr_header *)xattr,
                                                &new_xattr);
                                if (xattr_len < 0)
                                        GOTO(out_unlock, rc = xattr_len);

                                xattr = (char *)new_xattr;
                        }

                        if (attr->la_flags & XATTR_REPLACE)
                                flags |= LU_XATTR_REPLACE;

                        if (attr->la_flags & XATTR_CREATE)
                                flags |= LU_XATTR_CREATE;

                        mdt_fail_write(env, info->mti_mdt->mdt_bottom,
                                       OBD_FAIL_MDS_SETXATTR_WRITE);

                        buf->lb_buf = xattr;
                        buf->lb_len = xattr_len;
                        rc = mo_xattr_set(env, child, buf, xattr_name, flags);
                        /* update ctime after xattr changed */
                        if (rc == 0) {
                                ma->ma_attr_flags |= MDS_PERM_BYPASS;
                                mo_attr_set(env, child, ma);
                        }
                }
        } else if (valid & OBD_MD_FLXATTRRM) {
                rc = mo_xattr_del(env, child, xattr_name);
                /* update ctime after xattr changed */
                if (rc == 0) {
                        ma->ma_attr_flags |= MDS_PERM_BYPASS;
                        mo_attr_set(env, child, ma);
                }
        } else {
                CDEBUG(D_INFO, "valid bits: "LPX64"\n", valid);
                rc = -EINVAL;
        }
        if (rc == 0)
                mdt_counter_incr(req->rq_export, LPROC_MDT_SETXATTR);

        EXIT;
out_unlock:
        mdt_object_unlock_put(info, obj, lh, rc);
        if (unlikely(new_xattr != NULL))
                lustre_posix_acl_xattr_free(new_xattr, xattr_len);
out:
        mdt_exit_ucred(info);
        return rc;
}
Esempio n. 8
0
int mdt_getxattr(struct mdt_thread_info *info)
{
        struct ptlrpc_request  *req = mdt_info_req(info);
        struct mdt_export_data *med = mdt_req2med(req);
        struct md_ucred        *uc  = mdt_ucred(info);
        struct mdt_body        *reqbody;
        struct mdt_body        *repbody = NULL;
        struct md_object       *next;
        struct lu_buf          *buf;
        __u32                   remote = exp_connect_rmtclient(info->mti_exp);
        __u32                   perm;
        int                     easize, rc;
        ENTRY;

        LASSERT(info->mti_object != NULL);
        LASSERT(lu_object_assert_exists(&info->mti_object->mot_obj.mo_lu));

        CDEBUG(D_INODE, "getxattr "DFID"\n", PFID(&info->mti_body->fid1));

        reqbody = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
        if (reqbody == NULL)
                RETURN(err_serious(-EFAULT));

        rc = mdt_init_ucred(info, reqbody);
        if (rc)
                RETURN(err_serious(rc));

        next = mdt_object_child(info->mti_object);

        if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL) {
                if (unlikely(!remote))
                        GOTO(out, rc = err_serious(-EINVAL));

                perm = mdt_identity_get_perm(uc->mu_identity, remote,
                                             req->rq_peer.nid);
                if (!(perm & CFS_RMTACL_PERM))
                        GOTO(out, rc = err_serious(-EPERM));

                rc = mo_permission(info->mti_env, NULL, next, NULL,
                                   MAY_RGETFACL);
                if (rc)
                        GOTO(out, rc = err_serious(rc));
        }

        easize = mdt_getxattr_pack_reply(info);
        if (easize < 0)
                GOTO(out, rc = err_serious(easize));

        repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
        LASSERT(repbody != NULL);

        /* No need further getxattr. */
        if (easize == 0 || reqbody->eadatasize == 0)
                GOTO(out, rc = easize);


        buf = &info->mti_buf;
        buf->lb_buf = req_capsule_server_get(info->mti_pill, &RMF_EADATA);
        buf->lb_len = easize;

        if (info->mti_body->valid & OBD_MD_FLXATTR) {
                int flags = CFS_IC_NOTHING;
                char *xattr_name = req_capsule_client_get(info->mti_pill,
                                                          &RMF_NAME);
                CDEBUG(D_INODE, "getxattr %s\n", xattr_name);

                rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
                if (rc < 0) {
                        CERROR("getxattr failed: %d\n", rc);
                        GOTO(out, rc);
                }

                if (info->mti_body->valid &
                    (OBD_MD_FLRMTLSETFACL | OBD_MD_FLRMTLGETFACL))
                        flags = CFS_IC_ALL;
                else if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL)
                        flags = CFS_IC_MAPPED;

                if (rc > 0 && flags != CFS_IC_NOTHING) {
                        int rc1;

                        if (unlikely(!remote))
                                GOTO(out, rc = -EINVAL);

                        rc1 = lustre_posix_acl_xattr_id2client(uc,
                                        med->med_idmap,
                                        (posix_acl_xattr_header *)(buf->lb_buf),
                                        rc, flags);
                        if (unlikely(rc1 < 0))
                                rc = rc1;
                }
        } else if (info->mti_body->valid & OBD_MD_FLXATTRLS) {
                CDEBUG(D_INODE, "listxattr\n");

                rc = mo_xattr_list(info->mti_env, next, buf);
                if (rc < 0)
                        CDEBUG(D_INFO, "listxattr failed: %d\n", rc);
        } else
                LBUG();

        EXIT;
out:
        if (rc >= 0) {
                mdt_counter_incr(req->rq_export, LPROC_MDT_GETXATTR);
                repbody->eadatasize = rc;
                rc = 0;
        }
        mdt_exit_ucred(info);
        return rc;
}
Esempio n. 9
0
int mdt_getxattr(struct mdt_thread_info *info)
{
	struct ptlrpc_request  *req = mdt_info_req(info);
	struct mdt_export_data *med = mdt_req2med(req);
	struct lu_ucred        *uc  = lu_ucred(info->mti_env);
        struct mdt_body        *reqbody;
        struct mdt_body        *repbody = NULL;
        struct md_object       *next;
        struct lu_buf          *buf;
        __u32                   remote = exp_connect_rmtclient(info->mti_exp);
        __u32                   perm;
        int                     easize, rc;
	obd_valid		valid;
        ENTRY;

        LASSERT(info->mti_object != NULL);
	LASSERT(lu_object_assert_exists(&info->mti_object->mot_obj));

        CDEBUG(D_INODE, "getxattr "DFID"\n", PFID(&info->mti_body->fid1));

        reqbody = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
        if (reqbody == NULL)
                RETURN(err_serious(-EFAULT));

	rc = mdt_init_ucred(info, reqbody);
        if (rc)
                RETURN(err_serious(rc));

        next = mdt_object_child(info->mti_object);

        if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL) {
                if (unlikely(!remote))
                        GOTO(out, rc = err_serious(-EINVAL));

		perm = mdt_identity_get_perm(uc->uc_identity, remote,
					     req->rq_peer.nid);
                if (!(perm & CFS_RMTACL_PERM))
                        GOTO(out, rc = err_serious(-EPERM));

                rc = mo_permission(info->mti_env, NULL, next, NULL,
                                   MAY_RGETFACL);
                if (rc)
                        GOTO(out, rc = err_serious(rc));
        }

        easize = mdt_getxattr_pack_reply(info);
        if (easize < 0)
                GOTO(out, rc = err_serious(easize));

        repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
        LASSERT(repbody != NULL);

        /* No need further getxattr. */
        if (easize == 0 || reqbody->eadatasize == 0)
                GOTO(out, rc = easize);

        buf = &info->mti_buf;
        buf->lb_buf = req_capsule_server_get(info->mti_pill, &RMF_EADATA);
        buf->lb_len = easize;

	valid = info->mti_body->valid & (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS);

	if (valid == OBD_MD_FLXATTR) {
		char *xattr_name = req_capsule_client_get(info->mti_pill,
							  &RMF_NAME);
		rc = mdt_getxattr_one(info, xattr_name, next, buf, med, uc);
	} else if (valid == OBD_MD_FLXATTRLS) {
		CDEBUG(D_INODE, "listxattr\n");

		rc = mo_xattr_list(info->mti_env, next, buf);
		if (rc < 0)
			CDEBUG(D_INFO, "listxattr failed: %d\n", rc);
	} else if (valid == OBD_MD_FLXATTRALL) {
		rc = mdt_getxattr_all(info, reqbody, repbody,
				      buf, next);
	} else
		LBUG();

	EXIT;
out:
	if (rc >= 0) {
		mdt_counter_incr(req, LPROC_MDT_GETXATTR);
		repbody->eadatasize = rc;
		rc = 0;
	}
	mdt_exit_ucred(info);
	return rc;
}
Esempio n. 10
0
File: mdt_lib.c Progetto: hpc/lustre
int mdt_check_ucred(struct mdt_thread_info *info)
{
        struct ptlrpc_request   *req = mdt_info_req(info);
        struct mdt_device       *mdt = info->mti_mdt;
        struct ptlrpc_user_desc *pud = req->rq_user_desc;
        struct md_ucred         *ucred = mdt_ucred(info);
        struct md_identity      *identity = NULL;
        lnet_nid_t               peernid = req->rq_peer.nid;
        __u32                    perm = 0;
        __u32                    remote = exp_connect_rmtclient(info->mti_exp);
        int                      setuid;
        int                      setgid;
        int                      rc = 0;

        ENTRY;

        if ((ucred->mu_valid == UCRED_OLD) || (ucred->mu_valid == UCRED_NEW))
                RETURN(0);

        if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
                RETURN(0);

        /* sanity check: if we use strong authentication, we expect the
         * uid which client claimed is true */
        if (remote) {
                if (req->rq_auth_mapped_uid == INVALID_UID) {
                        CDEBUG(D_SEC, "remote user not mapped, deny access!\n");
                        RETURN(-EACCES);
                }

                if (ptlrpc_user_desc_do_idmap(req, pud))
                        RETURN(-EACCES);

                if (req->rq_auth_mapped_uid != pud->pud_uid) {
                        CDEBUG(D_SEC, "remote client %s: auth/mapped uid %u/%u "
                               "while client claims %u:%u/%u:%u\n",
                               libcfs_nid2str(peernid), req->rq_auth_uid,
                               req->rq_auth_mapped_uid,
                               pud->pud_uid, pud->pud_gid,
                               pud->pud_fsuid, pud->pud_fsgid);
                        RETURN(-EACCES);
                }
        } else {
                if (req->rq_auth_uid != pud->pud_uid) {
                        CDEBUG(D_SEC, "local client %s: auth uid %u "
                               "while client claims %u:%u/%u:%u\n",
                               libcfs_nid2str(peernid), req->rq_auth_uid,
                               pud->pud_uid, pud->pud_gid,
                               pud->pud_fsuid, pud->pud_fsgid);
                        RETURN(-EACCES);
                }
        }

        if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
                if (remote) {
                        CDEBUG(D_SEC, "remote client must run with identity_get "
                               "enabled!\n");
                        RETURN(-EACCES);
                }
                RETURN(0);
        }

        identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid);
        if (IS_ERR(identity)) {
                if (unlikely(PTR_ERR(identity) == -EREMCHG &&
                             !remote)) {
                        RETURN(0);
                } else {
                        CDEBUG(D_SEC, "Deny access without identity: uid %u\n",
                               pud->pud_uid);
                        RETURN(-EACCES);
               }
        }

        perm = mdt_identity_get_perm(identity, remote, peernid);
        /* find out the setuid/setgid attempt */
        setuid = (pud->pud_uid != pud->pud_fsuid);
        setgid = (pud->pud_gid != pud->pud_fsgid ||
                  pud->pud_gid != identity->mi_gid);

        /* check permission of setuid */
        if (setuid && !(perm & CFS_SETUID_PERM)) {
                CDEBUG(D_SEC, "mdt blocked setuid attempt (%u -> %u) from %s\n",
                       pud->pud_uid, pud->pud_fsuid, libcfs_nid2str(peernid));
                GOTO(out, rc = -EACCES);
        }

        /* check permission of setgid */
        if (setgid && !(perm & CFS_SETGID_PERM)) {
                CDEBUG(D_SEC, "mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
                       "from %s\n", pud->pud_uid, pud->pud_gid,
                       pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid,
                       libcfs_nid2str(peernid));
                GOTO(out, rc = -EACCES);
        }

        EXIT;

out:
        mdt_identity_put(mdt->mdt_identity_cache, identity);
        return rc;
}
Esempio n. 11
0
File: mdt_lib.c Progetto: hpc/lustre
static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
                          void *buf)
{
        struct ptlrpc_request   *req = mdt_info_req(info);
        struct mdt_device       *mdt = info->mti_mdt;
        struct ptlrpc_user_desc *pud = req->rq_user_desc;
        struct md_ucred         *ucred = mdt_ucred(info);
        lnet_nid_t               peernid = req->rq_peer.nid;
        __u32                    perm = 0;
        __u32                    remote = exp_connect_rmtclient(info->mti_exp);
        int                      setuid;
        int                      setgid;
        int                      rc = 0;

        ENTRY;

        LASSERT(req->rq_auth_gss);
        LASSERT(!req->rq_auth_usr_mdt);
        LASSERT(req->rq_user_desc);

        ucred->mu_valid = UCRED_INVALID;

        ucred->mu_o_uid   = pud->pud_uid;
        ucred->mu_o_gid   = pud->pud_gid;
        ucred->mu_o_fsuid = pud->pud_fsuid;
        ucred->mu_o_fsgid = pud->pud_fsgid;

        if (type == BODY_INIT) {
                struct mdt_body *body = (struct mdt_body *)buf;

                ucred->mu_suppgids[0] = body->suppgid;
                ucred->mu_suppgids[1] = -1;
        }

        /* sanity check: we expect the uid which client claimed is true */
        if (remote) {
                if (req->rq_auth_mapped_uid == INVALID_UID) {
                        CDEBUG(D_SEC, "remote user not mapped, deny access!\n");
                        RETURN(-EACCES);
                }

                if (ptlrpc_user_desc_do_idmap(req, pud))
                        RETURN(-EACCES);

                if (req->rq_auth_mapped_uid != pud->pud_uid) {
                        CDEBUG(D_SEC, "remote client %s: auth/mapped uid %u/%u "
                               "while client claims %u:%u/%u:%u\n",
                               libcfs_nid2str(peernid), req->rq_auth_uid,
                               req->rq_auth_mapped_uid,
                               pud->pud_uid, pud->pud_gid,
                               pud->pud_fsuid, pud->pud_fsgid);
                        RETURN(-EACCES);
                }
        } else {
                if (req->rq_auth_uid != pud->pud_uid) {
                        CDEBUG(D_SEC, "local client %s: auth uid %u "
                               "while client claims %u:%u/%u:%u\n",
                               libcfs_nid2str(peernid), req->rq_auth_uid,
                               pud->pud_uid, pud->pud_gid,
                               pud->pud_fsuid, pud->pud_fsgid);
                        RETURN(-EACCES);
                }
        }

        if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
                if (remote) {
                        CDEBUG(D_SEC, "remote client must run with identity_get "
                               "enabled!\n");
                        RETURN(-EACCES);
                } else {
                        ucred->mu_identity = NULL;
                        perm = CFS_SETUID_PERM | CFS_SETGID_PERM |
                               CFS_SETGRP_PERM;
                }
        } else {
                struct md_identity *identity;

                identity = mdt_identity_get(mdt->mdt_identity_cache,
                                            pud->pud_uid);
                if (IS_ERR(identity)) {
                        if (unlikely(PTR_ERR(identity) == -EREMCHG &&
                                     !remote)) {
                                ucred->mu_identity = NULL;
                                perm = CFS_SETUID_PERM | CFS_SETGID_PERM |
                                       CFS_SETGRP_PERM;
                        } else {
                                CDEBUG(D_SEC, "Deny access without identity: uid %u\n",
                                       pud->pud_uid);
                                RETURN(-EACCES);
                        }
                } else {
                        ucred->mu_identity = identity;
                        perm = mdt_identity_get_perm(ucred->mu_identity,
                                                     remote, peernid);
                }
        }

        /* find out the setuid/setgid attempt */
        setuid = (pud->pud_uid != pud->pud_fsuid);
        setgid = ((pud->pud_gid != pud->pud_fsgid) ||
                  (ucred->mu_identity &&
                  (pud->pud_gid != ucred->mu_identity->mi_gid)));

        /* check permission of setuid */
        if (setuid && !(perm & CFS_SETUID_PERM)) {
                CDEBUG(D_SEC, "mdt blocked setuid attempt (%u -> %u) from %s\n",
                       pud->pud_uid, pud->pud_fsuid, libcfs_nid2str(peernid));
                GOTO(out, rc = -EACCES);
        }

        /* check permission of setgid */
        if (setgid && !(perm & CFS_SETGID_PERM)) {
                CDEBUG(D_SEC, "mdt blocked setgid attempt (%u:%u/%u:%u -> %u) "
                       "from %s\n", pud->pud_uid, pud->pud_gid,
                       pud->pud_fsuid, pud->pud_fsgid,
                       ucred->mu_identity->mi_gid, libcfs_nid2str(peernid));
                GOTO(out, rc = -EACCES);
        }

        /*
         * NB: remote client not allowed to setgroups anyway.
         */
        if (!remote && perm & CFS_SETGRP_PERM) {
                if (pud->pud_ngroups) {
                        /* setgroups for local client */
                        ucred->mu_ginfo = cfs_groups_alloc(pud->pud_ngroups);
                        if (!ucred->mu_ginfo) {
                                CERROR("failed to alloc %d groups\n",
                                       pud->pud_ngroups);
                                GOTO(out, rc = -ENOMEM);
                        }

                        lustre_groups_from_list(ucred->mu_ginfo,
                                                pud->pud_groups);
                        lustre_groups_sort(ucred->mu_ginfo);
                } else {
                        ucred->mu_ginfo = NULL;
                }
        } else {
                ucred->mu_suppgids[0] = -1;
                ucred->mu_suppgids[1] = -1;
                ucred->mu_ginfo = NULL;
        }

        ucred->mu_uid   = pud->pud_uid;
        ucred->mu_gid   = pud->pud_gid;
        ucred->mu_fsuid = pud->pud_fsuid;
        ucred->mu_fsgid = pud->pud_fsgid;

        /* process root_squash here. */
        mdt_root_squash(info, peernid);

        /* remove fs privilege for non-root user. */
        if (ucred->mu_fsuid)
                ucred->mu_cap = pud->pud_cap & ~CFS_CAP_FS_MASK;
        else
                ucred->mu_cap = pud->pud_cap;
        if (remote && !(perm & CFS_RMTOWN_PERM))
                ucred->mu_cap &= ~(CFS_CAP_SYS_RESOURCE_MASK |
                                   CFS_CAP_CHOWN_MASK);
        ucred->mu_valid = UCRED_NEW;

        EXIT;

out:
        if (rc) {
                if (ucred->mu_ginfo) {
                        cfs_put_group_info(ucred->mu_ginfo);
                        ucred->mu_ginfo = NULL;
                }
                if (ucred->mu_identity) {
                        mdt_identity_put(mdt->mdt_identity_cache,
                                         ucred->mu_identity);
                        ucred->mu_identity = NULL;
                }
        }

        return rc;
}
Esempio n. 12
0
/**
 * Prepare buffers for write request processing.
 *
 * This function converts remote buffers from client to local buffers
 * and prepares the latter. If there is recovery in progress and required
 * object is missing then it can be re-created before write.
 *
 * \param[in] env	execution environment
 * \param[in] exp	OBD export of client
 * \param[in] ofd	OFD device
 * \param[in] fid	FID of object
 * \param[in] la	object attributes
 * \param[in] oa	OBDO structure from client
 * \param[in] objcount	always 1
 * \param[in] obj	object data
 * \param[in] rnb	remote buffers
 * \param[in] nr_local	number of local buffers
 * \param[in] lnb	local buffers
 * \param[in] jobid	job ID name
 *
 * \retval		0 on successful prepare
 * \retval		negative value on error
 */
static int ofd_preprw_write(const struct lu_env *env, struct obd_export *exp,
			    struct ofd_device *ofd, const struct lu_fid *fid,
			    struct lu_attr *la, struct obdo *oa,
			    int objcount, struct obd_ioobj *obj,
			    struct niobuf_remote *rnb, int *nr_local,
			    struct niobuf_local *lnb, char *jobid)
{
	struct ofd_object	*fo;
	int			 i, j, k, rc = 0, tot_bytes = 0;

	ENTRY;
	LASSERT(env != NULL);
	LASSERT(objcount == 1);

	if (unlikely(exp->exp_obd->obd_recovering)) {
		u64 seq = fid_seq(fid);
		u64 oid = fid_oid(fid);
		struct ofd_seq *oseq;

		oseq = ofd_seq_load(env, ofd, seq);
		if (IS_ERR(oseq)) {
			CERROR("%s: Can't find FID Sequence "LPX64": rc = %d\n",
			       ofd_name(ofd), seq, (int)PTR_ERR(oseq));
			GOTO(out, rc = -EINVAL);
		}

		if (oid > ofd_seq_last_oid(oseq)) {
			int sync = 0;
			int diff;

			mutex_lock(&oseq->os_create_lock);
			diff = oid - ofd_seq_last_oid(oseq);

			/* Do sync create if the seq is about to used up */
			if (fid_seq_is_idif(seq) || fid_seq_is_mdt0(seq)) {
				if (unlikely(oid >= IDIF_MAX_OID - 1))
					sync = 1;
			} else if (fid_seq_is_norm(seq)) {
				if (unlikely(oid >=
					     LUSTRE_DATA_SEQ_MAX_WIDTH - 1))
					sync = 1;
			} else {
				CERROR("%s : invalid o_seq "DOSTID"\n",
				       ofd_name(ofd), POSTID(&oa->o_oi));
				mutex_unlock(&oseq->os_create_lock);
				ofd_seq_put(env, oseq);
				GOTO(out, rc = -EINVAL);
			}

			while (diff > 0) {
				u64 next_id = ofd_seq_last_oid(oseq) + 1;
				int count = ofd_precreate_batch(ofd, diff);

				rc = ofd_precreate_objects(env, ofd, next_id,
							   oseq, count, sync);
				if (rc < 0) {
					mutex_unlock(&oseq->os_create_lock);
					ofd_seq_put(env, oseq);
					GOTO(out, rc);
				}

				diff -= rc;
			}

			mutex_unlock(&oseq->os_create_lock);
		}

		ofd_seq_put(env, oseq);
	}

	fo = ofd_object_find(env, ofd, fid);
	if (IS_ERR(fo))
		GOTO(out, rc = PTR_ERR(fo));
	LASSERT(fo != NULL);

	ofd_read_lock(env, fo);
	if (!ofd_object_exists(fo)) {
		CERROR("%s: BRW to missing obj "DOSTID"\n",
		       exp->exp_obd->obd_name, POSTID(&obj->ioo_oid));
		ofd_read_unlock(env, fo);
		ofd_object_put(env, fo);
		GOTO(out, rc = -ENOENT);
	}

	if (ofd->ofd_lfsck_verify_pfid && oa->o_valid & OBD_MD_FLFID) {
		rc = ofd_verify_ff(env, fo, oa);
		if (rc != 0) {
			ofd_read_unlock(env, fo);
			ofd_object_put(env, fo);
			GOTO(out, rc);
		}
	}

	/* Process incoming grant info, set OBD_BRW_GRANTED flag and grant some
	 * space back if possible */
	ofd_grant_prepare_write(env, exp, oa, rnb, obj->ioo_bufcnt);

	/* parse remote buffers to local buffers and prepare the latter */
	*nr_local = 0;
	for (i = 0, j = 0; i < obj->ioo_bufcnt; i++) {
		rc = dt_bufs_get(env, ofd_object_child(fo),
				 rnb + i, lnb + j, 1);
		if (unlikely(rc < 0))
			GOTO(err, rc);
		LASSERT(rc <= PTLRPC_MAX_BRW_PAGES);
		/* correct index for local buffers to continue with */
		for (k = 0; k < rc; k++) {
			lnb[j+k].lnb_flags = rnb[i].rnb_flags;
			if (!(rnb[i].rnb_flags & OBD_BRW_GRANTED))
				lnb[j+k].lnb_rc = -ENOSPC;

			/* remote client can't break through quota */
			if (exp_connect_rmtclient(exp))
				lnb[j+k].lnb_flags &= ~OBD_BRW_NOQUOTA;
		}
		j += rc;
		*nr_local += rc;
		LASSERT(j <= PTLRPC_MAX_BRW_PAGES);
		tot_bytes += rnb[i].rnb_len;
	}
	LASSERT(*nr_local > 0 && *nr_local <= PTLRPC_MAX_BRW_PAGES);

	rc = dt_write_prep(env, ofd_object_child(fo), lnb, *nr_local);
	if (unlikely(rc != 0))
		GOTO(err, rc);

	ofd_counter_incr(exp, LPROC_OFD_STATS_WRITE, jobid, tot_bytes);
	RETURN(0);
err:
	dt_bufs_put(env, ofd_object_child(fo), lnb, *nr_local);
	ofd_read_unlock(env, fo);
	ofd_object_put(env, fo);
	/* ofd_grant_prepare_write() was called, so we must commit */
	ofd_grant_commit(exp, oa->o_grant_used, rc);
out:
	/* let's still process incoming grant information packed in the oa,
	 * but without enforcing grant since we won't proceed with the write.
	 * Just like a read request actually. */
	ofd_grant_prepare_read(env, exp, oa);
	return rc;
}
Esempio n. 13
0
int mdt_handle_idmap(struct mdt_thread_info *info)
{
        struct ptlrpc_request *req = mdt_info_req(info);
        struct mdt_device *mdt = info->mti_mdt;
        struct mdt_export_data *med;
        struct ptlrpc_user_desc *pud = req->rq_user_desc;
        struct md_identity *identity;
        __u32 opc;
        int rc = 0;
        ENTRY;

        if (!req->rq_export)
                RETURN(0);

        med = mdt_req2med(req);
        if (!exp_connect_rmtclient(info->mti_exp))
                RETURN(0);

        opc = lustre_msg_get_opc(req->rq_reqmsg);
        /* Bypass other opc */
        if ((opc != SEC_CTX_INIT) && (opc != SEC_CTX_INIT_CONT) &&
            (opc != SEC_CTX_FINI) && (opc != MDS_CONNECT))
                RETURN(0);

        LASSERT(med->med_idmap);

        if (unlikely(!pud)) {
                CDEBUG(D_SEC, "remote client must run with rq_user_desc "
                       "present\n");
                RETURN(-EACCES);
        }

        if (req->rq_auth_mapped_uid == INVALID_UID) {
                CDEBUG(D_SEC, "invalid authorized mapped uid, please check "
                       "/etc/lustre/idmap.conf!\n");
                RETURN(-EACCES);
        }

        if (is_identity_get_disabled(mdt->mdt_identity_cache)) {
                CDEBUG(D_SEC, "remote client must run with identity_get "
                       "enabled!\n");
                RETURN(-EACCES);
        }

        identity = mdt_identity_get(mdt->mdt_identity_cache,
                                    req->rq_auth_mapped_uid);
        if (IS_ERR(identity)) {
                CDEBUG(D_SEC, "can't get mdt identity(%u), no mapping added\n",
                       req->rq_auth_mapped_uid);
                RETURN(-EACCES);
        }

        switch (opc) {
                case SEC_CTX_INIT:
                case SEC_CTX_INIT_CONT:
                case MDS_CONNECT:
                        rc = lustre_idmap_add(med->med_idmap,
                                              pud->pud_uid, identity->mi_uid,
                                              pud->pud_gid, identity->mi_gid);
                        break;
                case SEC_CTX_FINI:
                        rc = lustre_idmap_del(med->med_idmap,
                                              pud->pud_uid, identity->mi_uid,
                                              pud->pud_gid, identity->mi_gid);
                        break;
        }

        mdt_identity_put(mdt->mdt_identity_cache, identity);

        if (rc)
                RETURN(rc);

        switch (opc) {
                case SEC_CTX_INIT:
                case SEC_CTX_INIT_CONT:
                case SEC_CTX_FINI:
                        mdt_revoke_export_locks(req->rq_export);
                        break;
        }

        RETURN(0);
}
Esempio n. 14
0
static int ofd_preprw_write(const struct lu_env *env, struct obd_export *exp,
                            struct ofd_device *ofd, struct lu_fid *fid,
                            struct lu_attr *la, struct obdo *oa,
                            int objcount, struct obd_ioobj *obj,
                            struct niobuf_remote *rnb, int *nr_local,
                            struct niobuf_local *lnb, char *jobid)
{
    struct ofd_object	*fo;
    int			 i, j, k, rc = 0, tot_bytes = 0;

    ENTRY;
    LASSERT(env != NULL);
    LASSERT(objcount == 1);

    if (unlikely(exp->exp_obd->obd_recovering)) {
        struct ofd_thread_info *info = ofd_info(env);

        /* copied from ofd_precreate_object */
        /* XXX this should be consolidated to use the same code
         *     instead of a copy, due to the ongoing risk of bugs. */
        memset(&info->fti_attr, 0, sizeof(info->fti_attr));
        info->fti_attr.la_valid = LA_TYPE | LA_MODE;
        info->fti_attr.la_mode = S_IFREG | S_ISUID | S_ISGID | 0666;
        info->fti_attr.la_valid |= LA_ATIME | LA_MTIME | LA_CTIME;
        /* Initialize a/c/m time so any client timestamp will always
         * be newer and update the inode. ctime = 0 is also handled
         * specially in osd_inode_setattr().  See LU-221, LU-1042 */
        info->fti_attr.la_atime = 0;
        info->fti_attr.la_mtime = 0;
        info->fti_attr.la_ctime = 0;

        fo = ofd_object_find_or_create(env, ofd, fid, &info->fti_attr);
    } else {
        fo = ofd_object_find(env, ofd, fid);
    }

    if (IS_ERR(fo))
        GOTO(out, rc = PTR_ERR(fo));
    LASSERT(fo != NULL);

    ofd_read_lock(env, fo);
    if (!ofd_object_exists(fo)) {
        CERROR("%s: BRW to missing obj "DOSTID"\n",
               exp->exp_obd->obd_name, POSTID(&obj->ioo_oid));
        ofd_read_unlock(env, fo);
        ofd_object_put(env, fo);
        GOTO(out, rc = -ENOENT);
    }

    /* Process incoming grant info, set OBD_BRW_GRANTED flag and grant some
     * space back if possible */
    ofd_grant_prepare_write(env, exp, oa, rnb, obj->ioo_bufcnt);

    /* parse remote buffers to local buffers and prepare the latter */
    *nr_local = 0;
    for (i = 0, j = 0; i < obj->ioo_bufcnt; i++) {
        rc = dt_bufs_get(env, ofd_object_child(fo),
                         rnb + i, lnb + j, 1,
                         ofd_object_capa(env, fo));
        if (unlikely(rc < 0))
            GOTO(err, rc);
        LASSERT(rc <= PTLRPC_MAX_BRW_PAGES);
        /* correct index for local buffers to continue with */
        for (k = 0; k < rc; k++) {
            lnb[j+k].lnb_flags = rnb[i].rnb_flags;
            if (!(rnb[i].rnb_flags & OBD_BRW_GRANTED))
                lnb[j+k].lnb_rc = -ENOSPC;

            /* remote client can't break through quota */
            if (exp_connect_rmtclient(exp))
                lnb[j+k].lnb_flags &= ~OBD_BRW_NOQUOTA;
        }
        j += rc;
        *nr_local += rc;
        LASSERT(j <= PTLRPC_MAX_BRW_PAGES);
        tot_bytes += rnb[i].rnb_len;
    }
    LASSERT(*nr_local > 0 && *nr_local <= PTLRPC_MAX_BRW_PAGES);

    rc = dt_write_prep(env, ofd_object_child(fo), lnb, *nr_local);
    if (unlikely(rc != 0))
        GOTO(err, rc);

    ofd_counter_incr(exp, LPROC_OFD_STATS_WRITE, jobid, tot_bytes);
    RETURN(0);
err:
    dt_bufs_put(env, ofd_object_child(fo), lnb, *nr_local);
    ofd_read_unlock(env, fo);
    /* ofd_grant_prepare_write() was called, so we must commit */
    ofd_grant_commit(env, exp, rc);
out:
    /* let's still process incoming grant information packed in the oa,
     * but without enforcing grant since we won't proceed with the write.
     * Just like a read request actually. */
    ofd_grant_prepare_read(env, exp, oa);
    return rc;
}