Whamcloud - gitweb
LU-14121 nodemap: do not force fsuid/fsgid squashing
[fs/lustre-release.git] / lustre / mdt / mdt_lib.c
index 69c916b..be2531a 100644 (file)
@@ -166,7 +166,7 @@ static void ucred_set_audit_enabled(struct mdt_thread_info *info,
 }
 
 static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
-                         void *buf, bool drop_fs_cap)
+                         void *buf)
 {
        struct ptlrpc_request *req = mdt_info_req(info);
        struct mdt_device *mdt = info->mti_mdt;
@@ -214,9 +214,6 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
                        RETURN(-EACCES);
                }
 
-               ucred->uc_fsuid = nodemap->nm_squash_uid;
-               ucred->uc_fsgid = nodemap->nm_squash_gid;
-               ucred->uc_cap = 0;
                ucred->uc_suppgids[0] = -1;
                ucred->uc_suppgids[1] = -1;
        }
@@ -318,17 +315,18 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
 
        ucred->uc_uid = pud->pud_uid;
        ucred->uc_gid = pud->pud_gid;
+
+       if (nodemap && ucred->uc_o_uid == nodemap->nm_squash_uid) {
+               ucred->uc_cap = 0;
+       } else {
+               ucred->uc_cap = pud->pud_cap;
+       }
        ucred->uc_fsuid = pud->pud_fsuid;
        ucred->uc_fsgid = pud->pud_fsgid;
 
        /* process root_squash here. */
        mdt_root_squash(info, peernid);
 
-       /* remove fs privilege for non-root user. */
-       if (ucred->uc_fsuid && drop_fs_cap)
-               ucred->uc_cap = pud->pud_cap & ~CFS_CAP_FS_MASK;
-       else
-               ucred->uc_cap = pud->pud_cap;
        ucred->uc_valid = UCRED_NEW;
        ucred_set_jobid(info, ucred);
        ucred_set_nid(info, ucred);
@@ -462,8 +460,7 @@ out:
 }
 
 static int old_init_ucred_common(struct mdt_thread_info *info,
-                                struct lu_nodemap *nodemap,
-                                bool drop_fs_cap)
+                                struct lu_nodemap *nodemap)
 {
        struct lu_ucred         *uc = mdt_ucred(info);
        struct mdt_device       *mdt = info->mti_mdt;
@@ -474,8 +471,6 @@ static int old_init_ucred_common(struct mdt_thread_info *info,
                if (nodemap->nmf_deny_unknown)
                        RETURN(-EACCES);
 
-               uc->uc_fsuid = nodemap->nm_squash_uid;
-               uc->uc_fsgid = nodemap->nm_squash_gid;
                uc->uc_cap = 0;
                uc->uc_suppgids[0] = -1;
                uc->uc_suppgids[1] = -1;
@@ -500,9 +495,6 @@ static int old_init_ucred_common(struct mdt_thread_info *info,
        /* process root_squash here. */
        mdt_root_squash(info, mdt_info_req(info)->rq_peer.nid);
 
-       /* remove fs privilege for non-root user. */
-       if (uc->uc_fsuid && drop_fs_cap)
-               uc->uc_cap &= ~CFS_CAP_FS_MASK;
        uc->uc_valid = UCRED_OLD;
        ucred_set_jobid(info, uc);
        ucred_set_nid(info, uc);
@@ -514,7 +506,7 @@ static int old_init_ucred_common(struct mdt_thread_info *info,
 }
 
 static int old_init_ucred(struct mdt_thread_info *info,
-                         struct mdt_body *body, bool drop_fs_cap)
+                         struct mdt_body *body)
 {
        struct lu_ucred *uc = mdt_ucred(info);
        struct lu_nodemap *nodemap;
@@ -545,7 +537,7 @@ static int old_init_ucred(struct mdt_thread_info *info,
        uc->uc_ginfo = NULL;
        uc->uc_cap = body->mbo_capability;
 
-       rc = old_init_ucred_common(info, nodemap, drop_fs_cap);
+       rc = old_init_ucred_common(info, nodemap);
        nodemap_putref(nodemap);
 
        RETURN(rc);
@@ -574,15 +566,14 @@ static int old_init_ucred_reint(struct mdt_thread_info *info)
        uc->uc_o_gid = uc->uc_o_fsgid = uc->uc_gid = uc->uc_fsgid;
        uc->uc_ginfo = NULL;
 
-       rc = old_init_ucred_common(info, nodemap, true); /* drop_fs_cap=true */
+       rc = old_init_ucred_common(info, nodemap);
        nodemap_putref(nodemap);
 
        RETURN(rc);
 }
 
 static inline int __mdt_init_ucred(struct mdt_thread_info *info,
-                                  struct mdt_body *body,
-                                  bool drop_fs_cap)
+                                  struct mdt_body *body)
 {
        struct ptlrpc_request   *req = mdt_info_req(info);
        struct lu_ucred         *uc  = mdt_ucred(info);
@@ -594,25 +585,14 @@ static inline int __mdt_init_ucred(struct mdt_thread_info *info,
        mdt_exit_ucred(info);
 
        if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
-               return old_init_ucred(info, body, drop_fs_cap);
+               return old_init_ucred(info, body);
        else
-               return new_init_ucred(info, BODY_INIT, body, drop_fs_cap);
+               return new_init_ucred(info, BODY_INIT, body);
 }
 
 int mdt_init_ucred(struct mdt_thread_info *info, struct mdt_body *body)
 {
-       return __mdt_init_ucred(info, body, true);
-}
-
-/* LU-6528 when "no_subtree_check" is set for NFS export, nfsd_set_fh_dentry()
- * doesn't set correct fsuid explicitely, but raise capability to allow
- * exportfs_decode_fh() to reconnect disconnected dentry into dcache. So for
- * lookup (i.e. intent_getattr), we should keep FS capability, otherwise it
- * will fail permission check. */
-int mdt_init_ucred_intent_getattr(struct mdt_thread_info *info,
-                                 struct mdt_body *body)
-{
-       return __mdt_init_ucred(info, body, false);
+       return __mdt_init_ucred(info, body);
 }
 
 int mdt_init_ucred_reint(struct mdt_thread_info *info)
@@ -635,7 +615,7 @@ int mdt_init_ucred_reint(struct mdt_thread_info *info)
        if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc)
                return old_init_ucred_reint(info);
        else
-               return new_init_ucred(info, REC_INIT, NULL, true);
+               return new_init_ucred(info, REC_INIT, NULL);
 }
 
 /* copied from lov/lov_ea.c, just for debugging, will be removed later */
@@ -795,6 +775,12 @@ int mdt_fix_reply(struct mdt_thread_info *info)
            !(body->mbo_valid & OBD_MD_SECCTX))
                req_capsule_shrink(pill, &RMF_FILE_SECCTX, 0, RCL_SERVER);
 
