From 7d76a5b4f9eb4c0ed9e09bbc3c54a4f1f8da1bdc Mon Sep 17 00:00:00 2001 From: Rainer Strunz Date: Mon, 18 Apr 2011 00:09:33 +0100 Subject: [PATCH] fs: add support for relative ACL changes 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 Reviewed-by: Derrick Brashear Reviewed-by: Jeffrey Altman --- doc/man-pages/pod1/fs_setacl.pod | 20 ++++++++++++++- src/WINNT/afsd/fs.c | 48 ++++++++++++++++++++++++++++++------ src/venus/fs.c | 53 +++++++++++++++++++++++++++++++--------- 3 files changed, 102 insertions(+), 19 deletions(-) diff --git a/doc/man-pages/pod1/fs_setacl.pod b/doc/man-pages/pod1/fs_setacl.pod index cbe0e4d..fea5a5a 100644 --- a/doc/man-pages/pod1/fs_setacl.pod +++ b/doc/man-pages/pod1/fs_setacl.pod @@ -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 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 (administer) permission on the directory's diff --git a/src/WINNT/afsd/fs.c b/src/WINNT/afsd/fs.c index 9ff557e..9363e6c 100644 --- a/src/WINNT/afsd/fs.c +++ b/src/WINNT/afsd/fs.c @@ -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))) { diff --git a/src/venus/fs.c b/src/venus/fs.c index 06b3b6d..8cc842f 100644 --- a/src/venus/fs.c +++ b/src/venus/fs.c @@ -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); -- 1.9.4