Patchwork [BRANCH:release-3.1,BUG:2886] Access-Control : Sticky bit validation for rename, unlink and rmdir.

login
register
Submitter Gaurav
Date 2011-05-10 04:53:21
Message ID <1305003201-2640-1-git-send-email-gaurav@gluster.com>
Download mbox | patch
Permalink /patch/7165/
State Accepted
Headers show

Comments

Gaurav - 2011-05-10 04:53:21
From: Gaurav <gaurav@gluster.com>


Signed-off-by: Gaurav <gaurav@gluster.com>
---
 .../features/access-control/src/access-control.c   |  220 ++++++++++++++++++--
 1 files changed, 197 insertions(+), 23 deletions(-)

Patch

diff --git a/xlators/features/access-control/src/access-control.c b/xlators/features/access-control/src/access-control.c
index a4b4015..dc02b16 100644
--- a/xlators/features/access-control/src/access-control.c
+++ b/xlators/features/access-control/src/access-control.c
@@ -753,10 +753,8 @@  ac_unlink_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         if (op_ret == -1)
                 goto out;
 
-        op_ret = ac_test_access (buf, frame->root->uid, frame->root->gid,
-                                 frame->root->groups, frame->root->ngrps,
-                                 ACCTEST_WRITE, ACCTEST_ANY, &op_errno);
-        if (op_ret == -1) {
+        if (frame->root->uid != buf->ia_uid) {
+                op_ret = -1;
                 op_errno = EACCES;
                 goto out;
         }
@@ -772,6 +770,48 @@  out:
         return 0;
 }
 
+int32_t
+ac_unlink_parent_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+                    int32_t op_ret, int32_t op_errno, struct iatt *buf)
+{
+        call_stub_t     *stub = NULL;
+
+        stub = frame->local;
+        if (op_ret == -1)
+                goto out;
+
+        if (buf->ia_prot.sticky == 0) {
+                op_ret = ac_test_access (buf, frame->root->uid, frame->root->gid,
+                                         frame->root->groups, frame->root->ngrps,
+                                         ACCTEST_WRITE, ACCTEST_ANY, &op_errno);
+                if (op_ret == -1) {
+                        op_errno = EACCES;
+                        goto out;
+                }
+        } else {
+                if ((frame->root->uid == 0) ||
+                    (frame->root->uid == buf->ia_uid))
+                        goto access;
+
+                STACK_WIND (frame, ac_unlink_stat_cbk, FIRST_CHILD (this),
+                            FIRST_CHILD (this)->fops->stat, &stub->args.unlink.loc);
+                goto out;
+        }
+
+access:
+        stub = __get_frame_stub (frame);
+        call_resume (stub);
+out:
+        if (op_ret < 0) {
+                stub = __get_frame_stub (frame);
+                STACK_UNWIND_STRICT (unlink, frame, -1, op_errno, NULL, NULL);
+                if (stub)
+                        call_stub_destroy (stub);
+        }
+
+        return 0;
+}
+
 
 int32_t
 ac_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc)
@@ -797,7 +837,7 @@  ac_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc)
         if (ret < 0)
                 goto out;
 