+       /* Shrink optional ENCCTX buffer if it is not used */
+       if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX, RCL_SERVER) &&
+           req_capsule_get_size(pill, &RMF_FILE_ENCCTX, RCL_SERVER) != 0 &&
+           !(body->mbo_valid & OBD_MD_ENCCTX))
+               req_capsule_shrink(pill, &RMF_FILE_ENCCTX, 0, RCL_SERVER);
+
        /*
         * Some more field should be shrinked if needed.
         * This should be done by those who added fields to reply message.
@@ -1085,6 +1071,28 @@ static int mdt_file_secctx_unpack(struct req_capsule *pill,
        return 0;
 }
 
+static int mdt_file_encctx_unpack(struct req_capsule *pill,
+                                 void **encctx, size_t *encctx_size)
+{
+       *encctx = NULL;
+       *encctx_size = 0;
+
+       if (!exp_connect_encrypt(pill->rc_req->rq_export))
+               return 0;
+
+       if (!req_capsule_has_field(pill, &RMF_FILE_ENCCTX, RCL_CLIENT) ||
+           !req_capsule_field_present(pill, &RMF_FILE_ENCCTX, RCL_CLIENT))
+               return -EPROTO;
+
+       *encctx_size = req_capsule_get_size(pill, &RMF_FILE_ENCCTX, RCL_CLIENT);
+       if (*encctx_size == 0)
+               return 0;
+
+       *encctx = req_capsule_client_get(pill, &RMF_FILE_ENCCTX);
+
+       return 0;
+}
+
 static int mdt_setattr_unpack_rec(struct mdt_thread_info *info)
 {
        struct lu_ucred *uc = mdt_ucred(info);
@@ -1318,6 +1326,11 @@ static int mdt_create_unpack(struct mdt_thread_info *info)
        if (rc < 0)
                RETURN(rc);
 
+       rc = mdt_file_encctx_unpack(pill, &sp->sp_cr_file_encctx,
+                                   &sp->sp_cr_file_encctx_size);
+       if (rc < 0)
+               RETURN(rc);
+
        rc = req_check_sepol(pill);
        if (rc)
                RETURN(rc);
@@ -1520,7 +1533,10 @@ static int mdt_migrate_unpack(struct mdt_thread_info *info)
                        RETURN(rc);
 
                spec->sp_migrate_close = 1;
+       } else {
+               spec->sp_migrate_close = 0;
        }
+       spec->sp_migrate_nsonly = 0;
 
        /* lustre version > 2.11 migration packs lum */
        if (req_capsule_has_field(pill, &RMF_EADATA, RCL_CLIENT)) {
@@ -1645,6 +1661,11 @@ static int mdt_open_unpack(struct mdt_thread_info *info)
        if (rc < 0)
                RETURN(rc);
 
+       rc = mdt_file_encctx_unpack(pill, &sp->sp_cr_file_encctx,
+                                   &sp->sp_cr_file_encctx_size);
+       if (rc < 0)
+               RETURN(rc);
+
        rc = req_check_sepol(pill);
        if (rc)
                RETURN(rc);
@@ -1779,14 +1800,14 @@ int mdt_reint_unpack(struct mdt_thread_info *info, __u32 op)
         RETURN(rc);
 }
 
