fs: add support for relative ACL changes
authorRainer Strunz <Rainer.Strunz@lrz.de>
Sun, 17 Apr 2011 23:09:33 +0000 (00:09 +0100)
committerJeffrey Altman <jaltman@openafs.org>
Sat, 4 Jun 2011 17:43:29 +0000 (10:43 -0700)
This change permits "fs setacl" to change ACLs in a relative
manner, rather than just setting rights absolutely as it is
done now.

If a single plus (+) or minus (-) character is appended to
the rights' letters argument, the new rights are computed
relatively to the existing ones.

A few examples should make clear that behaviour:

old rights: rights set: new rights:
-----------------------------------------------
rl a+ rla
rlid idwa- rl
rla write- a
rl write- [none] (ie. entry deleted)
[any] read= rl

As shown in the last example, a '=' character got implemented
also (and for free) as an alternative writing of the current
and default behaviour of just setting an ACL.

FIXES 123962

Change-Id: If15a4ab3c69ec44a42c8746a0b93f5e8b785d61e
Reviewed-on: http://gerrit.openafs.org/4496
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>

doc/man-pages/pod1/fs_setacl.pod
src/WINNT/afsd/fs.c
src/venus/fs.c

index cbe0e4d..fea5a5a 100644 (file)
@@ -94,7 +94,9 @@ A user name or group name as listed in the Protection Database.
 =item *
 
 One or more ACL permissions, indicated either by combining the individual
-letters or by one of the four acceptable shorthand words.
+letters or by one of the four acceptable shorthand words, optionally
+followed by a single plus (+) or minus (-) chracter to request a relative
+ACL change
 
 =back
 
@@ -296,6 +298,22 @@ and its F<public> subdirectory).
       pat rlidwka
       pat:friends rli
 
+The following example demonstrates the use of the + and - options to
+modfiy ACLs relative to the existing set
+
+   % fs setacl dir . -acl pat:friends r-
+   % fs listacl -path .
+   Access list for . is
+   Normal rights:
+      pat rlidwka
+      pat:friends li
+   % fs setacl dir . acl pat:friends w+
+   % fs listacl -path .
+   Access list for . is
+   Normal rights:
+      pat rlidwka
+      pat:friends wli
+
 =head1 PRIVILEGE REQUIRED
 
 The issuer must have the C<a> (administer) permission on the directory's
index 9ff557e..9363e6c 100644 (file)
@@ -326,16 +326,33 @@ Parent(char *apath)
     return tspace;
 }
 