-        STACK_WIND (frame, ac_unlink_stat_cbk, FIRST_CHILD (this),
+        STACK_WIND (frame, ac_unlink_parent_stat_cbk, FIRST_CHILD (this),
                     FIRST_CHILD (this)->fops->stat, &parentloc);
         loc_wipe (&parentloc);
         ret = 0;
@@ -834,10 +874,8 @@  ac_rmdir_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         if (op_ret == -1)
                 goto out;
 
-        op_ret = ac_test_access (buf, frame->root->uid, frame->root->gid,
-                                 frame->root->groups, frame->root->ngrps,
-                                 ACCTEST_WRITE, ACCTEST_ANY, &op_errno);
-        if (op_ret == -1) {
+        if (frame->root->uid != buf->ia_uid) {
+                op_ret = -1;
                 op_errno = EACCES;
                 goto out;
         }
@@ -853,6 +891,48 @@  out:
         return 0;
 }
 
+int32_t
+ac_rmdir_parent_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+                   int32_t op_ret, int32_t op_errno, struct iatt *buf)
+{
+        call_stub_t     *stub = NULL;
+
+        stub = frame->local;
+        if (op_ret == -1)
+                goto out;
+
+        if (buf->ia_prot.sticky == 0) {
+                op_ret = ac_test_access (buf, frame->root->uid, frame->root->gid,
+                                         frame->root->groups, frame->root->ngrps,
+                                         ACCTEST_WRITE, ACCTEST_ANY, &op_errno);
+                if (op_ret == -1) {
+                        op_errno = EACCES;
+                        goto out;
+                }
+        } else {
+                if ((frame->root->uid == 0) ||
+                    (frame->root->uid == buf->ia_uid))
+                        goto access;
+
+                STACK_WIND (frame, ac_rmdir_stat_cbk, FIRST_CHILD (this),
+                            FIRST_CHILD (this)->fops->stat, &stub->args.rmdir.loc);
+                goto out;
+        }
+
+access:
+        stub = __get_frame_stub (frame);
+        call_resume (stub);
+out:
+        if (op_ret < 0) {
+                stub = __get_frame_stub (frame);
+                STACK_UNWIND_STRICT (rmdir, frame, -1, op_errno, NULL, NULL);
+                if (stub)
+                        call_stub_destroy (stub);
+        }
+
+        return 0;
+}
+
 
 int
 ac_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags)
@@ -878,7 +958,7 @@  ac_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags)
         if (ret < 0)
                 goto out;
 
