Whamcloud - gitweb
land b_hd_sec onto HEAD: various security related fixes.
authorericm <ericm>
Mon, 20 Jun 2005 22:18:48 +0000 (22:18 +0000)
committerericm <ericm>
Mon, 20 Jun 2005 22:18:48 +0000 (22:18 +0000)
16 files changed:
lustre/include/linux/lustre_sec.h
lustre/include/linux/lustre_smfs.h
lustre/llite/dir.c
lustre/mdc/mdc_locks.c
lustre/osc/osc_request.c
lustre/sec/gss/sec_gss.c
lustre/sec/sec.c
lustre/smfs/cache.c
lustre/smfs/dir.c
lustre/smfs/file.c
lustre/smfs/smfs_internal.h
lustre/smfs/symlink.c
lustre/tests/acl/inheritance.test [new file with mode: 0644]
lustre/tests/acl/make-tree [new file with mode: 0755]
lustre/tests/acl/permissions.test
lustre/tests/sanity-sec.sh

index 34efde0..4426178 100644 (file)
@@ -234,6 +234,7 @@ static inline int ptlrpcs_cred_is_uptodate(struct ptlrpc_cred *cred)
         return ((cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) ==
                 PTLRPC_CRED_UPTODATE);
 }
+
 static inline int ptlrpcs_cred_refresh(struct ptlrpc_cred *cred)
 {
         LASSERT(cred);
@@ -242,21 +243,32 @@ static inline int ptlrpcs_cred_refresh(struct ptlrpc_cred *cred)
         LASSERT(cred->pc_ops->refresh);
         return cred->pc_ops->refresh(cred);
 }
-static inline void ptlrpcs_cred_die(struct ptlrpc_cred *cred)
+
+/* we set the cred flags is safe since cred cache code don't
+ * touch cred with refcount > 0
+ */
+static inline void ptlrpcs_cred_expire(struct ptlrpc_cred *cred)
 {
         LASSERT(atomic_read(&cred->pc_refcount));
         LASSERT(cred->pc_sec);
-        if (!(cred->pc_flags & PTLRPC_CRED_DEAD)) {
-                spin_lock(&cred->pc_sec->ps_lock);
-                cred->pc_flags |= PTLRPC_CRED_DEAD;
-                cred->pc_flags &= ~PTLRPC_CRED_UPTODATE;
-                list_del_init(&cred->pc_hash);
-                spin_unlock(&cred->pc_sec->ps_lock);
-        }
+
+        if (cred->pc_flags & PTLRPC_CRED_DEAD)
+                return;
+        cred->pc_flags |= PTLRPC_CRED_DEAD;
+        cred->pc_flags &= ~PTLRPC_CRED_UPTODATE;
+        CWARN("cred %p: get expired\n", cred);
 }
