PATCH smbcacls

Nigel Williams nigel at veritas.com
Mon Jan 21 17:42:03 GMT 2002


This patch allows smbcacls to modify share permissions

nigel
-------------- next part --------------
Index: utils/smbcacls.c
===================================================================
RCS file: /cvsroot/samba/source/utils/smbcacls.c,v
retrieving revision 1.63
diff -u -r1.63 smbcacls.c
--- utils/smbcacls.c	20 Jan 2002 01:24:59 -0000	1.63
+++ utils/smbcacls.c	22 Jan 2002 01:24:17 -0000
@@ -6,6 +6,7 @@
    Copyright (C) Andrew Tridgell 2000
    Copyright (C) Tim Potter      2000
    Copyright (C) Jeremy Allison  2000
+   Copyright (C) Nigel Williams  2001
    
    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
@@ -27,7 +28,6 @@
 static fstring password;
 static pstring username;
 static pstring owner_username;
-static fstring server;
 static int got_pass;
 static int test_args;
 TALLOC_CTX *ctx;
@@ -35,418 +35,234 @@
 #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;
-
-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;
-	uint32 mask;
-};
-
-/* These values discovered by inspection */
-
-static struct perm_value special_values[] = {
-	{ "R", 0x00120089 },
-	{ "W", 0x00120116 },
-	{ "X", 0x001200a0 },
-	{ "D", 0x00010000 },
-	{ "P", 0x00040000 },
-	{ "O", 0x00080000 },
-	{ NULL, 0 },
-};
-
-static 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;
 
-/* Open cli connection and policy handle */
+/***************************************************** 
+set the ACLs on a share given an ascii description
+*******************************************************/
 
