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,
};
static struct cli_state *global_hack_cli;
+static struct rpc_pipe_client *global_pipe_hnd;
static POLICY_HND pol;
static BOOL got_policy_hnd;
/* Initialise cli LSA connection */
if (!global_hack_cli) {
+ NTSTATUS ret;
global_hack_cli = connect_one("IPC$");
- if (!cli_nt_session_open (global_hack_cli, PI_LSARPC)) {
+ global_pipe_hnd = cli_rpc_pipe_open_noauth(global_hack_cli, PI_LSARPC, &ret);
+ if (!global_pipe_hnd) {
return False;
}
}
/* 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(global_hack_cli, global_hack_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;
}
{
char **domains = NULL;
char **names = NULL;
- uint32 *types = NULL;
+ enum lsa_SidType *types = NULL;
sid_to_string(str, sid);
/* Ask LSA to convert the sid to a name */
if (!cacls_open_policy_hnd() ||
- !NT_STATUS_IS_OK(cli_lsa_lookup_sids(global_hack_cli, global_hack_cli->mem_ctx,
+ !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]) {
/* convert a string to a SID, either numeric or username/group */
static BOOL StringToSid(DOM_SID *sid, const char *str)
{
- uint32 *types = NULL;
+ enum lsa_SidType *types = NULL;
DOM_SID *sids = NULL;
BOOL result = True;
}
if (!cacls_open_policy_hnd() ||
- !NT_STATUS_IS_OK(cli_lsa_lookup_names(global_hack_cli, global_hack_cli->mem_ctx,
- &pol, 1, &str, &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;
if (numeric) {
fprintf(f, "%d/%d/0x%08x",
- ace->type, ace->flags, ace->info.mask);
+ ace->type, ace->flags, ace->access_mask);
return;
}
/* 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;
}
/* 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);
}
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;
/* 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;
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 */
/* 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;
}
cp = p;
if (!next_token(&cp, tok, "/", sizeof(fstring))) {
+ printf("ACE '%s': failed to find '/' character.\n",
+ orig_str);
+ SAFE_FREE(str);
return False;
}
} 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;
}
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(&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;
}
}
- 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);
+ new_ace = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
SAFE_FREE(aces);
- (*the_acl) = new;
+ (*the_acl) = new_ace;
return True;
}
{
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;
}
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;
}
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);
+ done:
SAFE_FREE(grp_sid);
SAFE_FREE(owner_sid);
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, "");
}
/* 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");
return EXIT_FAILED;
}
- sd = make_sec_desc(ctx,old->revision,
+ 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);
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->access_mask != ace2->access_mask)
+ return ace1->access_mask - ace2->access_mask;
if (ace1->size != ace2->size)
return ace1->size - ace2->size;
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 {
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])) {
+ 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) {
- SAFE_FREE(old->dacl->ace);
- SAFE_FREE(old->dacl);
- old->off_dacl = 0;
- }
found = True;
break;
}
if (!found) {
printf("ACL for ACE:");
- print_ace(stdout, &sd->dacl->ace[i]);
+ print_ace(stdout, &sd->dacl->aces[i]);
printf(" not found\n");
}
}
BOOL found = False;
for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
- if (sid_equal(&sd->dacl->ace[i].trustee,
- &old->dacl->ace[j].trustee)) {
- 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;
}
}
if (!found) {
fstring str;
- SidToString(str, &sd->dacl->ace[i].trustee);
+ 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;
sort_acl(old->dacl);
/* Create new security descriptor and set it */
- sd = make_sec_desc(ctx,old->revision, NULL, NULL,
+#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, WRITE_DAC_ACCESS);
+ 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;
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" },
+ { "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" },
struct cli_state *cli;
- ctx=talloc_init("main");
+ load_case_tables();
- setlinebuf(stdout);
+ 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 );
- setup_logging(argv[0],True);
+ setlinebuf(stdout);
- lp_load(dyn_CONFIGFILE,True,False,False);
+ lp_load(dyn_CONFIGFILE,True,False,False,True);
load_interfaces();
pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
- poptSetOtherOptionHelp(pc, "//server1/share1 filename");
+ poptSetOtherOptionHelp(pc, "//server1/share1 filename\nACLs look like: "
+ "'ACL:user:[ALLOWED|DENIED]/flags/permissions'");
while ((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
mode = SMB_ACL_MODIFY;
break;
- case 'A':
+ case 'a':
the_acl = smb_xstrdup(poptGetOptArg(pc));
mode = SMB_ACL_ADD;
break;
fstrcpy(server,path+2);
share = strchr_m(server,'\\');
if (!share) {
- share = strchr_m(server,'/');
- if (!share) {
- printf("Invalid argument: %s\n", share);
- return -1;
- }
+ printf("Invalid argument: %s\n", share);
+ return -1;
}
*share = 0;