r23779: Change from v2 or later to v3 or later.
[bbaumbach/samba-autobuild/.git] / source3 / utils / smbcacls.c
index 914e99367bb71a71ebbb083247b712e1ddb5b671..e4ab4e9283a117bdde43042c63372768d2002f39 100644 (file)
@@ -1,15 +1,15 @@
 /* 
-   Unix SMB/Netbios implementation.
+   Unix SMB/CIFS implementation.
    ACL get/set utility
-   Version 3.0
    
    Copyright (C) Andrew Tridgell 2000
    Copyright (C) Tim Potter      2000
    Copyright (C) Jeremy Allison  2000
+   Copyright (C) Jelmer Vernooij 2003
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
 
 #include "includes.h"
 
-static fstring password;
-static pstring username;
 static pstring owner_username;
 static fstring server;
-static int got_pass;
-static int test_args;
-TALLOC_CTX *ctx;
+static int test_args = False;
+static TALLOC_CTX *ctx;
 
 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
-#define CREATE_ACCESS_WRITE (WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS)
 
 /* numeric is set when the user wants numeric SIDs and ACEs rather
    than going via LSA calls to resolve them */
-static int numeric;
+static BOOL numeric = False;
 
 enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD };
 enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP};
 enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
 
 struct perm_value {
-       char *perm;
+       const char *perm;
        uint32 mask;
 };
 
 /* These values discovered by inspection */
 