-static BOOL cacls_open_policy_hnd(void)
-{
-	creds.pwd.null_pwd = 1;
+static int cacl_acl_update_share(struct cli_state *cli, 
+				 char *netname, 
+				 SEC_DESC **sd,
+				 enum acl_mode mode,
+				 enum chown_mode change_mode,
+				 DOM_SID *sid
+	)
+{
+        int sd_size;
+	SEC_DESC *old;
+	SRV_SHARE_INFO share_info;
+	uint32 parm_error = 0;
+	int result = EXIT_OK;
+	NTSTATUS status;
 
-	/* Initialise cli LSA connection */
+	if (test_args) return EXIT_OK;
 
-	if (!lsa_cli.initialised && 
-	    !cli_lsa_initialise(&lsa_cli, server, &creds)) {
-		return False;
-	}
+	cli_nt_session_open(cli, PIPE_SRVSVC);
 
-	/* Open policy handle */
+	ZERO_STRUCT(share_info);
 
-	if (!got_policy_hnd) {
+	share_info.switch_value = 502;
 
-		/* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
-		   but NT sends 0x2000000 so we might as well do it too. */
+	status = cli_srvsvc_net_share_get_info(cli, 
+					       ctx,
+					       cli->desthost,
+					       netname,
+					       &share_info
+		);
 
-		if (!NT_STATUS_IS_OK(cli_lsa_open_policy(&lsa_cli, lsa_cli.mem_ctx, True, 
-							 GENERIC_EXECUTE_ACCESS, &pol))) {
-			return False;
-		}
+	if(!NT_STATUS_IS_OK(status)) {
 
-		got_policy_hnd = True;
+		DEBUG(0, ("cli_srvsvc_net_share_get_info failed. %s.\n", get_nt_error_msg(status)));
+		cli_nt_session_close(cli);
+		return EXIT_FAILED;
 	}
-	
-	return True;
-}
 
-/* 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;
+	old = (share_info.share.info502.info_502.ptr_sd)?share_info.share.info502.info_502_str.sd:NULL;
 
-	sid_to_string(str, sid);
+	if (!old) {
+		printf("calc_set: Failed to query old descriptor\n");
+		cli_nt_session_close(cli);
+		return EXIT_FAILED;
+	}
 
-	if (numeric) return;
+	smbcacl_lib_acl_update(&old, sd, ctx, &sd_size, mode, change_mode, sid);
 
-	/* Ask LSA to convert the sid to a name */
+	ZERO_STRUCT(share_info);
 
-	if (!cacls_open_policy_hnd() ||
-	    !NT_STATUS_IS_OK(cli_lsa_lookup_sids(&lsa_cli, lsa_cli.mem_ctx,  
-						 &pol, 1, sid, &domains, &names, 
-						 &types, &num_names)) ||
-	    !domains || !domains[0] || !names || !names[0]) {
-		return;
-	}
+	share_info.switch_value  = 1501;
+	share_info.ptr_share_ctr = 1;
 
-	/* Converted OK */
+	share_info.share.info1501.sdb = make_sec_desc_buf(ctx, sd_size, *sd);
 
-	slprintf(str, sizeof(fstring) - 1, "%s%s%s",
-		 domains[0], lp_winbind_separator(),
-		 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;
-	DOM_SID *sids = NULL;
-	int num_sids;
-	BOOL result = True;
-	fstring name, domain;
-	
-	if (strncmp(str, "S-", 2) == 0) {
-		return string_to_sid(sid, str);
-	}
+	status = cli_srvsvc_net_share_set_info(cli, 
+					       ctx,
+					       cli->desthost,
+					       netname,
+					       &share_info,
+					       &parm_error
+		);
 
-	split_domain_name(str, domain, name);
+	if(!NT_STATUS_IS_OK(status)) {
 
-	if (!cacls_open_policy_hnd() ||
-	    !NT_STATUS_IS_OK(cli_lsa_lookup_names(&lsa_cli, lsa_cli.mem_ctx, &pol, 1, 
-						  (const char **)&domain, (const char **)&name, 
-						  &sids, &types, &num_sids))) {
-		result = False;
-		goto done;
+		DEBUG(0, ("cli_srvsvc_net_share_set_info failed. %s. parm %d\n", get_nt_error_msg(status), parm_error));
+		cli_nt_session_close(cli);
+		return EXIT_FAILED;
 	}
 
-	sid_copy(sid, &sids[0]);
+	/* Clean up */
 
- done:
+	cli_nt_session_close(cli);
 
 	return result;
 }
 
+/***************************************************** 
+dump the acls for a share
+*******************************************************/
 
-/* print an ACE on a FILE, using either numeric or ascii representation */
-static void print_ace(FILE *f, SEC_ACE *ace)
+static int cacl_dump_share(struct cli_state *cli, char *netname)
 {
-	struct perm_value *v;
-	fstring sidstr;
-	int do_print = 0;
-	uint32 got_mask;
+        int result;
+	SRV_SHARE_INFO share_info;
+	SEC_DESC *sd;
+	NTSTATUS status;
 
-	SidToString(sidstr, &ace->trustee);
+	if (test_args) return EXIT_OK;
 
-	fprintf(f, "%s:", sidstr);
+	cli_nt_session_open(cli, PIPE_SRVSVC);
 
-	if (numeric) {
-		fprintf(f, "%d/%d/0x%08x", 
-			ace->type, ace->flags, ace->info.mask);
-		return;
-	}
+	ZERO_STRUCT(share_info);
 
-	/* Ace type */
+	share_info.switch_value = 502;
 
-	if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
-		fprintf(f, "ALLOWED");
-	} else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
-		fprintf(f, "DENIED");
-	} else {
-		fprintf(f, "%d", ace->type);
-	}
+	status = cli_srvsvc_net_share_get_info(cli, 
+					       ctx,
+					       cli->desthost,
+					       netname,
+					       &share_info
+		);
 
-	/* Not sure what flags can be set in a file ACL */
+	if(!NT_STATUS_IS_OK(status)) {
 
-	fprintf(f, "/%d/", ace->flags);
+		DEBUG(0, ("cli_srvsvc_net_share_get_info failed. %s.\n", get_nt_error_msg(status)));
+		cli_nt_session_close(cli);
+		return EXIT_FAILED;
+	}
 
-	/* Standard permissions */
+	sd = (share_info.share.info502.info_502.ptr_sd)?share_info.share.info502.info_502_str.sd:NULL;
 
-	for (v = standard_values; v->perm; v++) {
-		if (ace->info.mask == v->mask) {
-			fprintf(f, "%s", v->perm);
-			return;
-		}
+	if (!sd) {
+		printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
+		cli_nt_session_close(cli);
+		return EXIT_FAILED;
 	}
 
-	/* Special permissions.  Print out a hex value if we have
-	   leftover bits in the mask. */
+	smbcacl_lib_sec_desc_print(stdout, sd);
 
-	got_mask = ace->info.mask;
+	cli_nt_session_close(cli);
 
- again:
-	for (v = special_values; v->perm; v++) {
-		if ((ace->info.mask & v->mask) == v->mask) {
-			if (do_print) {
-				fprintf(f, "%s", v->perm);
-			}
-			got_mask &= ~v->mask;
-		}
-	}
-
-	if (!do_print) {
-		if (got_mask != 0) {
-			fprintf(f, "0x%08x", ace->info.mask);
-		} else {
-			do_print = 1;
-			goto again;
-		}
-	}
+	return EXIT_OK;
 }
 
+/*
+ * It is interesting to note that 
+ * NetShareEnumSticky will return owner and group sids within sds at level 502
+ * NetShareEnum, NetShareGetInfo however return null offsets to owner and groups sids for the same shares
+ *
+ */
 
-/* parse an ACE in the same format as print_ace() */
-static BOOL parse_ace(SEC_ACE *ace, char *str)
+static int owner_set_share(struct cli_state *cli, char *netname, char *new_username, enum chown_mode change_mode)
 {
-	char *p;
-	fstring tok;
-	unsigned atype, aflags, amask;
 	DOM_SID sid;
-	SEC_ACCESS mask;
-	struct perm_value *v;
-
-	ZERO_STRUCTP(ace);
-	p = strchr_m(str,':');
-	if (!p) return False;
-	*p = '\0';
-	p++;
+	SEC_DESC *sd = NULL;
+	enum acl_mode mode = SMB_ACL_NONE;
 
-	/* Try to parse numeric form */
-
-	if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
-	    StringToSid(&sid, str)) {
-		goto done;
-	}
-
-	/* Try to parse text form */
-
-	if (!StringToSid(&sid, str)) {
-		return False;
-	}
-
-	if (!next_token(&p, tok, "/", sizeof(fstring))) {
-		return False;
-	}
-
-	if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
-		atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
-	} else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
-		atype = SEC_ACE_TYPE_ACCESS_DENIED;
-	} else {
-		return False;
-	}
-
-	/* Only numeric form accepted for flags at present */
-
-	if (!(next_token(&p, tok, "/", sizeof(fstring)) &&
-	      sscanf(tok, "%i", &aflags))) {
-		return False;
-	}
-
-	if (!next_token(&p, tok, "/", sizeof(fstring))) {
-		return False;
-	}
-
-	if (strncmp(tok, "0x", 2) == 0) {
-		if (sscanf(tok, "%i", &amask) != 1) {
-			return False;
-		}
-		goto done;
-	}
-
-	for (v = standard_values; v->perm; v++) {
-		if (strcmp(tok, v->perm) == 0) {
-			amask = v->mask;
-			goto done;
-		}
-	}
-
-	p = tok;
+	if (!smbcacl_lib_StringToSid(&sid, new_username))
+		return EXIT_PARSE_ERROR;
 