-void mdt_pack_secctx_in_reply(struct mdt_thread_info *info,
-                             struct mdt_object *child)
+int mdt_pack_secctx_in_reply(struct mdt_thread_info *info,
+                            struct mdt_object *child)
 {
        char *secctx_name;
        struct lu_buf *buffer;
        struct mdt_body *repbody;
        struct req_capsule *pill = info->mti_pill;
-       int rc;
+       int rc = 0;
 
        if (req_capsule_has_field(pill, &RMF_FILE_SECCTX, RCL_SERVER) &&
            req_capsule_get_size(pill, &RMF_FILE_SECCTX, RCL_SERVER) != 0) {
@@ -1811,12 +1832,192 @@ void mdt_pack_secctx_in_reply(struct mdt_thread_info *info,
                        if (rc < buffer->lb_len)
                                req_capsule_shrink(pill, &RMF_FILE_SECCTX, rc,
                                                   RCL_SERVER);
+                       rc = 0;
                } else {
                        CDEBUG(D_SEC,
                             "security context not found for "DFID": rc = %d\n",
                             PFID(mdt_object_fid(child)), rc);
                        req_capsule_shrink(pill, &RMF_FILE_SECCTX, 0,
                                           RCL_SERVER);
+                       /* handling -ENOENT is important because it may change
+                        * object state in DNE env dropping LOHA_EXISTS flag,
+                        * it is important to return that to the caller.
+                        * Check LU-13115 for details.
+                        */
+                       if (rc != -ENOENT)
+                               rc = 0;
                }
        }
+       return rc;
+}
+
+/* check whether two FIDs belong to different MDT. */
+static int mdt_fids_different_target(struct mdt_thread_info *info,
+                                    const struct lu_fid *fid1,
+                                    const struct lu_fid *fid2)
+{
+       const struct lu_env *env = info->mti_env;
+       struct mdt_device *mdt = info->mti_mdt;
+       struct lu_seq_range *range = &info->mti_range;
+       struct seq_server_site *ss;
+       __u32 index1, index2;
+       int rc;
+
+       if (fid_seq(fid1) == fid_seq(fid2))
+               return 0;
+
+       ss = mdt->mdt_lu_dev.ld_site->ld_seq_site;
+
+       range->lsr_flags = LU_SEQ_RANGE_MDT;
+       rc = fld_server_lookup(env, ss->ss_server_fld, fid1->f_seq, range);
+       if (rc)
+               return rc;
+
+       index1 = range->lsr_index;
+
+       rc = fld_server_lookup(env, ss->ss_server_fld, fid2->f_seq, range);
+       if (rc)
+               return rc;
+
+       index2 = range->lsr_index;
+
+       return index1 != index2;
+}
+
+/**
+ * Check whether \a child is remote object on \a parent.
+ *
+ * \param[in]  info    thread environment
+ * \param[in]  parent  parent object, it's the same as child object in
+ *                     getattr_by_fid
+ * \param[in]  child   child object
+ *
+ * \retval 1   is remote object.
+ * \retval 0   isn't remote object.
+ * \retval < 1  error code
+ */
+int mdt_is_remote_object(struct mdt_thread_info *info,
+                        struct mdt_object *parent,
+                        struct mdt_object *child)
+{
+       struct lu_buf *buf = &info->mti_big_buf;
+       struct linkea_data ldata = { NULL };
+       struct link_ea_header *leh;
+       struct link_ea_entry *lee;
+       struct lu_name name;
+       struct lu_fid pfid;
+       int reclen;
+       int i;
+       int rc;
+
+       ENTRY;
+
+       if (fid_is_root(mdt_object_fid(child)))
+               RETURN(0);
+
+       if (likely(parent != child)) {
+               if (mdt_object_remote(parent) ^ mdt_object_remote(child))
+                       RETURN(1);
+
+               if (!mdt_object_remote(parent) && !mdt_object_remote(child))
+                       RETURN(0);
+
+               rc = mdt_fids_different_target(info, mdt_object_fid(parent),
+                                              mdt_object_fid(child));
+               RETURN(rc);
+       }
+
+       /* client < 2.13.52 getattr_by_fid parent and child are the same */
+       buf = lu_buf_check_and_alloc(buf, PATH_MAX);
+       if (!buf->lb_buf)
+               RETURN(-ENOMEM);
+
+       ldata.ld_buf = buf;
+       rc = mdt_links_read(info, child, &ldata);
+       /* can't read linkea, just assume it's remote object */
+       if (rc == -ENOENT || rc == -ENODATA)
+               RETURN(1);
+       if (rc)
+               RETURN(rc);
+
+       leh = buf->lb_buf;
+       lee = (struct link_ea_entry *)(leh + 1);
+       for (i = 0; i < leh->leh_reccount; i++) {
+               linkea_entry_unpack(lee, &reclen, &name, &pfid);
+               lee = (struct link_ea_entry *) ((char *)lee + reclen);
+               if (mdt_fids_different_target(info, &pfid,
+                                             mdt_object_fid(child)))
+                       RETURN(1);
+       }
+
+       RETURN(0);
+}
+
+int mdt_pack_encctx_in_reply(struct mdt_thread_info *info,
+                            struct mdt_object *child)
+{
+       struct lu_buf *buffer;
+       struct mdt_body *repbody;
+       struct req_capsule *pill = info->mti_pill;
+       struct obd_export *exp = mdt_info_req(info)->rq_export;
+       int rc = 0;
+
+       if (!exp_connect_encrypt(exp))
+               return rc;
+
+       if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX, RCL_SERVER) &&
+           req_capsule_get_size(pill, &RMF_FILE_ENCCTX, RCL_SERVER) != 0) {
+               struct lu_attr la = { 0 };
+               struct dt_object *dt = mdt_obj2dt(child);
+
+               if (dt && dt->do_ops && dt->do_ops->do_attr_get)
+                       dt_attr_get(info->mti_env, mdt_obj2dt(child), &la);
+
+               if (la.la_valid & LA_FLAGS && la.la_flags & LUSTRE_ENCRYPT_FL) {
+                       buffer = &info->mti_buf;
+
+                       /* fill reply buffer with encryption context now */
+                       buffer->lb_len =
+                               req_capsule_get_size(pill, &RMF_FILE_ENCCTX,
+                                                    RCL_SERVER);
+                       buffer->lb_buf =
+                               req_capsule_server_get(pill, &RMF_FILE_ENCCTX);
+                       rc = mo_xattr_get(info->mti_env,
+                                         mdt_object_child(child),
+                                         buffer,
+                                         LL_XATTR_NAME_ENCRYPTION_CONTEXT);
+                       if (rc >= 0) {
+                               CDEBUG(D_SEC,
+                                      "found encryption ctx of size %d for "DFID"\n",
+                                      rc, PFID(mdt_object_fid(child)));
+
+                               repbody = req_capsule_server_get(pill,
+                                                                &RMF_MDT_BODY);
+                               repbody->mbo_valid |= OBD_MD_ENCCTX;
+                               if (rc < buffer->lb_len)
+                                       req_capsule_shrink(pill,
+                                                          &RMF_FILE_ENCCTX, rc,
+                                                          RCL_SERVER);
+                               rc = 0;
+                       } else {
+                               CDEBUG(D_SEC,
+                                      "encryption ctx not found for "DFID": rc = %d\n",
+                                      PFID(mdt_object_fid(child)), rc);
+                               req_capsule_shrink(pill, &RMF_FILE_ENCCTX, 0,
+                                                  RCL_SERVER);
+                               /* handling -ENOENT is important because it may
+                                * change object state in DNE env dropping
+                                * LOHA_EXISTS flag, it is important to return
+                                * that to the caller.
+                                * Check LU-13115 for details.
+                                */
+                               if (rc != -ENOENT)
+                                       rc = 0;
+                       }
+               } else {
+                       req_capsule_shrink(pill, &RMF_FILE_ENCCTX, 0,
+                                          RCL_SERVER);
+               }
+       }
+       return rc;
 }