diff options
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/smbcacls.c | 130 |
1 files changed, 118 insertions, 12 deletions
diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index f18899d01d..8a88469999 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -32,6 +32,9 @@ static int got_pass; than going via LSA calls to resolve them */ static int numeric; +enum acl_mode {ACL_SET, ACL_DELETE, ACL_MODIFY, ACL_ADD}; + + /* convert a SID to a string, either numeric or username/group */ static void SidToString(fstring str, DOM_SID *sid) { @@ -79,7 +82,7 @@ static void print_ace(FILE *f, SEC_ACE *ace) perm = "C"; } else if (ace->info.mask == 0x001200a9) { perm = "R"; - } else if (ace->info.mask == 0x00000000) { + } else if (ace->info.mask == 0x00080000) { perm = "N"; } else { perm = "?"; @@ -275,12 +278,14 @@ static void cacl_dump(struct cli_state *cli, char *filename) /***************************************************** set the ACLs on a file given an ascii description *******************************************************/ -static void cacl_set(struct cli_state *cli, char *filename, char *set_acl) +static void cacl_set(struct cli_state *cli, char *filename, + char *acl, enum acl_mode mode) { int fnum; - SEC_DESC *sd; + SEC_DESC *sd, *old; + int i, j; - sd = sec_desc_parse(set_acl); + sd = sec_desc_parse(acl); if (!sd) { printf("Failed to parse security descriptor\n"); return; @@ -292,14 +297,89 @@ static void cacl_set(struct cli_state *cli, char *filename, char *set_acl) return; } - /* sec_desc_print(stdout, sd); */ + old = cli_query_secdesc(cli, fnum); + + /* the logic here is rather more complex than I would like */ + switch (mode) { + case ACL_DELETE: + for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { + for (j=0;old->dacl && j<old->dacl->num_aces;j++) { + if (sec_ace_equal(&sd->dacl->ace[i], + &old->dacl->ace[j])) { + if (j == old->dacl->num_aces-1) { + free(old->dacl->ace); + old->dacl->ace=NULL; + free(old->dacl); + old->dacl = NULL; + } else { + old->dacl->ace[j] = old->dacl->ace[j+1]; + old->dacl->num_aces--; + } + j--; + } + } + } + for (i=0;sd->sacl && i<sd->sacl->num_aces;i++) { + for (j=0;old->sacl && j<old->sacl->num_aces;j++) { + if (sec_ace_equal(&sd->sacl->ace[i], + &old->sacl->ace[j])) { + if (j == old->sacl->num_aces-1) { + free(old->sacl->ace); + old->sacl->ace=NULL; + free(old->sacl); + old->sacl = NULL; + } else { + old->sacl->ace[j] = old->sacl->ace[j+1]; + old->sacl->num_aces--; + } + j--; + } + } + } + break; + + case ACL_MODIFY: + for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { + for (j=0;old->dacl && j<old->dacl->num_aces;j++) { + if (sid_equal(&sd->dacl->ace[i].sid, + &old->dacl->ace[j].sid)) { + old->dacl->ace[j] = sd->dacl->ace[i]; + } + } + } + for (i=0;sd->sacl && i<sd->sacl->num_aces;i++) { + for (j=0;old->sacl && j<old->sacl->num_aces;j++) { + if (sid_equal(&sd->sacl->ace[i].sid, + &old->sacl->ace[j].sid)) { + old->sacl->ace[j] = sd->sacl->ace[i]; + } + } + } + break; + + case ACL_ADD: + for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) { + add_ace(&old->dacl, &sd->dacl->ace[i]); + } + for (i=0;sd->sacl && i<sd->sacl->num_aces;i++) { + add_ace(&old->sacl, &sd->sacl->ace[i]); + } + break; + + case ACL_SET: + free_sec_desc(&old); + old = sd; + break; + + } - if (!cli_set_secdesc(cli, fnum, sd)) { + if (!cli_set_secdesc(cli, fnum, old)) { printf("ERROR: secdesc set failed\n"); return; } free_sec_desc(&sd); + free_sec_desc(&old); cli_close(cli, fnum); } @@ -393,7 +473,16 @@ static void usage(void) { printf( "Usage:\n\ - smbcacls //server1/share1 filename\n\n"); + smbcacls //server1/share1 filename [options]\n\n\ +\n\ + -D <acls> delete an acl\n\ + -M <acls> modify an acl\n\ + -A <acls> add an acl\n\ + -S <acls> set acls\n\ +\n\ + an acl is of the form SID:type/flags/mask\n\ + you can string acls together with spaces, commas or newlines\n\ +"); } /**************************************************************************** @@ -411,7 +500,8 @@ static void usage(void) int seed; static pstring servicesf = CONFIGFILE; struct cli_state *cli; - char *set_acl = NULL; + enum acl_mode mode; + char *acl = NULL; setlinebuf(stdout); @@ -444,7 +534,7 @@ static void usage(void) seed = time(NULL); - while ((opt = getopt(argc, argv, "U:nhS:")) != EOF) { + while ((opt = getopt(argc, argv, "U:nhS:D:A:M:")) != EOF) { switch (opt) { case 'U': pstrcpy(username,optarg); @@ -457,7 +547,23 @@ static void usage(void) break; case 'S': - set_acl = optarg; + acl = optarg; + mode = ACL_SET; + break; + + case 'D': + acl = optarg; + mode = ACL_DELETE; + break; + + case 'M': + acl = optarg; + mode = ACL_MODIFY; + break; + + case 'A': + acl = optarg; + mode = ACL_ADD; break; case 'n': @@ -479,8 +585,8 @@ static void usage(void) cli = connect_one(share); if (!cli) exit(1); - if (set_acl) { - cacl_set(cli, filename, set_acl); + if (acl) { + cacl_set(cli, filename, acl, mode); } else { cacl_dump(cli, filename); } |