-static inline int ptlrpcs_cred_is_dead(struct ptlrpc_cred *cred)
+
+/* usually called upon an UPTODATE cred */
+static inline int ptlrpcs_cred_check_expire(struct ptlrpc_cred *cred)
 {
-        return(cred->pc_flags & PTLRPC_CRED_DEAD);
+        LASSERT(atomic_read(&cred->pc_refcount));
+        if (cred->pc_expire == 0)
+                return 0;
+        if (time_after(cred->pc_expire, get_seconds()))
+                return 0;
+        ptlrpcs_cred_expire(cred);
+        return 1;
 }
 
 static inline int ptlrpcs_est_req_payload(struct ptlrpc_sec *sec,
@@ -338,6 +350,7 @@ int  ptlrpcs_req_get_cred(struct ptlrpc_request *req);
 void ptlrpcs_req_drop_cred(struct ptlrpc_request *req);
 int  ptlrpcs_req_replace_dead_cred(struct ptlrpc_request *req);
 int  ptlrpcs_req_refresh_cred(struct ptlrpc_request *req);
+int ptlrpcs_check_cred(struct obd_import *imp);
 
 /* internal helpers */
 int sec_alloc_reqbuf(struct ptlrpc_sec *sec, struct ptlrpc_request *req,
index 63cf931..feab216 100644 (file)
@@ -53,6 +53,7 @@ struct sm_operations {
         struct inode_operations sm_dir_iops;
         struct inode_operations sm_file_iops;
         struct inode_operations sm_sym_iops;
+        struct inode_operations sm_special_iops;
         struct file_operations sm_dir_fops;
         struct file_operations sm_file_fops;
         struct file_operations sm_sym_fops;
index 826d798..b5b96e3 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/lustre_mds.h>
 #include <linux/lustre_lite.h>
 #include <linux/lustre_dlm.h>
+#include <linux/lustre_sec.h>
 #include "llite_internal.h"
 
 typedef struct ext2_dir_entry_2 ext2_dirent;
@@ -250,6 +251,12 @@ static struct page *ll_get_dir_page(struct inode *dir, unsigned long n)
                         CERROR("lock enqueue: rc: %d\n", rc);
                         return ERR_PTR(rc);
                 }
+        } else {
+                if (ptlrpcs_check_cred(obddev->u.cli.cl_import)) {
+                        /* return immediately if no credential held */
+                        ldlm_lock_decref(&lockh, LCK_PR);
+                        return ERR_PTR(-EACCES);
+                }
         }
         ldlm_lock_dump_handle(D_OTHER, &lockh);
 
index f0987fc..91101fd 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/obd_class.h>
 #include <linux/lustre_mds.h>
 #include <linux/lustre_dlm.h>
+#include <linux/lustre_sec.h>
 #include <linux/lprocfs_status.h>
 #include <linux/lustre_acl.h>
 #include <linux/lustre_lite.h>
@@ -526,6 +527,11 @@ int mdc_intent_lock(struct obd_export *exp, struct lustre_id *pid,
                                              &lockh);
                 }
                 if (rc) {
+                        if (ptlrpcs_check_cred(exp->exp_obd->u.cli.cl_import)) {
+                                /* return immediately if no credential held */
+                                ldlm_lock_decref(&lockh, mode);
+                                RETURN(-EACCES);
+                        }
                         memcpy(&LUSTRE_IT(it)->it_lock_handle, &lockh,
                                sizeof(lockh));
                         LUSTRE_IT(it)->it_lock_mode = mode;
index f900f5c..a2deb85 100644 (file)
@@ -2424,6 +2424,12 @@ static int osc_enqueue(struct obd_export *exp, struct lov_stripe_md *lsm,
         rc = ldlm_lock_match(obd->obd_namespace, 0, &res_id, type, policy, mode,
                              lockh);
         if (rc == 1) {
+                if (ptlrpcs_check_cred(obd->u.cli.cl_import)) {
+                        /* return immediately if no credential held */
+                        ldlm_lock_decref(lockh, mode);
+                        RETURN(-EACCES);
+                }
+
                 osc_set_data_with_check(lockh, data);
                 if (*flags & LDLM_FL_HAS_INTENT) {
                         /* I would like to be able to ASSERT here that rss <=
@@ -2450,6 +2456,12 @@ static int osc_enqueue(struct obd_export *exp, struct lov_stripe_md *lsm,
                 rc = ldlm_lock_match(obd->obd_namespace, 0, &res_id, type,
                                      policy, LCK_PW, lockh);
                 if (rc == 1) {
+                        if (ptlrpcs_check_cred(obd->u.cli.cl_import)) {
+                                /* return immediately if no credential held */
+                                ldlm_lock_decref(lockh, LCK_PW);
+                                RETURN(-EACCES);
+                        }
+
                         /* FIXME: This is not incredibly elegant, but it might
                          * be more elegant than adding another parameter to
                          * lock_match.  I want a second opinion. */
index 13293db..96d93d0 100644 (file)
@@ -833,7 +833,8 @@ waiting:
                 goto out;
 
         if (signal_pending(current)) {
-                CERROR("cred %p: interrupted upcall\n", cred);
+                CERROR("%s: cred %p: interrupted upcall\n",
+                       current->comm, cred);
                 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
                 res = -EINTR;
         } else if (res == 0) {
@@ -991,7 +992,8 @@ static int gss_cred_sign(struct ptlrpc_cred *cred,
                req->rq_reqbuf, lmsg.data, lmsg.len, mic.data, mic.len);
         major = kgss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, &lmsg, &mic);
         if (major) {
-                CERROR("gss compute mic error, major %x\n", major);
+                CERROR("cred %p: req %p compute mic error, major %x\n",
+                       cred, req, major);
                 rc = -EACCES;
                 goto out;
         }
@@ -1068,8 +1070,18 @@ static int gss_cred_verify(struct ptlrpc_cred *cred,
 
                 major = kgss_verify_mic(ctx->gc_gss_ctx, &lmsg, &mic, NULL);
                 if (major != GSS_S_COMPLETE) {
-                        CERROR("gss verify mic error: major %x\n", major);
-                        GOTO(proc_data_out, rc = -EINVAL);
+                        CERROR("cred %p: req %p verify mic error: major %x\n",
+                               cred, req, major);
+
+                        if (major == GSS_S_CREDENTIALS_EXPIRED ||
+                            major == GSS_S_CONTEXT_EXPIRED) {
+                                ptlrpcs_cred_expire(cred);
+                                req->rq_ptlrpcs_restart = 1;
+                                rc = 0;
+                        } else
+                                rc = -EINVAL;
+
+                        GOTO(proc_data_out, rc);
                 }
 
                 req->rq_repmsg = (struct lustre_msg *) lmsg.data;
@@ -1102,12 +1114,9 @@ proc_data_out:
                                req, cred, (major == GSS_S_NO_CONTEXT) ?
                                            "NO_CONTEXT" : "BAD_SIG");
 
-                        ptlrpcs_cred_die(cred);
-                        rc = ptlrpcs_req_replace_dead_cred(req);
-                        if (!rc)
-                                req->rq_ptlrpcs_restart = 1;
-                        else
-                                CERROR("replace dead cred failed %d\n", rc);
+                        ptlrpcs_cred_expire(cred);
+                        req->rq_ptlrpcs_restart = 1;
+                        rc = 0;
                 } else {
                         CERROR("req %p: unrecognized gss error (%x/%x)\n",
                                 req, major, minor);
@@ -1177,7 +1186,8 @@ static int gss_cred_seal(struct ptlrpc_cred *cred,
         vlen -= 4;
 
         msg_buf.buf = (__u8 *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
-        msg_buf.buflen = req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN + GSS_PRIVBUF_SUFFIX_LEN;
+        msg_buf.buflen = req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
+                                          GSS_PRIVBUF_SUFFIX_LEN;
         msg_buf.dataoff = GSS_PRIVBUF_PREFIX_LEN;
         msg_buf.datalen = req->rq_reqlen;
 
@@ -1187,7 +1197,7 @@ static int gss_cred_seal(struct ptlrpc_cred *cred,
         major = kgss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
                           &msg_buf, &cipher_buf);
         if (major) {
-                CERROR("error wrap: major 0x%x\n", major);
+                CERROR("cred %p: error wrap: major 0x%x\n", cred, major);
                 GOTO(out, rc = -EINVAL);
         }
 
@@ -1213,7 +1223,7 @@ static int gss_cred_unseal(struct ptlrpc_cred *cred,
         struct ptlrpcs_wire_hdr *sec_hdr;
         rawobj_t                cipher_text, plain_text;
         __u32                   *vp, vlen, subflavor, proc, seq, svc;
-        int                     rc;
+        __u32                   major, rc;
         ENTRY;
 
         LASSERT(req->rq_repbuf);
@@ -1271,11 +1281,21 @@ static int gss_cred_unseal(struct ptlrpc_cred *cred,
                 ctx = gss_cred_get_ctx(cred);
                 LASSERT(ctx);
 
-                rc = kgss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
-                                 &cipher_text, &plain_text);
-                if (rc) {
-                        CERROR("error unwrap: 0x%x\n", rc);
-                        GOTO(proc_out, rc = -EINVAL);
+                major = kgss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
+                                    &cipher_text, &plain_text);
+                if (major) {
+                        CERROR("cred %p: error unwrap: major 0x%x\n",
+                               cred, major);
+
+                        if (major == GSS_S_CREDENTIALS_EXPIRED ||
+                            major == GSS_S_CONTEXT_EXPIRED) {
+                                ptlrpcs_cred_expire(cred);
+                                req->rq_ptlrpcs_restart = 1;
+                                rc = 0;
+                        } else
+                                rc = -EINVAL;
+
+                        GOTO(proc_out, rc);
                 }
 
                 req->rq_repmsg = (struct lustre_msg *) vp;
index e249b84..08c66d2 100644 (file)
@@ -164,14 +164,24 @@ int ptlrpcs_cred_unlink_expired(struct ptlrpc_cred *cred,
 {
         LASSERT(cred->pc_sec);
 
+        /* only unlink non-busy entries */
         if (atomic_read(&cred->pc_refcount) != 0)
                 return 0;
+        /* expire is 0 means never expire. a newly created gss cred
+         * which during upcall also has 0 expiration
+         */
+        if (cred->pc_expire == 0)
+                return 0;
+        /* check real expiration */
         if (time_after(cred->pc_expire, get_seconds()))
                 return 0;
 
+        LASSERT((cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) ==
+                PTLRPC_CRED_UPTODATE);
+        CWARN("cred %p: get expired, unlink\n", cred);
+
         list_del(&cred->pc_hash);
         list_add(&cred->pc_hash, freelist);
-        CDEBUG(D_SEC, "put cred %p into freelist\n", cred);
         return 1;
 }
 
@@ -187,6 +197,11 @@ void ptlrpcs_credcache_gc(struct ptlrpc_sec *sec,
         for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
                 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
                                          pc_hash) {
+                        if (cred->pc_flags & (PTLRPC_CRED_DEAD |
+                                              PTLRPC_CRED_ERROR)) {
+                                LASSERT(atomic_read(&cred->pc_refcount));
+                                continue;
+                        }
                         ptlrpcs_cred_unlink_expired(cred, freelist);
                 }
         }
@@ -254,8 +269,13 @@ retry:
                 ptlrpcs_credcache_gc(sec, &freelist);
 
         list_for_each_entry_safe(cred, n, &sec->ps_credcache[hash], pc_hash) {
-                if (cred->pc_flags & PTLRPC_CRED_DEAD)
+                /* for DEAD and ERROR entries, its final put will
+                 * release them, so we simply skip here.
+                 */
+                if (cred->pc_flags & (PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR)) {
+                        LASSERT(atomic_read(&cred->pc_refcount));
                         continue;
+                }
                 if (ptlrpcs_cred_unlink_expired(cred, &freelist))
                         continue;
                 if (cred->pc_ops->match(cred, vcred)) {
@@ -305,23 +325,29 @@ struct ptlrpc_cred * ptlrpcs_cred_lookup(struct ptlrpc_sec *sec,
         RETURN(cred);
 }
 
-int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
+static struct ptlrpc_cred *get_cred(struct ptlrpc_sec *sec)
 {
-        struct obd_import *imp = req->rq_import;
         struct vfs_cred vcred;
-        ENTRY;
-
-        LASSERT(!req->rq_cred);
-        LASSERT(imp);
-        LASSERT(imp->imp_sec);
 
+        LASSERT(sec);
         /* XXX
          * for now we simply let PAG == real uid
          */
         vcred.vc_pag = (__u64) current->uid;
         vcred.vc_uid = current->uid;
 
-        req->rq_cred = cred_cache_lookup(imp->imp_sec, &vcred, 1);
+        return cred_cache_lookup(sec, &vcred, 1);
+}
+
+int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
+{
+        struct obd_import *imp = req->rq_import;
+        ENTRY;
+
+        LASSERT(!req->rq_cred);
+        LASSERT(imp);
+
+        req->rq_cred = get_cred(imp->imp_sec);
 
         if (!req->rq_cred) {
                 CERROR("req %p: fail to get cred from cache\n", req);
@@ -331,6 +357,52 @@ int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
         RETURN(0);
 }
 
+/*
+ * check whether current user have valid credential for an import or not.
+ * might repeatedly try in case of non-fatal errors.
+ * return 0 on success, 1 on failure
+ */
+int ptlrpcs_check_cred(struct obd_import *imp)
+{
+        struct ptlrpc_cred *cred;
+        ENTRY;
+
+again:
+        cred = get_cred(imp->imp_sec);
+        if (!cred)
+                RETURN(0);
+
+        if (ptlrpcs_cred_is_uptodate(cred)) {
+                if (!ptlrpcs_cred_check_expire(cred)) {
+                        ptlrpcs_cred_put(cred, 1);
+                        RETURN(0);
+                } else {
+                        ptlrpcs_cred_put(cred, 1);
+                        goto again;
+                }
+        }
+
+        ptlrpcs_cred_refresh(cred);
+        if (ptlrpcs_cred_is_uptodate(cred)) {
+                ptlrpcs_cred_put(cred, 1);
+                RETURN(0);
+        }
+
+        if (cred->pc_flags & PTLRPC_CRED_ERROR ||
+            !imp->imp_replayable) {
+                ptlrpcs_cred_put(cred, 1);
+                RETURN(1);
+        }
+
+        ptlrpcs_cred_put(cred, 1);
+
+        if (signal_pending(current)) {
+                CWARN("%s: interrupted\n", current->comm);
+                RETURN(1);
+        }
+        goto again;
+}
+
 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec);
 
 void ptlrpcs_cred_put(struct ptlrpc_cred *cred, int sync)
@@ -342,8 +414,8 @@ void ptlrpcs_cred_put(struct ptlrpc_cred *cred, int sync)
         LASSERT(atomic_read(&cred->pc_refcount));
 
         spin_lock(&sec->ps_lock);
-        if (atomic_dec_and_test(&cred->pc_refcount) &&
-            sync && cred->pc_flags & PTLRPC_CRED_DEAD) {
+        if (atomic_dec_and_test(&cred->pc_refcount) && sync &&
+            cred->pc_flags & (PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR)) {
                 list_del_init(&cred->pc_hash);
                 ptlrpcs_cred_destroy(cred);
                 if (!atomic_read(&sec->ps_credcount) &&
@@ -417,8 +489,10 @@ int ptlrpcs_req_refresh_cred(struct ptlrpc_request *req)
 
         LASSERT(cred);
 
-        if (ptlrpcs_cred_is_uptodate(cred))
-                RETURN(0);
+        if (ptlrpcs_cred_is_uptodate(cred)) {
+                if (!ptlrpcs_cred_check_expire(cred))
+                        RETURN(0);
+        }
 
         if (cred->pc_flags & PTLRPC_CRED_ERROR) {
                 req->rq_ptlrpcs_err = 1;
@@ -435,6 +509,7 @@ int ptlrpcs_req_refresh_cred(struct ptlrpc_request *req)
                         LASSERT(cred == req->rq_cred);
                         CERROR("req %p: failed to replace dead cred %p\n",
                                 req, cred);
+                        req->rq_ptlrpcs_err = 1;
                         RETURN(-ENOMEM);
                 }
         }
@@ -911,6 +986,7 @@ EXPORT_SYMBOL(ptlrpcs_req_get_cred);
 EXPORT_SYMBOL(ptlrpcs_req_drop_cred);
 EXPORT_SYMBOL(ptlrpcs_req_replace_dead_cred);
 EXPORT_SYMBOL(ptlrpcs_req_refresh_cred);
+EXPORT_SYMBOL(ptlrpcs_check_cred);
 EXPORT_SYMBOL(ptlrpcs_cli_alloc_reqbuf);
 EXPORT_SYMBOL(ptlrpcs_cli_free_reqbuf);
 EXPORT_SYMBOL(ptlrpcs_cli_alloc_repbuf);
index 7275899..80c6b5d 100644 (file)
@@ -193,6 +193,18 @@ static void setup_sm_symlink_ops(struct inode *inode)
         unlock_kernel();
 }
 
+static void setup_sm_special_ops(struct inode *inode)
+{
+        struct smfs_super_info *smb = S2SMI(inode->i_sb);
+        struct inode *cache_inode = I2CI(inode);
+        
+        setup_iops(cache_inode, &smfs_special_iops, &smb->sm_ops->sm_special_iops);
+
+        lock_kernel();
+        smb->smsi_ops_check |= SPECIAL_OPS_CHECK;
+        unlock_kernel();
+}
+
 #define SMFS_IOPEN_INO  1
 
 void sm_set_inode_ops(struct inode *inode)
@@ -223,6 +235,10 @@ void sm_set_inode_ops(struct inode *inode)
                         setup_sm_symlink_ops(inode);
                 inode->i_op = &smb->sm_ops->sm_sym_iops;
                 inode->i_fop =  &smb->sm_ops->sm_sym_fops;
+        } else {
+                if (!(smb->smsi_ops_check & SPECIAL_OPS_CHECK))
+                        setup_sm_special_ops(inode);
+                inode->i_op = &smb->sm_ops->sm_special_iops;
         }
 }
 
index cc3ae29..fe17f3a 100644 (file)
@@ -769,26 +769,27 @@ exit:
 }
 
 struct inode_operations smfs_dir_iops = {
-        create:         smfs_create,
-        lookup:         smfs_lookup,
+        .create         = smfs_create,
+        .lookup         = smfs_lookup,
 #if HAVE_LOOKUP_RAW
-        lookup_raw:     smfs_lookup_raw,
+        .lookup_raw     = smfs_lookup_raw,
 #endif
-        link:           smfs_link,              /* BKL held */
-        unlink:         smfs_unlink,            /* BKL held */
-        symlink:        smfs_symlink,           /* BKL held */
-        mkdir:          smfs_mkdir,             /* BKL held */
-        rmdir:          smfs_rmdir,             /* BKL held */
-        mknod:          smfs_mknod,             /* BKL held */
-        rename:         smfs_rename,            /* BKL held */
-        setxattr:       smfs_setxattr,          /* BKL held */
-        getxattr:       smfs_getxattr,          /* BKL held */
-        listxattr:      smfs_listxattr,         /* BKL held */
-        removexattr:    smfs_removexattr,       /* BKL held */
+        .link           = smfs_link,              /* BKL held */
+        .unlink         = smfs_unlink,            /* BKL held */
+        .symlink        = smfs_symlink,           /* BKL held */
+        .mkdir          = smfs_mkdir,             /* BKL held */
+        .rmdir          = smfs_rmdir,             /* BKL held */
+        .mknod          = smfs_mknod,             /* BKL held */
+        .rename         = smfs_rename,            /* BKL held */
+        .setxattr       = smfs_setxattr,
+        .getxattr       = smfs_getxattr,
+        .listxattr      = smfs_listxattr,
+        .removexattr    = smfs_removexattr,
+        .permission     = smfs_permission,
 };
 
 struct inode_operations smfs_iopen_iops = {
-        lookup:         smfs_iopen_lookup,
+        .lookup         = smfs_iopen_lookup,
 };
 
 static ssize_t smfs_read_dir(struct file *filp, char *buf,
index c0d8842..88e3931 100644 (file)
@@ -531,12 +531,41 @@ int smfs_removexattr(struct dentry *dentry, const char *name)
         RETURN(rc);
 }
 
+int smfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+        struct inode *cache_inode = I2CI(inode);
+        int rc = 0;
+
+        ENTRY;
+        
+        LASSERT(cache_inode);
+        LASSERT(cache_inode->i_op->permission);
+
+        pre_smfs_inode(inode, cache_inode);
+
+        rc = cache_inode->i_op->permission(cache_inode, mask, nd);
+
+        post_smfs_inode(inode, cache_inode);
+
+        RETURN(rc);
+}
+
 struct inode_operations smfs_file_iops = {
         .truncate       = smfs_truncate,          /* BKL held */
         .setattr        = smfs_setattr,           /* BKL held */
-        .setxattr       = smfs_setxattr,          /* BKL held */
-        .getxattr       = smfs_getxattr,          /* BKL held */
-        .listxattr      = smfs_listxattr,         /* BKL held */
-        .removexattr    = smfs_removexattr,       /* BKL held */
+        .setxattr       = smfs_setxattr,
+        .getxattr       = smfs_getxattr,
+        .listxattr      = smfs_listxattr,
+        .removexattr    = smfs_removexattr,
+        .permission     = smfs_permission,
+};
+
+struct inode_operations smfs_special_iops = {
+        .setattr        = smfs_setattr,           /* BKL held */
+        .setxattr       = smfs_setxattr,
+        .getxattr       = smfs_getxattr,
+        .listxattr      = smfs_listxattr,
+        .removexattr    = smfs_removexattr,
+        .permission     = smfs_permission,
 };
 
index ec7fab5..e507032 100644 (file)
@@ -55,7 +55,7 @@ struct smfs_control_device {
 #define INODE_OPS_CHECK          0x2
 #define FILE_OPS_CHECK           0x4
 #define DENTRY_OPS_CHECK         0x8
-#define DEV_OPS_CHECK            0x10
+#define SPECIAL_OPS_CHECK        0x10
 #define SYMLINK_OPS_CHECK        0x20
 #define DIR_OPS_CHECK            0x40
 
@@ -98,6 +98,7 @@ extern struct file_operations smfs_iopen_fops;
 /*file.c*/
 extern struct inode_operations smfs_file_iops;
 extern struct file_operations  smfs_file_fops;
+extern struct inode_operations smfs_special_iops;
 extern int smfs_ioctl(struct inode * inode, struct file * filp,
                       unsigned int cmd, unsigned long arg);
 extern int smfs_fsync(struct file * file, struct dentry *dentry, int datasync);
@@ -108,6 +109,7 @@ extern int smfs_getxattr(struct dentry *dentry, const char *name, void *buffer,
                          size_t size);
 extern ssize_t smfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 extern int smfs_removexattr(struct dentry *dentry, const char *name);
+extern int smfs_permission(struct inode *inode, int mask, struct nameidata *nd);
 extern int smfs_open(struct inode * inode, struct file * filp);
 extern int smfs_release(struct inode * inode, struct file * filp);
 /*inode.c*/
index 619b7b7..879afc6 100644 (file)
@@ -78,10 +78,11 @@ static int smfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 struct inode_operations smfs_sym_iops = {
         .readlink        = smfs_readlink,
         .follow_link     = smfs_follow_link,
-        .setxattr        = smfs_setxattr,          /* BKL held */
-        .getxattr        = smfs_getxattr,          /* BKL held */
-        .listxattr       = smfs_listxattr,         /* BKL held */
-        .removexattr     = smfs_removexattr,       /* BKL held */
+        .setxattr        = smfs_setxattr,
+        .getxattr        = smfs_getxattr,
+        .listxattr       = smfs_listxattr,
+        .removexattr     = smfs_removexattr,
+        .permission      = smfs_permission,
 };
 
 struct file_operations smfs_sym_fops = {
diff --git a/lustre/tests/acl/inheritance.test b/lustre/tests/acl/inheritance.test
new file mode 100644 (file)
index 0000000..bef89b7
--- /dev/null
@@ -0,0 +1,129 @@
+ACL inheritance test.  Run these tests on a filesystem with ACL support.
+
+       $ id -u
+        > 0
+
+       $ mkdir d
+        $ setfacl -d -m group:bin:r-x d
+        $ getfacl d
+       > # file: d
+       > # owner: root
+       > # group: root
+       > user::rwx
+       > group::r-x
+       > other::r-x
+       > default:user::rwx
+       > default:group::r-x
+       > default:group:bin:r-x
+       > default:mask::r-x
+       > default:other::r-x
+        >
+
+       $ mkdir d/subdir
+        $ getfacl d/subdir
+       > # file: d/subdir
+       > # owner: root
+       > # group: root
+       > user::rwx
+       > group::r-x
+       > group:bin:r-x
+       > mask::r-x
+       > other::r-x
+       > default:user::rwx
+       > default:group::r-x
+       > default:group:bin:r-x
+       > default:mask::r-x
+       > default:other::r-x
+       >
+
+        $ touch d/f
+        $ ls -l d/f | awk -- '{ print $1 }'
+        > -rw-r--r--+
+       $ getfacl d/f
+       > # file: d/f
+       > # owner: root
+       > # group: root
+       > user::rw-
+       > group::r-x    #effective:r--
+       > group:bin:r-x #effective:r--
+       > mask::r--
+       > other::r--
+       >
+
+        $ su bin
+        $ echo i >> d/f
+       > d/f: Permission denied
+
+Changed by CFS: (1). reduce the tree level to 2 (for shortening
+time of local tests). (2). add one more getfacl test since dir
+might be distributed around MDS's.
+
+        $ su
+        $ rm d/f
+        $ rmdir d/subdir
+        $ mv d tree 
+        $ ./make-tree
+        $ getfacl tree/dir0/dir5/file4 
+       > # file: tree/dir0/dir5/file4
+       > # owner: root
+       > # group: root
+       > user::rw-
+       > group::r-x    #effective:r--
+       > group:bin:r-x #effective:r--
+       > mask::r--
+       > other::r--
+       >
+        $ getfacl tree/dir0/dir6/file4 
+       > # file: tree/dir0/dir6/file4
+       > # owner: root
+       > # group: root
+       > user::rw-
+       > group::r-x    #effective:r--
+       > group:bin:r-x #effective:r--
+       > mask::r--
+       > other::r--
+       >
+       $ echo i >> tree/dir6/dir2/file2
+       $ echo i > tree/dir1/f
+       $ ls -l tree/dir1/f | awk -- '{ print $1 }'
+       > -rw-r--r--+
+       $ su bin
+       $ echo i > tree/dir6/dir2/f
+       > tree/dir6/dir2/f: No such file or directory
+       $ su
+
+        $ rm -rf tree
+
+
+Original scripts, comment out by CFS.
+#
+#        $ su
+#        $ rm d/f
+#        $ rmdir d/subdir
+#        $ mv d tree 
+#        $ ./make-tree
+#        $ getfacl tree/dir0/dir5/dir7/file4 
+#      > # file: tree/dir0/dir5/dir7/file4
+#      > # owner: root
+#      > # group: root
+#      > user::rw-
+#      > group::r-x    #effective:r--
+#      > group:bin:r-x #effective:r--
+#      > mask::r--
+#      > other::r--
+#      >
+#      $ echo i >> tree/dir6/dir2/dir1/file2
+#      $ echo i > tree/dir1/f
+#      $ ls -l tree/dir1/f | awk -- '{ print $1 }'
+#      > -rw-r--r--+
+#      $ su bin
+#      $ echo i > tree/dir6/dir2/f
+#      > tree/dir6/dir2/f: No such file or directory
+#      $ su
+#
+#        $ rm -rf tree
+
+
+
diff --git a/lustre/tests/acl/make-tree b/lustre/tests/acl/make-tree
new file mode 100755 (executable)
index 0000000..c27dde8
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# reduce LEVELS from 3 => 2 by CFS
+LEVELS=2 ;             [ -z "$1" ] || LEVELS=$1
+DIRS=10 ;              [ -z "$2" ] || DIRS=$2
+FILES=10 ;             [ -z "$2" ] || FILES=$3
+NUMBER_OF_ACLS=50 ;    [ -z "$3" ] || NUMBER_OF_ACLS=$4
+
+function random_dir() {
+       mkdir -p $1
+       #setfacl -s "u::rwx,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rwx,g::rx,o:-" $1
+}
+
+function random_file() {
+       touch $1
+       #setfacl -s "u::rw,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rw,g::r,o:-" $1
+}
+
+function create () {
+       local LEVEL=$1
+       if [ $LEVEL -eq 0 ]; then
+               local I=0
+               while [ $I -lt $FILES ]; do
+                       random_file file$I
+                       I=$[$I+1]
+               done
+       else
+               local I=0
+               while [ $I -lt $DIRS ]; do
+                       random_dir dir$I
+                       cd dir$I
+                       create $[$LEVEL-1]
+                       cd ..
+                       I=$[$I+1]
+               done
+       fi
+       return
+}
+
+mkdir -p tree
+cd tree
+create $LEVELS
+cd ..
+exit 0
+
index 17f696e..bcf947c 100644 (file)
@@ -200,8 +200,10 @@ only need to verify that ACL permissions make a difference.
        $ su bin
        $ echo e/*
        > e/h
-       $ echo i > e/i
-       > e/i: Permission denied
+following 2 lines seems not valid, which also failed on ext3 in FC3 enviroment,
+although it pass in FC2. commented out by CFS (agreed with HP)
+#      $ echo i > e/i
+#      > e/i: Permission denied
 
        $ su
        $ setfacl -m u:bin:rwx e
index a0e863c..99237a9 100644 (file)
@@ -18,6 +18,7 @@ export SECURITY=${SECURITY:-"null"}
 
 TMP=${TMP:-/tmp}
 FSTYPE=${FSTYPE:-ext3}
+NETTYPE=${NETTYPE:-tcp}
 
 CHECKSTAT=${CHECKSTAT:-"checkstat -v"}
 CREATETEST=${CREATETEST:-createtest}
@@ -36,22 +37,13 @@ SOCKETSERVER=${SOCKETSERVER:-socketserver}
 SOCKETCLIENT=${SOCKETCLIENT:-socketclient}
 IOPENTEST1=${IOPENTEST1:-iopentest1}
 IOPENTEST2=${IOPENTEST2:-iopentest2}
+RUNAS=${RUNAS:-"runas"}
 
 . krb5_env.sh
 
 if [ $UID -ne 0 ]; then
-       RUNAS_ID="$UID"
-       RUNAS=""
-else
-       RUNAS_ID=${RUNAS_ID:-500}
-       RUNAS=${RUNAS:-"runas -u $RUNAS_ID"}
-fi
-
-if [ `using_krb5_sec $SECURITY` == 'y' ] ; then
-    start_krb5_kdc || exit 1
-    if [ $RUNAS_ID -ne $UID ]; then
-        $RUNAS ./krb5_refresh_cache.sh || exit 2
-    fi
+    echo "Must be run as root"
+    exit 1
 fi
 
 export NAME=${NAME:-local}
@@ -209,8 +201,8 @@ EOF
 
 mynidstr(){
         lctl << EOF
-        network tcp
-        mynid
+        network $NETTYPE
+        shownid
         quit
 EOF
 }
@@ -218,7 +210,7 @@ EOF
 test_1(){
         mdsnum=`mdsdevice|awk ' $3=="mds" {print $1}'`
        if [ ! -z "$mdsnum" ];then
-        mynid=`mynidstr|awk '{print $4}'`
+        mynid=`mynidstr`
         mkdir $DIR/test_0a_dir1
         touch $DIR/test_0a_file1
         ln -s $DIR/test_0a_file1 $DIR/test_0a_filelink1
@@ -307,17 +299,30 @@ run_acl_subtest()
 }
 
 test_3 () {
-        SAVE_UMASK=`umask`
-        cd $DIR
+    # acl tests are using user "bin" and "daemon", which uid are 1 and 2
+    # in most distributions
+    if [ `using_krb5_sec $SECURITY` == 'y' ] ; then
+        $RUNAS -u 1 ./krb5_refresh_cache.sh || exit 20
+        $RUNAS -u 2 ./krb5_refresh_cache.sh || exit 21
+    fi
+
+    SAVE_UMASK=`umask`
+    cd $DIR
+
+    run_acl_subtest cp || return 1
+    run_acl_subtest getfacl-noacl || return 2
+    run_acl_subtest misc || return 3
+    run_acl_subtest permissions || return 4
+    run_acl_subtest setfacl || return 5
 
-        run_acl_subtest cp || return 1
-        run_acl_subtest getfacl-noacl || return 2
-        run_acl_subtest misc || return 3
-        run_acl_subtest permissions || return 4
-        run_acl_subtest setfacl || return 5
+    # inheritance test got from HP
+    cp $SAVE_PWD/acl/make-tree . || return 6
+    chmod +x make-tree || return 7
+    run_acl_subtest inheritance || return 8
+    rm -f make-tree
 
-        cd $SAVED_PWD
-        umask $SAVE_UMASK
+    cd $SAVED_PWD
+    umask $SAVE_UMASK
 }
 run_test 3 "==============acl test ============="