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,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
-static fstring password;
-static pstring username;
-static pstring owner_username;
-static fstring server;
-static int got_pass;
-static int test_args;
-static TALLOC_CTX *ctx;
+static int test_args = False;
#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 int 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};
{ NULL, 0 },
};
-static struct cli_state *global_hack_cli;
-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)
+static NTSTATUS cli_lsa_lookup_sid(struct cli_state *cli,
+ const DOM_SID *sid,
+ TALLOC_CTX *mem_ctx,
+ enum lsa_SidType *type,
+ char **domain, char **name)
{
- /* Initialise cli LSA connection */
+ uint16 orig_cnum = cli->cnum;
+ struct rpc_pipe_client *p;
+ struct policy_handle handle;
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ enum lsa_SidType *types;
+ char **domains;
+ char **names;
- if (!global_hack_cli) {
- global_hack_cli = connect_one("IPC$");
- if (!cli_nt_session_open (global_hack_cli, PI_LSARPC)) {
- return False;
- }
+ if (!cli_send_tconX(cli, "IPC$", "?????", "", 0)) {
+ return cli_nt_error(cli);
+ }
+
+ p = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
+ if (p == NULL) {
+ goto fail;
}
-
- /* Open policy handle */
- if (!got_policy_hnd) {
+ status = rpccli_lsa_open_policy(p, talloc_tos(), True,
+ GENERIC_EXECUTE_ACCESS, &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
- /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
- but NT sends 0x2000000 so we might as well do it too. */
+ status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
+ &domains, &names, &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
- if (!NT_STATUS_IS_OK(cli_lsa_open_policy(global_hack_cli, global_hack_cli->mem_ctx, True,
- GENERIC_EXECUTE_ACCESS, &pol))) {
- return False;
- }
+ *type = types[0];
+ *domain = talloc_move(mem_ctx, &domains[0]);
+ *name = talloc_move(mem_ctx, &names[0]);
+
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(p);
+ cli_tdis(cli);
+ cli->cnum = orig_cnum;
+ TALLOC_FREE(frame);
+ return status;
+}
- got_policy_hnd = True;
+static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
+ const char *name,
+ enum lsa_SidType *type,
+ DOM_SID *sid)
+{
+ uint16 orig_cnum = cli->cnum;
+ struct rpc_pipe_client *p;
+ struct policy_handle handle;
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ DOM_SID *sids;
+ enum lsa_SidType *types;
+
+ if (!cli_send_tconX(cli, "IPC$", "?????", "", 0)) {
+ return cli_nt_error(cli);
}
-
- return True;
+
+ p = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
+ if (p == NULL) {
+ goto fail;
+ }
+
+ status = rpccli_lsa_open_policy(p, talloc_tos(), True,
+ GENERIC_EXECUTE_ACCESS, &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
+ NULL, 1, &sids, &types);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ *type = types[0];
+ *sid = sids[0];
+
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(p);
+ cli_tdis(cli);
+ cli->cnum = orig_cnum;
+ TALLOC_FREE(frame);
+ return status;
}
/* convert a SID to a string, either numeric or username/group */
-static void SidToString(fstring str, DOM_SID *sid)
+static void SidToString(struct cli_state *cli, fstring str, const DOM_SID *sid)
{
- char **domains = NULL;
- char **names = NULL;
- uint32 *types = NULL;
+ char *domain = NULL;
+ char *name = NULL;
+ enum lsa_SidType type;
+ NTSTATUS status;
- sid_to_string(str, sid);
+ sid_to_fstring(str, sid);
- if (numeric) return;
+ if (numeric) {
+ return;
+ }
- /* Ask LSA to convert the sid to a name */
+ status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
+ &domain, &name);
- if (!cacls_open_policy_hnd() ||
- !NT_STATUS_IS_OK(cli_lsa_lookup_sids(global_hack_cli, global_hack_cli->mem_ctx,
- &pol, 1, sid, &domains,
- &names, &types)) ||
- !domains || !domains[0] || !names || !names[0]) {
+ if (!NT_STATUS_IS_OK(status)) {
return;
}
- /* Converted OK */
-
slprintf(str, sizeof(fstring) - 1, "%s%s%s",
- domains[0], lp_winbind_separator(),
- names[0]);
+ domain, lp_winbind_separator(), name);
}
/* convert a string to a SID, either numeric or username/group */
-static BOOL StringToSid(DOM_SID *sid, const char *str)
+static bool StringToSid(struct cli_state *cli, DOM_SID *sid, const char *str)
{
- uint32 *types = NULL;
- DOM_SID *sids = NULL;
- BOOL result = True;
+ enum lsa_SidType type;
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(global_hack_cli, global_hack_cli->mem_ctx,
- &pol, 1, &str, &sids,
- &types))) {
- result = False;
- goto done;
- }
-
- sid_copy(sid, &sids[0]);
- done:
-
- return result;
+ return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid));
}
/* print an ACE on a FILE, using either numeric or ascii representation */
-static void print_ace(FILE *f, SEC_ACE *ace)
+static void print_ace(struct cli_state *cli, FILE *f, SEC_ACE *ace)
{
const struct perm_value *v;
fstring sidstr;
int do_print = 0;
uint32 got_mask;
- SidToString(sidstr, &ace->trustee);
+ SidToString(cli, 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;
}
/* 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(struct cli_state *cli, SEC_ACE *ace,
+ const char *orig_str)
{
char *p;
const char *cp;
- fstring tok;
- unsigned atype, aflags, amask;
+ char *tok;
+ 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);
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!str) {
+ TALLOC_FREE(frame);
+ 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);
+ TALLOC_FREE(frame);
+ return False;
+ }
*p = '\0';
p++;
/* Try to parse numeric form */
if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
- StringToSid(&sid, str)) {
+ StringToSid(cli, &sid, str)) {
goto done;
}
/* Try to parse text form */
- if (!StringToSid(&sid, str)) {
+ if (!StringToSid(cli, &sid, str)) {
+ printf("ACE '%s': failed to convert '%s' to SID\n",
+ orig_str, str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
return False;
}
cp = p;
- if (!next_token(&cp, tok, "/", sizeof(fstring))) {
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ printf("ACE '%s': failed to find '/' character.\n",
+ orig_str);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
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);
+ TALLOC_FREE(frame);
return False;
}
/* Only numeric form accepted for flags at present */
- if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
+ if (!(next_token_talloc(frame, &cp, &tok, "/") &&
sscanf(tok, "%i", &aflags))) {
+ printf("ACE '%s': bad integer flags entry at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
return False;
}
- if (!next_token(&cp, tok, "/", sizeof(fstring))) {
+ if (!next_token_talloc(frame, &cp, &tok, "/")) {
+ printf("ACE '%s': missing / at '%s'\n",
+ orig_str, tok);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
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);
+ TALLOC_FREE(frame);
return False;
}
goto done;
p = tok;
while(*p) {
- BOOL found = False;
+ bool found = False;
for (v = special_values; v->perm; v++) {
if (v->perm[0] == *p) {
}
}
- if (!found) return False;
+ if (!found) {
+ printf("ACE '%s': bad permission value at '%s'\n",
+ orig_str, p);
+ SAFE_FREE(str);
+ TALLOC_FREE(frame);
+ return False;
+ }
p++;
}
if (*p) {
+ TALLOC_FREE(frame);
+ SAFE_FREE(str);
return False;
}
done:
- mask.mask = amask;
+ mask = amask;
init_sec_ace(ace, &sid, atype, mask, aflags);
+ TALLOC_FREE(frame);
+ 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)
+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(talloc_tos(), 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(talloc_tos(),(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
SAFE_FREE(aces);
- (*the_acl) = new;
+ (*the_acl) = new_ace;
return True;
}
/* parse a ascii version of a security descriptor */
-static SEC_DESC *sec_desc_parse(char *str)
+static SEC_DESC *sec_desc_parse(TALLOC_CTX *ctx, struct cli_state *cli, char *str)
{
const char *p = str;
- fstring tok;
- SEC_DESC *ret;
+ char *tok;
+ SEC_DESC *ret = NULL;
size_t sd_size;
DOM_SID *grp_sid=NULL, *owner_sid=NULL;
SEC_ACL *dacl=NULL;
int revision=1;
- while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
-
+ while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
if (strncmp(tok,"REVISION:", 9) == 0) {
revision = strtol(tok+9, NULL, 16);
continue;
}
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)) {
+ !StringToSid(cli, 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)) {
+ !StringToSid(cli, 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;
+ if (!parse_ace(cli, &ace, tok+4)) {
+ 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);
/* print a ascii version of a security descriptor on a FILE handle */
-static void sec_desc_print(FILE *f, SEC_DESC *sd)
+static void sec_desc_print(struct cli_state *cli, FILE *f, SEC_DESC *sd)
{
fstring sidstr;
uint32 i;
- printf("REVISION:%d\n", sd->revision);
+ fprintf(f, "REVISION:%d\n", sd->revision);
/* Print owner and group sid */
if (sd->owner_sid) {
- SidToString(sidstr, sd->owner_sid);
+ SidToString(cli, sidstr, sd->owner_sid);
} else {
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(cli, 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);
+ print_ace(cli, f, ace);
fprintf(f, "\n");
}
goto done;
}
- sd = cli_query_secdesc(cli, fnum, ctx);
+ sd = cli_query_secdesc(cli, fnum, talloc_tos());
if (!sd) {
printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
goto done;
}
- sec_desc_print(stdout, sd);
+ sec_desc_print(cli, stdout, sd);
result = EXIT_OK;
*******************************************************/
static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
- char *filename, char *new_username)
+ const char *filename, const char *new_username)
{
int fnum;
DOM_SID sid;
return EXIT_FAILED;
}
- if (!StringToSid(&sid, new_username))
+ if (!StringToSid(cli, &sid, new_username))
return EXIT_PARSE_ERROR;
- old = cli_query_secdesc(cli, fnum, ctx);
+ old = cli_query_secdesc(cli, fnum, talloc_tos());
cli_close(cli, fnum);
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(talloc_tos(),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));
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 {
size_t sd_size;
int result = EXIT_OK;
- sd = sec_desc_parse(the_acl);
+ sd = sec_desc_parse(talloc_tos(), cli, the_acl);
if (!sd) return EXIT_PARSE_ERROR;
if (test_args) return EXIT_OK;
return EXIT_FAILED;
}
- old = cli_query_secdesc(cli, fnum, ctx);
+ old = cli_query_secdesc(cli, fnum, talloc_tos());
if (!old) {
printf("calc_set: Failed to query old descriptor\n");
switch (mode) {
case SMB_ACL_DELETE:
for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
- BOOL found = False;
+ 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(cli, stdout, &sd->dacl->aces[i]);
printf(" not found\n");
}
}
case SMB_ACL_MODIFY:
for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
- BOOL found = False;
+ 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(cli, 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, old->owner_sid, old->grp_sid,
+
+ /* 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(talloc_tos(),old->revision, old->type,
+ old->owner_sid, old->group_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);
if (fnum == -1) {
printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
}
-/*****************************************************
-return a connection to a server
+/*****************************************************
+ Return a connection to a server.
*******************************************************/
-static struct cli_state *connect_one(const char *share)
+static struct cli_state *connect_one(const char *server, const char *share)
{
- struct cli_state *c;
- struct in_addr ip;
+ struct cli_state *c = NULL;
+ struct sockaddr_storage ss;
NTSTATUS nt_status;
- zero_ip(&ip);
-
- if (!got_pass) {
+ zero_addr(&ss);
+
+ if (!get_cmdline_auth_info_got_pass()) {
char *pass = getpass("Password: ");
if (pass) {
- fstrcpy(password, pass);
- got_pass = True;
+ set_cmdline_auth_info_password(pass);
}
}
- if (NT_STATUS_IS_OK(nt_status = cli_full_connection(&c, global_myname(), server,
- &ip, 0,
- share, "?????",
- username, lp_workgroup(),
- password, 0, NULL))) {
- return c;
- } else {
+ nt_status = cli_full_connection(&c, global_myname(), server,
+ &ss, 0,
+ share, "?????",
+ get_cmdline_auth_info_username(),
+ lp_workgroup(),
+ get_cmdline_auth_info_password(),
+ get_cmdline_auth_info_use_kerberos() ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
+ get_cmdline_auth_info_signing_state(),
+ NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
return NULL;
}
-}
+ if (get_cmdline_auth_info_smb_encrypt()) {
+ nt_status = cli_cm_force_encryption(c,
+ get_cmdline_auth_info_username(),
+ get_cmdline_auth_info_password(),
+ lp_workgroup(),
+ share);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(c);
+ c = NULL;
+ }
+ }
-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\
-");
+ return c;
}
/****************************************************************************
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;
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;
+ char *path;
+ char *filename = NULL;
+ 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;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *owner_username = "";
+ char *server;
- ctx=talloc_init("main");
+ load_case_tables();
- setlinebuf(stdout);
+ /* 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;
+ setlinebuf(stdout);
- lp_load(dyn_CONFIGFILE,True,False,False);
+ lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
load_interfaces();
- if (getenv("USER")) {
- pstrcpy(username,getenv("USER"));
+ pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
- if ((p=strchr_m(username,'%'))) {
- *p = 0;
- fstrcpy(password,p+1);
- got_pass = True;
- memset(strchr_m(getenv("USER"), '%') + 1, 'X',
- strlen(password));
- }
- }
+ 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;
- fstrcpy(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);
+ owner_username = poptGetOptArg(pc);
change_mode = REQUEST_CHOWN;
break;
case 'G':
- pstrcpy(owner_username,optarg);
+ 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;
+ /* Make connection to server */
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
- default:
- printf("Unknown option %c (%d)\n", (char)opt, opt);
- talloc_destroy(ctx);
- exit(EXIT_PARSE_ERROR);
- }
+ path = talloc_strdup(frame, poptGetArg(pc));
+ if (!path) {
+ return -1;
}
- argc -= optind;
- argv += optind;
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
- if (argc > 0) {
- usage();
- talloc_destroy(ctx);
- exit(EXIT_PARSE_ERROR);
+ filename = talloc_strdup(frame, poptGetArg(pc));
+ if (!filename) {
+ return -1;
}
- /* Make connection to server */
+ string_replace(path,'/','\\');
- fstrcpy(server,share+2);
+ server = talloc_strdup(frame, path+2);
+ if (!server) {
+ return -1;
+ }
share = strchr_m(server,'\\');
if (!share) {
- share = strchr_m(server,'/');
- if (!share) {
- return -1;
- }
+ printf("Invalid argument: %s\n", share);
+ return -1;
}
*share = 0;
share++;
if (!test_args) {
- cli = connect_one(share);
+ cli = connect_one(server, share);
if (!cli) {
- talloc_destroy(ctx);
exit(EXIT_FAILED);
}
} else {
exit(0);
}
- all_string_sub(filename, "/", "\\", 0);
+ string_replace(filename, '/', '\\');
if (filename[0] != '\\') {
- pstring s;
- s[0] = '\\';
- safe_strcpy(&s[1], filename, sizeof(pstring)-2);
- pstrcpy(filename, s);
+ filename = talloc_asprintf(frame,
+ "\\%s",
+ filename);
+ if (!filename) {
+ return -1;
+ }
}
/* Perform requested action */
result = cacl_dump(cli, filename);
}
- talloc_destroy(ctx);
+ TALLOC_FREE(frame);
return result;
}
-