-enum rtype {add, destroy, deny};
+                                /* added relative add resp. delete    */
+                                /* (so old add really means to set)   */
+enum rtype { add, destroy, deny, reladd, reldel };
 
 static afs_int32
 Convert(char *arights, int dfs, enum rtype *rtypep)
 {
     afs_int32 mode;
     char tc;
+    char *tcp;
 
     *rtypep = add;     /* add rights, by default */
 
+                                /* analyze last character of string   */
+    tcp = arights + strlen(arights);
+    if ( tcp-- > arights ) {    /* assure non-empty string            */
+        if ( *tcp == '+' )
+            *rtypep = reladd;   /* '+' indicates more rights          */
+        else if ( *tcp == '-' )
+            *rtypep = reldel;   /* '-' indicates less rights          */
+        else if ( *tcp == '=' )
+            *rtypep = add;      /* '=' also allows old behaviour      */
+        else
+            tcp++;              /* back to original null byte         */
+        *tcp = '\0';            /* do not disturb old strcmp-s        */
+    }
+
     if (dfs) {
        if (!strcmp(arights, "null")) {
            *rtypep = deny;
@@ -366,7 +383,8 @@ Convert(char *arights, int dfs, enum rtype *rtypep)
        return 0;
     }
     mode = 0;
-    for(; (tc = *arights) != '\0'; arights++) {
+    tcp = arights;
+    while ((tc = *tcp++)) {
        if (dfs) {
            if (tc == '-')
                 continue;
@@ -478,20 +496,36 @@ SetDotDefault(struct cmd_item **aitemp)
 }
 
 static void
-ChangeList (struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights)
+ChangeList (struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights,
+           enum rtpe *artypep)
 {
     struct AclEntry *tlist;
     tlist = (plus ? al->pluslist : al->minuslist);
     tlist = FindList (tlist, aname);
     if (tlist) {
         /* Found the item already in the list. */
-        tlist->rights = arights;
+                                /* modify rights in case of reladd    */
+                                /* and reladd only, use standard -    */
+                                /* add, ie. set - otherwise           */
+        if ( artypep == NULL )
+            tlist->rights = arights;
+        else if ( *artypep == reladd )
+            tlist->rights |= arights;
+        else if ( *artypep == reldel )
+            tlist->rights &= ~arights;
+        else
+            tlist->rights = arights;
+
         if (plus)
             al->nplus -= PruneList(&al->pluslist, al->dfs);
         else
             al->nminus -= PruneList(&al->minuslist, al->dfs);
         return;
     }
+    if ( artypep != NULL && *artypep == reldel )
+                                /* can't reduce non-existing rights   */
+        return;
+
     /* Otherwise we make a new item and plug in the new data. */
     tlist = (struct AclEntry *) malloc(sizeof (struct AclEntry));
     assert(tlist);
@@ -1094,7 +1128,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
                 plusp = 0;
            if (rtype == destroy && ta->dfs)
                 rights = -1;
-           ChangeList(ta, plusp, ui->data, rights);
+           ChangeList(ta, plusp, ui->data, rights, &rtype);
        }
        blob.in = AclToString(ta);
        blob.out_size=0;
@@ -1239,9 +1273,9 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
            }
        }
        for (tp = fa->pluslist;tp;tp=tp->next)
-           ChangeList(ta, 1, tp->name, tp->rights);
+           ChangeList(ta, 1, tp->name, tp->rights, NULL);
        for (tp = fa->minuslist;tp;tp=tp->next)
-           ChangeList(ta, 0, tp->name, tp->rights);
+           ChangeList(ta, 0, tp->name, tp->rights, NULL);
        blob.in = AclToString(ta);
        blob.out_size=0;
        if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
index 06b3b6d..8cc842f 100644 (file)
@@ -305,17 +305,33 @@ Parent(char *apath)
     return tspace;
 }
 
-enum rtype { add, destroy, deny };
+                                /* added relative add resp. delete    */
+                                /* (so old add really means to set)   */
+enum rtype { add, destroy, deny, reladd, reldel };
 
 static afs_int32
 Convert(char *arights, int dfs, enum rtype *rtypep)
 {
-    int i, len;
     afs_int32 mode;
     char tc;
+    char *tcp;                  /* to walk through the rights string  */
 
     *rtypep = add;             /* add rights, by default */
 
+                                /* analyze last character of string   */
+    tcp = arights + strlen(arights);
+    if ( tcp-- > arights ) {    /* assure non-empty string            */
+        if ( *tcp == '+' )
+            *rtypep = reladd;   /* '+' indicates more rights          */
+        else if ( *tcp == '-' )
+            *rtypep = reldel;   /* '-' indicates less rights          */
+        else if ( *tcp == '=' )
+            *rtypep = add;      /* '=' also allows old behaviour      */
+        else
+            tcp++;              /* back to original null byte         */
+        *tcp = '\0';            /* do not disturb old strcmp-s        */
+    }
+
     if (dfs) {
        if (!strcmp(arights, "null")) {
            *rtypep = deny;
@@ -345,10 +361,9 @@ Convert(char *arights, int dfs, enum rtype *rtypep)
        *rtypep = destroy;      /* Remove entire entry */
        return 0;
     }
-    len = strlen(arights);
     mode = 0;
-    for (i = 0; i < len; i++) {
-       tc = *arights++;
+    tcp = arights;
+    while ((tc = *tcp++ )) {
        if (dfs) {
            if (tc == '-')
                continue;
@@ -455,20 +470,35 @@ SetDotDefault(struct cmd_item **aitemp)
 }
 
 static void
-ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights)
+ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights,
+          enum rtype *artypep)
 {
     struct AclEntry *tlist;
     tlist = (plus ? al->pluslist : al->minuslist);
     tlist = FindList(tlist, aname);
     if (tlist) {
-       /* Found the item already in the list. */
-       tlist->rights = arights;
+       /* Found the item already in the list.
+        * modify rights in case of reladd and reladd only,
+        * use standard - add, ie. set - otherwise
+        */
+        if ( artypep == NULL )
+            tlist->rights = arights;
+        else if ( *artypep == reladd )
+            tlist->rights |= arights;
+        else if ( *artypep == reldel )
+            tlist->rights &= ~arights;
+        else
+            tlist->rights = arights;
+
        if (plus)
            al->nplus -= PruneList(&al->pluslist, al->dfs);
        else
            al->nminus -= PruneList(&al->minuslist, al->dfs);
        return;
     }
+    if ( artypep != NULL && *artypep == reldel )
+        return;                 /* can't reduce non-existing rights   */
+
     /* Otherwise we make a new item and plug in the new data. */
     tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
     assert(tlist);
@@ -821,7 +851,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
                plusp = 0;
            if (rtype == destroy && ta->dfs)
                rights = -1;
-           ChangeList(ta, plusp, ui->data, rights);
+           ChangeList(ta, plusp, ui->data, rights, &rtype);
        }
        blob.in = AclToString(ta);
        blob.out_size = 0;
@@ -948,10 +978,11 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
            }
            strcpy(ta->cell, fa->cell);
        }
+                                /* NULL rtype for standard handling   */
        for (tp = fa->pluslist; tp; tp = tp->next)
-           ChangeList(ta, 1, tp->name, tp->rights);
+           ChangeList(ta, 1, tp->name, tp->rights, NULL);
        for (tp = fa->minuslist; tp; tp = tp->next)
-           ChangeList(ta, 0, tp->name, tp->rights);
+           ChangeList(ta, 0, tp->name, tp->rights, NULL);
        blob.in = AclToString(ta);
        blob.out_size = 0;
        blob.in_size = 1 + strlen(blob.in);