-static struct perm_value special_values[] = {
+static const struct perm_value special_values[] = {
        { "R", 0x00120089 },
        { "W", 0x00120116 },
        { "X", 0x001200a0 },
@@ -60,31 +56,35 @@ static struct perm_value special_values[] = {
        { NULL, 0 },
 };
 
-static struct perm_value standard_values[] = {
+static const struct perm_value standard_values[] = {
        { "READ",   0x001200a9 },
        { "CHANGE", 0x001301bf },
        { "FULL",   0x001f01ff },
        { NULL, 0 },
 };
 
-struct cli_state lsa_cli;
-POLICY_HND pol;
-struct ntuser_creds creds;
-BOOL got_policy_hnd;
+static struct cli_state *global_hack_cli;
+static struct rpc_pipe_client *global_pipe_hnd;
+static POLICY_HND pol;
+static BOOL got_policy_hnd;
+
+static struct cli_state *connect_one(const char *share);
 
 /* Open cli connection and policy handle */
 
 static BOOL cacls_open_policy_hnd(void)
 {
-       creds.pwd.null_pwd = 1;
-
        /* Initialise cli LSA connection */
 
-       if (!lsa_cli.initialised && 
-           !cli_lsa_initialise(&lsa_cli, server, &creds)) {
-               return False;
+       if (!global_hack_cli) {
+               NTSTATUS ret;
+               global_hack_cli = connect_one("IPC$");
+               global_pipe_hnd = cli_rpc_pipe_open_noauth(global_hack_cli, PI_LSARPC, &ret);
+               if (!global_pipe_hnd) {
+                               return False;
+               }
        }
-
+       
        /* Open policy handle */
 
        if (!got_policy_hnd) {
@@ -92,7 +92,7 @@ static BOOL cacls_open_policy_hnd(void)
                /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
                   but NT sends 0x2000000 so we might as well do it too. */
 
-               if (!NT_STATUS_IS_OK(cli_lsa_open_policy(&lsa_cli, lsa_cli.mem_ctx, True, 
+               if (!NT_STATUS_IS_OK(rpccli_lsa_open_policy(global_pipe_hnd, global_hack_cli->mem_ctx, True, 
                                                         GENERIC_EXECUTE_ACCESS, &pol))) {
                        return False;
                }
@@ -106,9 +106,9 @@ static BOOL cacls_open_policy_hnd(void)
 /* convert a SID to a string, either numeric or username/group */
 static void SidToString(fstring str, DOM_SID *sid)
 {
+       char **domains = NULL;
        char **names = NULL;
-       uint32 *types = NULL;
-       int num_names;
+       enum lsa_SidType *types = NULL;
 
        sid_to_string(str, sid);
 
@@ -117,38 +117,41 @@ static void SidToString(fstring str, DOM_SID *sid)
        /* Ask LSA to convert the sid to a name */
 
        if (!cacls_open_policy_hnd() ||
-           !NT_STATUS_IS_OK(cli_lsa_lookup_sids(&lsa_cli, lsa_cli.mem_ctx,  &pol, 1, sid, &names, 
-                                                &types, &num_names)) ||
-           !names || !names[0]) {
+           !NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(global_pipe_hnd, global_hack_cli->mem_ctx,  
+                                                &pol, 1, sid, &domains, 
+                                                &names, &types)) ||
+           !domains || !domains[0] || !names || !names[0]) {
                return;
        }
 
        /* Converted OK */
+
+       slprintf(str, sizeof(fstring) - 1, "%s%s%s",
+                domains[0], lp_winbind_separator(),
+                names[0]);
        
-       fstrcpy(str, names[0]);
 }
 
 /* convert a string to a SID, either numeric or username/group */
-static BOOL StringToSid(DOM_SID *sid, char *str)
+static BOOL StringToSid(DOM_SID *sid, const char *str)
 {
-       uint32 *types = NULL;
+       enum lsa_SidType *types = NULL;
        DOM_SID *sids = NULL;
-       int num_sids;
        BOOL result = True;
-       
+
        if (strncmp(str, "S-", 2) == 0) {
                return string_to_sid(sid, str);
        }
 
        if (!cacls_open_policy_hnd() ||
-           !NT_STATUS_IS_OK(cli_lsa_lookup_names(&lsa_cli, lsa_cli.mem_ctx, &pol, 1, &str, 
-                                                &sids, &types, &num_sids))) {
+           !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, global_hack_cli->mem_ctx, 
+                                                 &pol, 1, &str, NULL, 1, &sids, 
+                                                 &types))) {
                result = False;
                goto done;
        }
 
        sid_copy(sid, &sids[0]);
-
  done:
 
        return result;
@@ -158,18 +161,18 @@ static BOOL StringToSid(DOM_SID *sid, char *str)
 /* print an ACE on a FILE, using either numeric or ascii representation */
 static void print_ace(FILE *f, SEC_ACE *ace)
 {
-       struct perm_value *v;
+       const struct perm_value *v;
        fstring sidstr;
        int do_print = 0;
        uint32 got_mask;
 
-       SidToString(sidstr, &ace->sid);
+       SidToString(sidstr, &ace->trustee);
 
        fprintf(f, "%s:", sidstr);
 
        if (numeric) {
                fprintf(f, "%d/%d/0x%08x", 
-                       ace->type, ace->flags, ace->info.mask);
+                       ace->type, ace->flags, ace->access_mask);
                return;
        }
 
@@ -190,7 +193,7 @@ static void print_ace(FILE *f, SEC_ACE *ace)
        /* Standard permissions */
 
        for (v = standard_values; v->perm; v++) {
-               if (ace->info.mask == v->mask) {
+               if (ace->access_mask == v->mask) {
                        fprintf(f, "%s", v->perm);
                        return;
                }
@@ -199,11 +202,11 @@ static void print_ace(FILE *f, SEC_ACE *ace)
        /* Special permissions.  Print out a hex value if we have
           leftover bits in the mask. */
 
-       got_mask = ace->info.mask;
+       got_mask = ace->access_mask;
 
  again:
        for (v = special_values; v->perm; v++) {
-               if ((ace->info.mask & v->mask) == v->mask) {
+               if ((ace->access_mask & v->mask) == v->mask) {
                        if (do_print) {
                                fprintf(f, "%s", v->perm);
                        }
@@ -213,7 +216,7 @@ static void print_ace(FILE *f, SEC_ACE *ace)
 
        if (!do_print) {
                if (got_mask != 0) {
-                       fprintf(f, "0x%08x", ace->info.mask);
+                       fprintf(f, "0x%08x", ace->access_mask);
                } else {
                        do_print = 1;
                        goto again;
@@ -223,21 +226,32 @@ static void print_ace(FILE *f, SEC_ACE *ace)
 
 
 /* parse an ACE in the same format as print_ace() */
-static BOOL parse_ace(SEC_ACE *ace, char *str)
+static BOOL parse_ace(SEC_ACE *ace, const char *orig_str)
 {
        char *p;
+       const char *cp;
        fstring tok;
-       unsigned atype, aflags, amask;
+       unsigned int atype = 0;
+       unsigned int aflags = 0;
+       unsigned int amask = 0;
        DOM_SID sid;
        SEC_ACCESS mask;
-       struct perm_value *v;
+       const struct perm_value *v;
+       char *str = SMB_STRDUP(orig_str);
+
+       if (!str) {
+               return False;
+       }
 
        ZERO_STRUCTP(ace);
        p = strchr_m(str,':');
-       if (!p) return False;
+       if (!p) {
+               printf("ACE '%s': missing ':'.\n", orig_str);
+               SAFE_FREE(str);
+               return False;
+       }
        *p = '\0';
        p++;
-
        /* Try to parse numeric form */
 
        if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
@@ -248,10 +262,17 @@ static BOOL parse_ace(SEC_ACE *ace, char *str)
        /* Try to parse text form */
 
        if (!StringToSid(&sid, str)) {
+               printf("ACE '%s': failed to convert '%s' to SID\n",
+                       orig_str, str);
+               SAFE_FREE(str);
                return False;
        }
 
-       if (!next_token(&p, tok, "/", sizeof(fstring))) {
+       cp = p;
+       if (!next_token(&cp, tok, "/", sizeof(fstring))) {
+               printf("ACE '%s': failed to find '/' character.\n",
+                       orig_str);
+               SAFE_FREE(str);
                return False;
        }
 
@@ -260,22 +281,34 @@ static BOOL parse_ace(SEC_ACE *ace, char *str)
        } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
                atype = SEC_ACE_TYPE_ACCESS_DENIED;
        } else {
+               printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
+                       orig_str, tok);
+               SAFE_FREE(str);
                return False;
        }
 
        /* Only numeric form accepted for flags at present */
 
-       if (!(next_token(&p, tok, "/", sizeof(fstring)) &&
+       if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
              sscanf(tok, "%i", &aflags))) {
+               printf("ACE '%s': bad integer flags entry at '%s'\n",
+                       orig_str, tok);
+               SAFE_FREE(str);
                return False;
        }
 
-       if (!next_token(&p, tok, "/", sizeof(fstring))) {
+       if (!next_token(&cp, tok, "/", sizeof(fstring))) {
+               printf("ACE '%s': missing / at '%s'\n",
+                       orig_str, tok);
+               SAFE_FREE(str);
                return False;
        }
 
        if (strncmp(tok, "0x", 2) == 0) {
                if (sscanf(tok, "%i", &amask) != 1) {
+                       printf("ACE '%s': bad hex number at '%s'\n",
+                               orig_str, tok);
+                       SAFE_FREE(str);
                        return False;
                }
                goto done;
@@ -300,45 +333,53 @@ static BOOL parse_ace(SEC_ACE *ace, char *str)
                        }
                }
 
-               if (!found) return False;
+               if (!found) {
+                       printf("ACE '%s': bad permission value at '%s'\n",
+                               orig_str, p);
+                       SAFE_FREE(str);
+                       return False;
+               }
                p++;
        }
 
        if (*p) {
+               SAFE_FREE(str);
                return False;
        }
 
  done:
-       mask.mask = amask;
+       mask = amask;
        init_sec_ace(ace, &sid, atype, mask, aflags);
+       SAFE_FREE(str);
        return True;
 }
 
 /* add an ACE to a list of ACEs in a SEC_ACL */
 static BOOL add_ace(SEC_ACL **the_acl, SEC_ACE *ace)
 {
-       SEC_ACL *new;
+       SEC_ACL *new_ace;
        SEC_ACE *aces;
        if (! *the_acl) {
-               (*the_acl) = make_sec_acl(ctx, 3, 1, ace);
-               return True;
+               return (((*the_acl) = make_sec_acl(ctx, 3, 1, ace)) != NULL);
        }
 
-       aces = calloc(1+(*the_acl)->num_aces,sizeof(SEC_ACE));
-       memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE));
+       if (!(aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces))) {
+               return False;
+       }
+       memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
        memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
-       new = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
-       free(aces);
-       (*the_acl) = new;
+       new_ace = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
+       SAFE_FREE(aces);
+       (*the_acl) = new_ace;
        return True;
 }
 
 /* parse a ascii version of a security descriptor */
 static SEC_DESC *sec_desc_parse(char *str)
 {
-       char *p = str;
+       const char *p = str;
        fstring tok;
-       SEC_DESC *ret;
+       SEC_DESC *ret = NULL;
        size_t sd_size;
        DOM_SID *grp_sid=NULL, *owner_sid=NULL;
        SEC_ACL *dacl=NULL;
@@ -352,21 +393,29 @@ static SEC_DESC *sec_desc_parse(char *str)
                }
 
                if (strncmp(tok,"OWNER:", 6) == 0) {
-                       owner_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
+                       if (owner_sid) {
+                               printf("Only specify owner once\n");
+                               goto done;
+                       }
+                       owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
                        if (!owner_sid ||
                            !StringToSid(owner_sid, tok+6)) {
                                printf("Failed to parse owner sid\n");
-                               return NULL;
+                               goto done;
                        }
                        continue;
                }
 
                if (strncmp(tok,"GROUP:", 6) == 0) {
-                       grp_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
+                       if (grp_sid) {
+                               printf("Only specify group once\n");
+                               goto done;
+                       }
+                       grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
                        if (!grp_sid ||
                            !StringToSid(grp_sid, tok+6)) {
                                printf("Failed to parse group sid\n");
-                               return NULL;
+                               goto done;
                        }
                        continue;
                }
@@ -374,25 +423,25 @@ static SEC_DESC *sec_desc_parse(char *str)
                if (strncmp(tok,"ACL:", 4) == 0) {
                        SEC_ACE ace;
                        if (!parse_ace(&ace, tok+4)) {
-                               printf("Failed to parse ACL %s\n", tok);
-                               return NULL;
+                               goto done;
                        }
                        if(!add_ace(&dacl, &ace)) {
                                printf("Failed to add ACL %s\n", tok);
-                               return NULL;
+                               goto done;
                        }
                        continue;
                }
 
-               printf("Failed to parse security descriptor\n");
-               return NULL;
+               printf("Failed to parse token '%s' in security descriptor,\n", tok);
+               goto done;
        }
 
-       ret = make_sec_desc(ctx,revision, owner_sid, grp_sid, 
+       ret = make_sec_desc(ctx,revision, SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, 
                            NULL, dacl, &sd_size);
 
-       if (grp_sid) free(grp_sid);
-       if (owner_sid) free(owner_sid);
+  done:
+       SAFE_FREE(grp_sid);
+       SAFE_FREE(owner_sid);
 
        return ret;
 }
@@ -402,9 +451,9 @@ static SEC_DESC *sec_desc_parse(char *str)
 static void sec_desc_print(FILE *f, SEC_DESC *sd)
 {
        fstring sidstr;
-       int i;
+       uint32 i;
 
-       printf("REVISION:%d\n", sd->revision);
+       fprintf(f, "REVISION:%d\n", sd->revision);
 
        /* Print owner and group sid */
 
@@ -414,10 +463,10 @@ static void sec_desc_print(FILE *f, SEC_DESC *sd)
                fstrcpy(sidstr, "");
        }
 
-       printf("OWNER:%s\n", sidstr);
+       fprintf(f, "OWNER:%s\n", sidstr);
 
-       if (sd->grp_sid) {
-               SidToString(sidstr, sd->grp_sid);
+       if (sd->group_sid) {
+               SidToString(sidstr, sd->group_sid);
        } else {
                fstrcpy(sidstr, "");
        }
@@ -426,7 +475,7 @@ static void sec_desc_print(FILE *f, SEC_DESC *sd)
 
        /* Print aces */
        for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
-               SEC_ACE *ace = &sd->dacl->ace[i];
+               SEC_ACE *ace = &sd->dacl->aces[i];
                fprintf(f, "ACL:");
                print_ace(f, ace);
                fprintf(f, "\n");
@@ -439,29 +488,36 @@ dump the acls for a file
 *******************************************************/
 static int cacl_dump(struct cli_state *cli, char *filename)
 {
-       int fnum;
+       int result = EXIT_FAILED;
+       int fnum = -1;
        SEC_DESC *sd;
 
-       if (test_args) return EXIT_OK;
+       if (test_args) 
+               return EXIT_OK;
 
        fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+
        if (fnum == -1) {
                printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
-               return EXIT_FAILED;
+               goto done;
        }
 
        sd = cli_query_secdesc(cli, fnum, ctx);
 
        if (!sd) {
                printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
-               return EXIT_FAILED;
+               goto done;
        }
 
        sec_desc_print(stdout, sd);
 
-       cli_close(cli, fnum);
+       result = EXIT_OK;
 
-       return EXIT_OK;
+done:
+       if (fnum != -1)
+               cli_close(cli, fnum);
+
+       return result;
 }
 
 /***************************************************** 
@@ -496,12 +552,12 @@ static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
                return EXIT_FAILED;
        }
 
-       sd = make_sec_desc(ctx,old->revision,
-                               (change_mode == REQUEST_CHOWN) ? &sid : old->owner_sid,
-                               (change_mode == REQUEST_CHGRP) ? &sid : old->grp_sid,
-                          NULL, old->dacl, &sd_size);
+       sd = make_sec_desc(ctx,old->revision, old->type,
+                               (change_mode == REQUEST_CHOWN) ? &sid : NULL,
+                               (change_mode == REQUEST_CHGRP) ? &sid : NULL,
+                          NULL, NULL, &sd_size);
 
-       fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
+       fnum = cli_nt_create(cli, filename, WRITE_OWNER_ACCESS);
 
        if (fnum == -1) {
                printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
@@ -525,27 +581,39 @@ static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
 
 static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
 {
-       if (sec_ace_equal(ace1, ace2)) return 0;
-       if (ace1->type != ace2->type) return ace2->type - ace1->type;
-       if (sid_compare(&ace1->sid, &ace2->sid)) return sid_compare(&ace1->sid, &ace2->sid);
-       if (ace1->flags != ace2->flags) return ace1->flags - ace2->flags;
-       if (ace1->info.mask != ace2->info.mask) return ace1->info.mask - ace2->info.mask;
-       if (ace1->size != ace2->size) return ace1->size - ace2->size;
+       if (sec_ace_equal(ace1, ace2)) 
+               return 0;
+
+       if (ace1->type != ace2->type) 
+               return ace2->type - ace1->type;
+
+       if (sid_compare(&ace1->trustee, &ace2->trustee)) 
+               return sid_compare(&ace1->trustee, &ace2->trustee);
+
+       if (ace1->flags != ace2->flags) 
+               return ace1->flags - ace2->flags;
+
+       if (ace1->access_mask != ace2->access_mask) 
+               return ace1->access_mask - ace2->access_mask;
+
+       if (ace1->size != ace2->size) 
+               return ace1->size - ace2->size;
+
        return memcmp(ace1, ace2, sizeof(SEC_ACE));
 }
 
 static void sort_acl(SEC_ACL *the_acl)
 {
-       int i;
+       uint32 i;
        if (!the_acl) return;
 
-       qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]), QSORT_CAST ace_compare);
+       qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), QSORT_CAST ace_compare);
 
        for (i=1;i<the_acl->num_aces;) {
-               if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
+               if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
                        int j;
                        for (j=i; j<the_acl->num_aces-1; j++) {
-                               the_acl->ace[j] = the_acl->ace[j+1];
+                               the_acl->aces[j] = the_acl->aces[j+1];
                        }
                        the_acl->num_aces--;
                } else {
@@ -562,7 +630,7 @@ static int cacl_set(struct cli_state *cli, char *filename,
 {
        int fnum;
        SEC_DESC *sd, *old;
-       int i, j;
+       uint32 i, j;
        size_t sd_size;
        int result = EXIT_OK;
 
@@ -597,20 +665,13 @@ static int cacl_set(struct cli_state *cli, char *filename,
                        BOOL found = False;
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
-                               if (sec_ace_equal(&sd->dacl->ace[i],
-                                                 &old->dacl->ace[j])) {
-                                       int k;
+                               if (sec_ace_equal(&sd->dacl->aces[i],
+                                                 &old->dacl->aces[j])) {
+                                       uint32 k;
                                        for (k=j; k<old->dacl->num_aces-1;k++) {
-                                               old->dacl->ace[k] = old->dacl->ace[k+1];
+                                               old->dacl->aces[k] = old->dacl->aces[k+1];
                                        }
                                        old->dacl->num_aces--;
-                                       if (old->dacl->num_aces == 0) {
-                                               free(old->dacl->ace);
-                                               old->dacl->ace=NULL;
-                                               free(old->dacl);
-                                               old->dacl = NULL;
-                                               old->off_dacl = 0;
-                                       }
                                        found = True;
                                        break;
                                }
@@ -618,7 +679,7 @@ static int cacl_set(struct cli_state *cli, char *filename,
 
                        if (!found) {
                                printf("ACL for ACE:"); 
-                               print_ace(stdout, &sd->dacl->ace[i]);
+                               print_ace(stdout, &sd->dacl->aces[i]);
                                printf(" not found\n");
                        }
                }
@@ -629,9 +690,9 @@ static int cacl_set(struct cli_state *cli, char *filename,
                        BOOL found = False;
 
                        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];
+                               if (sid_equal(&sd->dacl->aces[i].trustee,
+                                             &old->dacl->aces[j].trustee)) {
+                                       old->dacl->aces[j] = sd->dacl->aces[i];
                                        found = True;
                                }
                        }
@@ -639,16 +700,24 @@ static int cacl_set(struct cli_state *cli, char *filename,
                        if (!found) {
                                fstring str;
 
-                               SidToString(str, &sd->dacl->ace[i].sid);
+                               SidToString(str, &sd->dacl->aces[i].trustee);
                                printf("ACL for SID %s not found\n", str);
                        }
                }
 
+               if (sd->owner_sid) {
+                       old->owner_sid = sd->owner_sid;
+               }
+
+               if (sd->group_sid) { 
+                       old->group_sid = sd->group_sid;
+               }
+
                break;
 
        case SMB_ACL_ADD:
                for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-                       add_ace(&old->dacl, &sd->dacl->ace[i]);
+                       add_ace(&old->dacl, &sd->dacl->aces[i]);
                }
                break;
 
@@ -661,11 +730,24 @@ static int cacl_set(struct cli_state *cli, char *filename,
        sort_acl(old->dacl);
 
        /* Create new security descriptor and set it */
-       sd = make_sec_desc(ctx,old->revision, old->owner_sid, old->grp_sid, 
+#if 0
+       /* We used to just have "WRITE_DAC_ACCESS" without WRITE_OWNER.
+          But if we're sending an owner, even if it's the same as the one
+          that already exists then W2K3 insists we open with WRITE_OWNER access.
+          I need to check that setting a SD with no owner set works against WNT
+          and W2K. JRA.
+       */
+
+       sd = make_sec_desc(ctx,old->revision, old->type, old->owner_sid, old->grp_sid,
                           NULL, old->dacl, &sd_size);
 
-       fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
+       fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS);
+#else
+       sd = make_sec_desc(ctx,old->revision, old->type, NULL, NULL,
+                          NULL, old->dacl, &sd_size);
 
+       fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS);
+#endif
        if (fnum == -1) {
                printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
                return EXIT_FAILED;
@@ -687,244 +769,145 @@ static int cacl_set(struct cli_state *cli, char *filename,
 /***************************************************** 
 return a connection to a server
 *******************************************************/
-struct cli_state *connect_one(char *share)
+static struct cli_state *connect_one(const char *share)
 {
        struct cli_state *c;
-       struct nmb_name called, calling;
        struct in_addr ip;
-       extern struct in_addr ipzero;
-       extern pstring global_myname;
-
-       fstrcpy(server,share+2);
-       share = strchr_m(server,'\\');
-       if (!share) return NULL;
-       *share = 0;
-       share++;
-
-       ip = ipzero;
-
-       make_nmb_name(&calling, global_myname, 0x0);
-       make_nmb_name(&called , server, 0x20);
-
- again:
-       ip = ipzero;
-
-       /* have to open a new connection */
-       if (!(c=cli_initialise(NULL)) || !cli_connect(c, server, &ip)) {
-               DEBUG(0,("Connection to %s failed\n", server));
-               cli_shutdown(c);
-               safe_free(c);
-               return NULL;
-       }
-
-       if (!cli_session_request(c, &calling, &called)) {
-               DEBUG(0,("session request to %s failed\n", called.name));
-               cli_shutdown(c);
-               safe_free(c);
-               if (strcmp(called.name, "*SMBSERVER")) {
-                       make_nmb_name(&called , "*SMBSERVER", 0x20);
-                       goto again;
-               }
-               return NULL;
-       }
-
-       DEBUG(4,(" session request ok\n"));
-
-       if (!cli_negprot(c)) {
-               DEBUG(0,("protocol negotiation failed\n"));
-               cli_shutdown(c);
-               safe_free(c);
-               return NULL;
-       }
-
-       if (!got_pass) {
+       NTSTATUS nt_status;
+       zero_ip(&ip);
+       
+       if (!cmdline_auth_info.got_pass) {
                char *pass = getpass("Password: ");
                if (pass) {
-                       pstrcpy(password, pass);
+                       pstrcpy(cmdline_auth_info.password, pass);
+                       cmdline_auth_info.got_pass = True;
                }
        }
 
-       if (!cli_session_setup(c, username, 
-                              password, strlen(password),
-                              password, strlen(password),
-                              lp_workgroup())) {
-               DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
-               cli_shutdown(c);
-               safe_free(c);
-               return NULL;
-       }
-
-       DEBUG(4,(" session setup ok\n"));
-
-       if (!cli_send_tconX(c, share, "?????",
-                           password, strlen(password)+1)) {
-               DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
-               cli_shutdown(c);
-               safe_free(c);
+       if (NT_STATUS_IS_OK(nt_status = cli_full_connection(&c, global_myname(), server, 
+                                                           &ip, 0,
+                                                           share, "?????",  
+                                                           cmdline_auth_info.username, lp_workgroup(),
+                                                           cmdline_auth_info.password, 0,
+                                                           cmdline_auth_info.signing_state, NULL))) {
+               return c;
+       } else {
+               DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
                return NULL;
        }
-
-       DEBUG(4,(" tconx ok\n"));
-
-       return c;
-}
-
-
-static void usage(void)
-{
-       printf(
-"Usage: smbcacls //server1/share1 filename [options]\n\
-\n\
-\t-D <acls>               delete an acl\n\
-\t-M <acls>               modify an acl\n\
-\t-A <acls>               add an acl\n\
-\t-S <acls>               set acls\n\
-\t-C username             change ownership of a file\n\
-\t-G username             change group ownership of a file\n\
-\t-n                      don't resolve sids or masks to names\n\
-\t-h                      print help\n\
-\t-d debuglevel           set debug output level\n\
-\t-U username             user to autheticate as\n\
-\n\
-The username can be of the form username%%password or\n\
-workgroup\\username%%password.\n\n\
-An acl is of the form ACL:<SID>:type/flags/mask\n\
-You can string acls together with spaces, commas or newlines\n\
-");
 }
 
 /****************************************************************************
   main program
 ****************************************************************************/
- int main(int argc,char *argv[])
+ int main(int argc, const char *argv[])
 {
        char *share;
-       pstring filename;
-       extern char *optarg;
-       extern int optind;
        int opt;
-       char *p;
-       static pstring servicesf = CONFIGFILE;
-       struct cli_state *cli=NULL;
        enum acl_mode mode = SMB_ACL_SET;
-       char *the_acl = NULL;
+       static char *the_acl = NULL;
        enum chown_mode change_mode = REQUEST_NONE;
        int result;
-
-       ctx=talloc_init();
-
-       setlinebuf(stdout);
-
+       fstring path;
+       pstring filename;
+       poptContext pc;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               { "delete", 'D', POPT_ARG_STRING, NULL, 'D', "Delete an acl", "ACL" },
+               { "modify", 'M', POPT_ARG_STRING, NULL, 'M', "Modify an acl", "ACL" },
+               { "add", 'a', POPT_ARG_STRING, NULL, 'a', "Add an acl", "ACL" },
+               { "set", 'S', POPT_ARG_STRING, NULL, 'S', "Set acls", "ACLS" },
+               { "chown", 'C', POPT_ARG_STRING, NULL, 'C', "Change ownership of a file", "USERNAME" },
+               { "chgrp", 'G', POPT_ARG_STRING, NULL, 'G', "Change group ownership of a file", "GROUPNAME" },
+               { "numeric", 0, POPT_ARG_NONE, &numeric, True, "Don't resolve sids or masks to names" },
+               { "test-args", 't', POPT_ARG_NONE, &test_args, True, "Test arguments"},
+               POPT_COMMON_SAMBA
+               POPT_COMMON_CREDENTIALS
+               { NULL }
+       };
+
+       struct cli_state *cli;
+
+       load_case_tables();
+
+       ctx=talloc_init("main");
+
+       /* set default debug level to 1 regardless of what smb.conf sets */
+       setup_logging( "smbcacls", True );
+       DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
        dbf = x_stderr;
+       x_setbuf( x_stderr, NULL );
 
-       if (argc < 3 || argv[1][0] == '-') {
-               usage();
-               talloc_destroy(ctx);
-               exit(EXIT_PARSE_ERROR);
-       }
-
-       setup_logging(argv[0],True);
-
-       share = argv[1];
-       pstrcpy(filename, argv[2]);
-       all_string_sub(share,"/","\\",0);
-
-       argc -= 2;
-       argv += 2;
-
-       TimeInit();
+       setlinebuf(stdout);
 
-       lp_load(servicesf,True,False,False);
+       lp_load(dyn_CONFIGFILE,True,False,False,True);
        load_interfaces();
 
-       if (getenv("USER")) {
-               pstrcpy(username,getenv("USER"));
-
-               if ((p=strchr_m(username,'%'))) {
-                       *p = 0;
-                       pstrcpy(password,p+1);
-                       got_pass = True;
-                       memset(strchr_m(getenv("USER"), '%') + 1, 'X',
-                              strlen(password));
-               }
-       }
+       pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
+       
+       poptSetOtherOptionHelp(pc, "//server1/share1 filename\nACLs look like: "
+               "'ACL:user:[ALLOWED|DENIED]/flags/permissions'");
 
-       while ((opt = getopt(argc, argv, "U:nhS:D:A:M:C:G:td:")) != EOF) {
+       while ((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
-               case 'U':
-                       pstrcpy(username,optarg);
-                       p = strchr_m(username,'%');
-                       if (p) {
-                               *p = 0;
-                               pstrcpy(password, p+1);
-                               got_pass = 1;
-                       }
-                       break;
-
                case 'S':
-                       the_acl = optarg;
+                       the_acl = smb_xstrdup(poptGetOptArg(pc));
                        mode = SMB_ACL_SET;
                        break;
 
                case 'D':
-                       the_acl = optarg;
+                       the_acl = smb_xstrdup(poptGetOptArg(pc));
                        mode = SMB_ACL_DELETE;
                        break;
 
                case 'M':
-                       the_acl = optarg;
+                       the_acl = smb_xstrdup(poptGetOptArg(pc));
                        mode = SMB_ACL_MODIFY;
                        break;
 
-               case 'A':
-                       the_acl = optarg;
+               case 'a':
+                       the_acl = smb_xstrdup(poptGetOptArg(pc));
                        mode = SMB_ACL_ADD;
                        break;
 
                case 'C':
-                       pstrcpy(owner_username,optarg);
+                       pstrcpy(owner_username,poptGetOptArg(pc));
                        change_mode = REQUEST_CHOWN;
                        break;
 
                case 'G':
-                       pstrcpy(owner_username,optarg);
+                       pstrcpy(owner_username,poptGetOptArg(pc));
                        change_mode = REQUEST_CHGRP;
                        break;
-
-               case 'n':
-                       numeric = 1;
-                       break;
-
-               case 't':
-                       test_args = 1;
-                       break;
-
-               case 'h':
-                       usage();
-                       talloc_destroy(ctx);
-                       exit(EXIT_PARSE_ERROR);
-
-               case 'd':
-                       DEBUGLEVEL = atoi(optarg);
-                       break;
-
-               default:
-                       printf("Unknown option %c (%d)\n", (char)opt, opt);
-                       talloc_destroy(ctx);
-                       exit(EXIT_PARSE_ERROR);
                }
        }
 
-       argc -= optind;
-       argv += optind;
+       /* Make connection to server */
+       if(!poptPeekArg(pc)) { 
+               poptPrintUsage(pc, stderr, 0);
+               return -1;
+       }
+       
+       fstrcpy(path, poptGetArg(pc));
        
-       if (argc > 0) {
-               usage();
-               talloc_destroy(ctx);
-               exit(EXIT_PARSE_ERROR);
+       if(!poptPeekArg(pc)) { 
+               poptPrintUsage(pc, stderr, 0);  
+               return -1;
        }
+       
+       pstrcpy(filename, poptGetArg(pc));
 
-       /* Make connection to server */
+       all_string_sub(path,"/","\\",0);
+
+       fstrcpy(server,path+2);
+       share = strchr_m(server,'\\');
+       if (!share) {
+               printf("Invalid argument: %s\n", share);
+               return -1;
+       }
+
+       *share = 0;
+       share++;
 
        if (!test_args) {
                cli = connect_one(share);
@@ -932,13 +915,15 @@ You can string acls together with spaces, commas or newlines\n\
                        talloc_destroy(ctx);
                        exit(EXIT_FAILED);
                }
+       } else {
+               exit(0);
        }
 
        all_string_sub(filename, "/", "\\", 0);
        if (filename[0] != '\\') {
                pstring s;
                s[0] = '\\';
-               safe_strcpy(&s[1], filename, sizeof(pstring)-1);
+               safe_strcpy(&s[1], filename, sizeof(pstring)-2);
                pstrcpy(filename, s);
        }