-        STACK_WIND (frame, ac_rmdir_stat_cbk, FIRST_CHILD (this),
+        STACK_WIND (frame, ac_rmdir_parent_stat_cbk, FIRST_CHILD (this),
                     FIRST_CHILD (this)->fops->stat, &parentloc);
         loc_wipe (&parentloc);
         ret = 0;
@@ -999,21 +1079,66 @@  ac_rename_dst_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         call_stub_t     *stub = NULL;
 
         stub = __get_frame_stub (frame);
+
+        if ((op_ret == -1) && (op_errno == ENOENT))
+                goto access;
+
         if (op_ret == -1)
                 goto out;
 
-        op_ret = ac_test_access (buf, frame->root->uid,
-                                 frame->root->gid, frame->root->groups,
-                                 frame->root->ngrps, ACCTEST_WRITE,
-                                 ACCTEST_ANY, &op_errno);
-        if (op_ret == -1) {
+        if (frame->root->uid == buf->ia_uid)
+                goto access;
+        else {
+                op_ret = -1;
                 op_errno = EACCES;
-               goto out;
+                goto out;
+        }
+access:
+        call_resume (stub);
+out:
+        if (op_ret < 0) {
+                STACK_UNWIND_STRICT (rename, frame, -1, op_errno, NULL, NULL,
+                                     NULL, NULL, NULL);
+                if (stub)
+                        call_stub_destroy (stub);
+        }
+
+        return 0;
+}
+int32_t
+ac_rename_dst_parent_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+                        int32_t op_ret, int32_t op_errno, struct iatt *buf)
+{
+        call_stub_t     *stub = NULL;
+
+        stub = frame->local;
+        if (op_ret == -1)
+                goto out;
+
+        if (buf->ia_prot.sticky == 0) {
+                op_ret = ac_test_access (buf, frame->root->uid,
+                                         frame->root->gid, frame->root->groups,
+                                         frame->root->ngrps, ACCTEST_WRITE,
+                                         ACCTEST_ANY, &op_errno);
+                if (op_ret == -1) {
+                        op_errno = EACCES;
+                        goto out;
+                }
+        } else {
+                if ((frame->root->uid == 0) ||
+                    (frame->root->uid == buf->ia_uid))
+                        goto access;
+                STACK_WIND (frame, ac_rename_dst_stat_cbk, FIRST_CHILD (this),
+                             FIRST_CHILD (this)->fops->stat, &stub->args.rename.new);
+                goto out;
         }
 
+access:
+        stub = __get_frame_stub (frame);
         call_resume (stub);
 out:
         if (op_ret < 0) {
+                stub = __get_frame_stub (frame);
                 STACK_UNWIND_STRICT (rename, frame, -1, op_errno, NULL, NULL,
                                      NULL, NULL, NULL);
                 if (stub)
@@ -1035,11 +1160,8 @@  ac_rename_src_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         if (op_ret == -1)
                 goto out;
 
-        op_ret = ac_test_access (buf, frame->root->uid,
-                                 frame->root->gid, frame->root->groups,
-                                 frame->root->ngrps, ACCTEST_WRITE,
-                                 ACCTEST_ANY, &op_errno);
-        if (op_ret == -1) {
+        if (buf->ia_uid != frame->root->uid) {
+                op_ret = -1;
                 op_errno = EACCES;
                 goto out;
         }
@@ -1050,7 +1172,59 @@  ac_rename_src_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
                 goto out;
         }
 
-        STACK_WIND (frame, ac_rename_dst_stat_cbk, FIRST_CHILD (this),
+        STACK_WIND (frame, ac_rename_dst_parent_stat_cbk, FIRST_CHILD (this),
+                    FIRST_CHILD (this)->fops->stat, &parentloc);
+        loc_wipe (&parentloc);
+
+out:
+        if (op_ret < 0) {
+                /* Erase the stored stub before unwinding. */
+                stub = __get_frame_stub (frame);
+                if (stub)
+                        call_stub_destroy (stub);
+                STACK_UNWIND_STRICT (rename, frame, -1, op_errno, NULL, NULL,
+                                     NULL, NULL, NULL);
+        }
+        return 0;
+}
+
+int32_t
+ac_rename_src_parent_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+                        int32_t op_ret, int32_t op_errno, struct iatt *buf)
+{
+        call_stub_t     *stub = NULL;
+        loc_t           parentloc = {0, };
+
+        stub = frame->local;
+        if (op_ret == -1)
+                goto out;
+
+        if (buf->ia_prot.sticky == 0) {
+                op_ret = ac_test_access (buf, frame->root->uid,
+                                         frame->root->gid, frame->root->groups,
+                                         frame->root->ngrps, ACCTEST_WRITE,
+                                         ACCTEST_ANY, &op_errno);
+                if (op_ret == -1) {
+                        op_errno = EACCES;
+                        goto out;
+                }
+        } else {
+                if ((buf->ia_uid == frame->root->uid) ||
+                    (frame->root->uid ==0))
+                        goto access;
+                STACK_WIND (frame, ac_rename_src_stat_cbk, FIRST_CHILD (this),
+                             FIRST_CHILD (this)->fops->stat, &stub->args.rename.old);
+                goto out;
+        }
+
+access:
+        op_ret = ac_parent_loc_fill (&parentloc, &stub->args.rename.new);
+        if (op_ret < 0) {
+                op_errno = -EFAULT;
+                goto out;
+        }
+
+        STACK_WIND (frame, ac_rename_dst_parent_stat_cbk, FIRST_CHILD (this),
                     FIRST_CHILD (this)->fops->stat, &parentloc);
         loc_wipe (&parentloc);
 
@@ -1092,7 +1266,7 @@  ac_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc)
         if (ret < 0)
                 goto out;
 
-        STACK_WIND (frame, ac_rename_src_stat_cbk, FIRST_CHILD (this),
+        STACK_WIND (frame, ac_rename_src_parent_stat_cbk, FIRST_CHILD (this),
                     FIRST_CHILD (this)->fops->stat, &parentloc);
         loc_wipe (&parentloc);
         ret = 0;