-	while(*p) {
-		BOOL found = False;
+	return cacl_acl_update_share(cli, netname, &sd, mode, change_mode, &sid);
+}
 
-		for (v = special_values; v->perm; v++) {
-			if (v->perm[0] == *p) {
-				amask |= v->mask;
-				found = True;
-			}
-		}
+static int cacl_set_share(struct cli_state *cli, char *netname, char *the_acl, enum acl_mode mode)
+{
+        DOM_SID *sid = NULL;
+	SEC_DESC *sd = NULL;
+	enum chown_mode change_mode = REQUEST_NONE;
 
-		if (!found) return False;
-		p++;
-	}
+	if(!smbcacl_lib_sec_desc_parse(ctx, the_acl, &sd))
+		return EXIT_PARSE_ERROR;
 
-	if (*p) {
-		return False;
-	}
+	if (test_args) return EXIT_OK;
 
- done:
-	mask.mask = amask;
-	init_sec_ace(ace, &sid, atype, mask, aflags);
-	return True;
+	return cacl_acl_update_share(cli, netname, &sd, mode, change_mode, sid);
 }
 
-/* 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_ACE *aces;
-	if (! *the_acl) {
-		(*the_acl) = make_sec_acl(ctx, 3, 1, ace);
-		return True;
-	}
-
-	aces = calloc(1+(*the_acl)->num_aces,sizeof(SEC_ACE));
-	memcpy(aces, (*the_acl)->ace, (*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);
-	SAFE_FREE(aces);
-	(*the_acl) = new;
-	return True;
-}
+/***************************************************** 
+set the ACLs on a file given an ascii description
+*******************************************************/
 
-/* parse a ascii version of a security descriptor */
-static SEC_DESC *sec_desc_parse(char *str)
+static int cacl_acl_update_file(struct cli_state *cli, 
+				char *filename, 
+				SEC_DESC **sd,
+				enum acl_mode mode,
+				enum chown_mode change_mode,
+				DOM_SID *sid
+	)
 {
-	char *p = str;
-	fstring tok;
-	SEC_DESC *ret;
+	int fnum;
+	SEC_DESC *old;
 	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))) {
-
-		if (strncmp(tok,"REVISION:", 9) == 0) {
-			revision = strtol(tok+9, NULL, 16);
-			continue;
-		}
+	int result = EXIT_OK;
 
-		if (strncmp(tok,"OWNER:", 6) == 0) {
-			owner_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
-			if (!owner_sid ||
-			    !StringToSid(owner_sid, tok+6)) {
-				printf("Failed to parse owner sid\n");
-				return NULL;
-			}
-			continue;
-		}
+	if (test_args) return EXIT_OK;
 
-		if (strncmp(tok,"GROUP:", 6) == 0) {
-			grp_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
-			if (!grp_sid ||
-			    !StringToSid(grp_sid, tok+6)) {
-				printf("Failed to parse group sid\n");
-				return NULL;
-			}
-			continue;
-		}
+	/* The desired access below is the only one I could find that works
+	   with NT4, W2KP and Samba */
 
-		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(!add_ace(&dacl, &ace)) {
-				printf("Failed to add ACL %s\n", tok);
-				return NULL;
-			}
-			continue;
-		}
+	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
 
-		printf("Failed to parse security descriptor\n");
-		return NULL;
+	if (fnum == -1) {
+		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+		return EXIT_FAILED;
 	}
 
-	ret = make_sec_desc(ctx,revision, owner_sid, grp_sid, 
-			    NULL, dacl, &sd_size);
-
-	SAFE_FREE(grp_sid);
-	SAFE_FREE(owner_sid);
-
-	return ret;
-}
+	old = cli_query_secdesc(cli, fnum, ctx);
 
+	if (!old) {
+		printf("calc_set: Failed to query old descriptor\n");
+		return EXIT_FAILED;
+	}
 
-/* print a ascii version of a security descriptor on a FILE handle */
-static void sec_desc_print(FILE *f, SEC_DESC *sd)
-{
-	fstring sidstr;
-	int i;
+	cli_close(cli, fnum);
 
-	printf("REVISION:%d\n", sd->revision);
+	smbcacl_lib_acl_update(&old, sd, ctx, &sd_size, mode, change_mode, sid);
 
-	/* Print owner and group sid */
+	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
 
-	if (sd->owner_sid) {
-		SidToString(sidstr, sd->owner_sid);
-	} else {
-		fstrcpy(sidstr, "");
+	if (fnum == -1) {
+		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+		return EXIT_FAILED;
 	}
 
-	printf("OWNER:%s\n", sidstr);
-
-	if (sd->grp_sid) {
-		SidToString(sidstr, sd->grp_sid);
-	} else {
-		fstrcpy(sidstr, "");
+	if (!cli_set_secdesc(cli, fnum, *sd)) {
+		printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
+		result = EXIT_FAILED;
 	}
 
-	fprintf(f, "GROUP:%s\n", sidstr);
+	/* Clean up */
 
-	/* Print aces */
-	for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
-		SEC_ACE *ace = &sd->dacl->ace[i];
-		fprintf(f, "ACL:");
-		print_ace(f, ace);
-		fprintf(f, "\n");
-	}
+	cli_close(cli, fnum);
 
+	return result;
 }
 
 /***************************************************** 
 dump the acls for a file
 *******************************************************/
-static int cacl_dump(struct cli_state *cli, char *filename)
+
+static int cacl_dump_file(struct cli_state *cli, char *filename)
 {
 	int fnum;
 	SEC_DESC *sd;
@@ -466,7 +282,7 @@
 		return EXIT_FAILED;
 	}
 
-	sec_desc_print(stdout, sd);
+	smbcacl_lib_sec_desc_print(stdout, sd);
 
 	cli_close(cli, fnum);
 
@@ -478,252 +294,86 @@
 because the NT docs say this can't be done :-). JRA.
 *******************************************************/
 
-static int owner_set(struct cli_state *cli, enum chown_mode change_mode, 
-		     char *filename, char *new_username)
+static int owner_set_file(struct cli_state *cli, char *filename, char *new_username, enum chown_mode change_mode)
 {
-	int fnum;
 	DOM_SID sid;
-	SEC_DESC *sd, *old;
-	size_t sd_size;
-
-	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+	SEC_DESC *sd = NULL;
+	enum acl_mode mode = SMB_ACL_NONE;
 
-	if (fnum == -1) {
-		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
-		return EXIT_FAILED;
-	}
-
-	if (!StringToSid(&sid, new_username))
+	if (!smbcacl_lib_StringToSid(&sid, new_username))
 		return EXIT_PARSE_ERROR;
 
-	old = cli_query_secdesc(cli, fnum, ctx);
-
-	cli_close(cli, fnum);
-
-	if (!old) {
-		printf("owner_set: Failed to query old descriptor\n");
-		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);
-
-	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
-
-	if (fnum == -1) {
-		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
-		return EXIT_FAILED;
-	}
-
-	if (!cli_set_secdesc(cli, fnum, sd)) {
-		printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
-	}
-
-	cli_close(cli, fnum);
-
-	return EXIT_OK;
+	return cacl_acl_update_file(cli, filename, &sd, mode, change_mode, &sid);
 }
 
-
-/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
-   However NT4 gives a "The information may have been modified by a
-   computer running Windows NT 5.0" if denied ACEs do not appear before
-   allowed ACEs. */
-
-static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
+static int cacl_set_file(struct cli_state *cli, char *filename, char *the_acl, enum acl_mode mode)
 {
-	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->info.mask != ace2->info.mask) 
-		return ace1->info.mask - ace2->info.mask;
-
-	if (ace1->size != ace2->size) 
-		return ace1->size - ace2->size;
-
-	return memcmp(ace1, ace2, sizeof(SEC_ACE));
-}
+        DOM_SID *sid = NULL;
+	SEC_DESC *sd = NULL;
+	enum chown_mode change_mode = REQUEST_NONE;
 
-static void sort_acl(SEC_ACL *the_acl)
-{
-	int i;
-	if (!the_acl) return;
+	if(!smbcacl_lib_sec_desc_parse(ctx, the_acl, &sd))
+		return EXIT_PARSE_ERROR;
 
-	qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]), QSORT_CAST ace_compare);
+	if (test_args) return EXIT_OK;
 
-	for (i=1;i<the_acl->num_aces;) {
-		if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
-			int j;
-			for (j=i; j<the_acl->num_aces-1; j++) {
-				the_acl->ace[j] = the_acl->ace[j+1];
-			}
-			the_acl->num_aces--;
-		} else {
-			i++;
-		}
-	}
+	return cacl_acl_update_file(cli, filename, &sd, mode, change_mode, sid);
 }
 
 /***************************************************** 
-set the ACLs on a file given an ascii description
+return a connection to a server
 *******************************************************/
-static int cacl_set(struct cli_state *cli, char *filename, 
-		    char *the_acl, enum acl_mode mode)
-{
-	int fnum;
-	SEC_DESC *sd, *old;
-	int i, j;
-	size_t sd_size;
-	int result = EXIT_OK;
-
-	sd = sec_desc_parse(the_acl);
-
-	if (!sd) return EXIT_PARSE_ERROR;
-	if (test_args) return EXIT_OK;
-
-	/* The desired access below is the only one I could find that works
-	   with NT4, W2KP and Samba */
-
-	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
-
-	if (fnum == -1) {
-		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
-		return EXIT_FAILED;
-	}
-
-	old = cli_query_secdesc(cli, fnum, ctx);
-
-	if (!old) {
-		printf("calc_set: Failed to query old descriptor\n");
-		return EXIT_FAILED;
-	}
-
-	cli_close(cli, fnum);
-
-	/* the logic here is rather more complex than I would like */
-	switch (mode) {
-	case SMB_ACL_DELETE:
-		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-			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;
-					for (k=j; k<old->dacl->num_aces-1;k++) {
-						old->dacl->ace[k] = old->dacl->ace[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]);
-				printf(" not found\n");
-			}
-		}
-		break;
-
-	case SMB_ACL_MODIFY:
-		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-			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];
-					found = True;
-				}
-			}
-
-			if (!found) {
-				fstring str;
 
-				SidToString(str, &sd->dacl->ace[i].trustee);
-				printf("ACL for SID %s not found\n", str);
-			}
-		}
+struct cli_state *connect_one(const char *server, const char *service, char *service_type) 
+{
+	extern pstring global_myname;
 
-		break;
+	struct cli_state *c;
+	struct in_addr ip;
+	int port = 0;
+	NTSTATUS status;
 
-	case SMB_ACL_ADD:
-		for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-			add_ace(&old->dacl, &sd->dacl->ace[i]);
+	if (!got_pass) {
+		char *pass = getpass("Password: ");
+		if (pass) {
+			pstrcpy(password, pass);
 		}
-		break;
-
-	case SMB_ACL_SET:
- 		old = sd;
-		break;
 	}
 
-	/* Denied ACE entries must come before allowed ones */
-	sort_acl(old->dacl);
+	zero_ip(&ip);
 
-	/* Create new security descriptor and set it */
-	sd = make_sec_desc(ctx,old->revision, old->owner_sid, old->grp_sid, 
-			   NULL, old->dacl, &sd_size);
+	status = cli_full_connection(&c,
+				     global_myname,
+				     server,
+				     &ip, port,
+				     (char *)service, service_type,
+				     username, lp_workgroup(),
+				     password, strlen(password) + 1);
 
-	fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
+	if(!NT_STATUS_IS_OK(status)) {
 
-	if (fnum == -1) {
-		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
-		return EXIT_FAILED;
-	}
-
-	if (!cli_set_secdesc(cli, fnum, sd)) {
-		printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
-		result = EXIT_FAILED;
+		DEBUG(0, ("cli_full_connection to %s failed. %s.\n", service, get_nt_error_msg(status)));
+		return NULL;
 	}
 
-	/* Clean up */
-
-	cli_close(cli, fnum);
-
-	return result;
+	return c;
 }
 
+#if 0
 
-/***************************************************** 
-return a connection to a server
-*******************************************************/
-struct cli_state *connect_one(char *share)
+/* just a reminder of what used to be here. remove when code above is whoen to work */
+
+struct cli_state *connect_one(const char *server, const char *share)
 {
 	struct cli_state *c;
 	struct nmb_name called, calling;
 	struct in_addr ip;
 	extern pstring global_myname;
 
-	fstrcpy(server,share+2);
-	share = strchr_m(server,'\\');
-	if (!share) return NULL;
-	*share = 0;
-	share++;
-
         zero_ip(&ip);
 
 	make_nmb_name(&calling, global_myname, 0x0);
 	make_nmb_name(&called , server, 0x20);
-
  again:
         zero_ip(&ip);
 
@@ -752,7 +402,7 @@
 		return NULL;
 	}
 
-	if (!got_pass) {
+ 	if (!got_pass) {
 		char *pass = getpass("Password: ");
 		if (pass) {
 			pstrcpy(password, pass);
@@ -781,41 +431,65 @@
 
 	return c;
 }
-
+#endif
 
 static void usage(void)
 {
 	printf(
-"Usage: smbcacls //server1/share1 filename [options]\n\
+		"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-D <acls>               delete an ace from an acl\n\
+\t-M <acls>               modify an ace within an acl\n\
+\t-A <acls>               add an ace to an acl\n\
+\t-S <acls>               set entire acl\n\
+\t-C username             change ownership of the resource\n\
+\t-G username             change group ownership of the resource\n\
 \t-n                      don't resolve sids or masks to names\n\
+\t-N DC                   also attempt lsa name lookups from this server\n\
 \t-h                      print help\n\
 \t-d debuglevel           set debug output level\n\
-\t-U username             user to autheticate as\n\
+\t-U username             user to authenticate 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\
-");
+An ace is of the form ACE:<SID>:type/flags/mask\n\
+You can string aces together with spaces, commas or newlines\n\
+to form an acl");
 }
 
+enum RESOURCE_TAG {FILE_RESOURCE, SHARE_RESOURCE};
+
+static struct {
+
+	enum RESOURCE_TAG tag;
+
+	int (*owner_set)(struct cli_state *cli, char *resource_name, char *owner_name, enum chown_mode change_mode);
+	int   (*acl_set)(struct cli_state *cli, char *resource_name, char *acl_str,    enum acl_mode mode);
+	int   (*sd_dump)(struct cli_state *cli, char *resource_name);
+
+} cacl_fns[] = {
+
+	{FILE_RESOURCE,  owner_set_file,  cacl_set_file,  cacl_dump_file},
+	{SHARE_RESOURCE, owner_set_share, cacl_set_share, cacl_dump_share}
+};
+
+#define CALL(A, B, C) \
+((cacl_fns[(A)].tag == (A))?(cacl_fns[(A)].B C):(DEBUG(0, ("CALL tag %d != %d\n", (A), cacl_fns[(A)].tag)), EXIT_FAILED))
+
 /****************************************************************************
   main program
 ****************************************************************************/
- int main(int argc,char *argv[])
+int main(int argc,char *argv[])
 {
+        fstring server;
 	char *share;
-	pstring filename;
+	char *service      = "IPC$";
+	char *service_type = "IPC";
+	pstring resource_name = "";
+	int resource_index;
 	extern char *optarg;
 	extern int optind;
-	int opt;
+	int opt, opt_offset = 0;
 	char *p;
 	struct cli_state *cli=NULL;
 	enum acl_mode mode = SMB_ACL_SET;
@@ -829,20 +503,64 @@
 
 	dbf = x_stderr;
 
-	if (argc < 3 || argv[1][0] == '-') {
+	if (argc < 2 || argv[1][0] == '-') {
+		usage();
+		talloc_destroy(ctx);
+		exit(EXIT_PARSE_ERROR);
+	}
+
+	setup_logging(argv[opt_offset++],True);
+
+	share = argv[opt_offset++];
+	all_string_sub(share, "/", "\\", 0);
+
+	fstrcpy(server, share+2); 
+
+	share = strchr_m(server,'\\');
+
+	if (!share) {
 		usage();
 		talloc_destroy(ctx);
 		exit(EXIT_PARSE_ERROR);
 	}
 
-	setup_logging(argv[0],True);
+	*share = 0;
+
+	smbcacl_lib_server_set(server); /* this server will be used to resolve sid<->name */
+	
+	share++; /* advance past the \\ */
+
+	if(argc > 2 && argv[opt_offset][0] != '-') {
+
+		/* a file resource has been specified */
+	  
+		pstrcpy(resource_name, argv[opt_offset++]);
+
+		all_string_sub(resource_name, "/", "\\", 0);
+		if (resource_name[0] != '\\') {
+			pstring s;
+			s[0] = '\\';
+			safe_strcpy(&s[1], resource_name, sizeof(pstring)-1);
+			pstrcpy(resource_name, s);
+		}
+
+		service      = share;
+		service_type = "?????";
+
+		resource_index = FILE_RESOURCE;
+	} else {
+
+		/* we are operating on the share itself */
+
+		pstrcpy(resource_name, share);
 
-	share = argv[1];
-	pstrcpy(filename, argv[2]);
+		resource_index = SHARE_RESOURCE;
+	}
+	  
 	all_string_sub(share,"/","\\",0);
 
-	argc -= 2;
-	argv += 2;
+	argc -= opt_offset;
+	argv += opt_offset;
 
 	lp_load(dyn_CONFIGFILE,True,False,False);
 	load_interfaces();
@@ -859,7 +577,9 @@
 		}
 	}
 
-	while ((opt = getopt(argc, argv, "U:nhS:D:A:M:C:G:td:")) != EOF) {
+	optind = 0;
+
+	while ((opt = getopt(argc, argv, "U:nhS:D:A:M:C:G:td:N:")) != EOF) {
 		switch (opt) {
 		case 'U':
 			pstrcpy(username,optarg);
@@ -902,7 +622,11 @@
 			break;
 
 		case 'n':
-			numeric = 1;
+			smbcacl_lib_numeric_set(1);
+			break;
+
+		case 'N':
+			smbcacl_lib_DC_set(optarg);
 			break;
 
 		case 't':
@@ -937,29 +661,22 @@
 	/* Make connection to server */
 
 	if (!test_args) {
-		cli = connect_one(share);
+		cli = connect_one(server, service, service_type);
+
 		if (!cli) {
 			talloc_destroy(ctx);
 			exit(EXIT_FAILED);
 		}
 	}
 
-	all_string_sub(filename, "/", "\\", 0);
-	if (filename[0] != '\\') {
-		pstring s;
-		s[0] = '\\';
-		safe_strcpy(&s[1], filename, sizeof(pstring)-1);
-		pstrcpy(filename, s);
-	}
-
 	/* Perform requested action */
 
 	if (change_mode != REQUEST_NONE) {
-		result = owner_set(cli, change_mode, filename, owner_username);
+		result = CALL(resource_index, owner_set, (cli, resource_name, owner_username, change_mode));
 	} else if (the_acl) {
-		result = cacl_set(cli, filename, the_acl, mode);
+		result = CALL(resource_index,   acl_set, (cli, resource_name, the_acl, mode));
 	} else {
-		result = cacl_dump(cli, filename);
+		result = CALL(resource_index,   sd_dump, (cli, resource_name));
 	}
 
 	talloc_destroy(ctx);


More information about the samba-technical mailing list