[PATCH] smbcacls added support for a -I flag

Matthew McGillis matthew at mcgillis.org
Sat Apr 24 14:36:02 MDT 2010


Added support for a -I flag which provides the equivelant functionality of
setting or unsetting the windows file properity check box:

"Allow inheritable permissions from the parent to propagate to this object
and all child objects. Include these with entries explicitly defined here."

Hope this comes across correclty for git am this was generated from the v3-5-stable branch. Please let me know if you run into issues.

Regards
Matthew

---
 source3/utils/smbcacls.c |  268 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 199 insertions(+), 69 deletions(-)

diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c
index e1e37ae..4d000d5 100644
--- a/source3/utils/smbcacls.c
+++ b/source3/utils/smbcacls.c
@@ -36,7 +36,7 @@ static int numeric;
 static int sddl;
 
 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 chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP, REQUEST_INHERIT};
 enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
 
 struct perm_value {
@@ -63,6 +63,7 @@ static const struct perm_value standard_values[] = {
 	{ NULL, 0 },
 };
 
+
 /* Open cli connection and policy handle */
 
 static NTSTATUS cli_lsa_lookup_sid(struct cli_state *cli,
@@ -659,42 +660,115 @@ static void sec_desc_print(struct cli_state *cli, FILE *f, SEC_DESC *sd)
 }
 
 /***************************************************** 
-dump the acls for a file
+get fileinfo for filename
 *******************************************************/
-static int cacl_dump(struct cli_state *cli, char *filename)
+static uint16 get_fileinfo(struct cli_state *cli, char *filename)
+{
+	uint16_t fnum = (uint16_t)-1;
+	uint16 mode;
+
+	/* The desired access below is the only one I could find that works
+	   with NT4, W2KP and Samba */
+
+	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ,
+                                          0, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                          FILE_OPEN, 0x0, 0x0, &fnum))) {
+		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+	}
+
+	if (!cli_qfileinfo(cli, fnum, &mode, NULL, NULL, NULL,
+                                             NULL, NULL, NULL)) {
+		printf("Failed to file info %s: %s\n", filename,
+                                                       cli_errstr(cli));
+        }
+
+	cli_close(cli, fnum);
+
+        return mode;
+}
+
+/***************************************************** 
+get sec desc for filename
+*******************************************************/
+static SEC_DESC *get_secdesc(struct cli_state *cli, char *filename)
 {
-	int result = EXIT_FAILED;
 	uint16_t fnum = (uint16_t)-1;
 	SEC_DESC *sd;
 
-	if (test_args) 
-		return EXIT_OK;
+	/* The desired access below is the only one I could find that works
+	   with NT4, W2KP and Samba */
 
-	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ, 0,
-				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
+	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ,
+                                          0, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                          FILE_OPEN, 0x0, 0x0, &fnum))) {
 		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
-		goto done;
+		return NULL;
 	}
 
 	sd = cli_query_secdesc(cli, fnum, talloc_tos());
 
+	cli_close(cli, fnum);
+
 	if (!sd) {
-		printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
-		goto done;
+		printf("Failed to get security descriptor\n");
+		return NULL;
+	}
+        return sd;
+}
+
+/***************************************************** 
+set sec desc for filename
+*******************************************************/
+static bool set_secdesc(struct cli_state *cli, char *filename, SEC_DESC *sd)
+{
+        printf("set_secdesc\n");
+	uint16_t fnum = (uint16_t)-1;
+        bool result=true;
+
+	/* The desired access below is the only one I could find that works
+	   with NT4, W2KP and Samba */
+
+	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, 
+                                          WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS,
+                                          0, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                          FILE_OPEN, 0x0, 0x0, &fnum))) {
+		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+		return false;
 	}
 
-	if (sddl) {
-		printf("%s\n", sddl_encode(talloc_tos(), sd,
-					   get_global_sam_sid()));
-	} else {
-		sec_desc_print(cli, stdout, sd);
+	if (!cli_set_secdesc(cli, fnum, sd)) {
+		printf("ERROR: security description set failed: %s\n", 
+                       cli_errstr(cli));
+		cli_close(cli, fnum);
+		result=false;
 	}
 
-	result = EXIT_OK;
+	cli_close(cli, fnum);
+        printf("set_secdesc result=%d\n",result);
+	return result;
+}
 
-done:
-	if (fnum != (uint16_t)-1)
-		cli_close(cli, fnum);
+/***************************************************** 
+dump the acls for a file
+*******************************************************/
+static int cacl_dump(struct cli_state *cli, char *filename)
+{
+	int result = EXIT_FAILED;
+	SEC_DESC *sd;
+
+	if (test_args) 
+		return EXIT_OK;
+
+	sd = get_secdesc(cli, filename);
+
+	if (sd) {
+          if (sddl) {
+            printf("%s\n", sddl_encode(talloc_tos(), sd, get_global_sam_sid()));
+          } else {
+	    sec_desc_print(cli, stdout, sd);
+          }
+	  result = EXIT_OK;
+	}
 
 	return result;
 }
@@ -705,28 +779,19 @@ because the NT docs say this can't be done :-). JRA.
 *******************************************************/
 
 static int owner_set(struct cli_state *cli, enum chown_mode change_mode, 
-			const char *filename, const char *new_username)
+		     char *filename, const char *new_username)
 {
 	uint16_t fnum;
 	DOM_SID sid;
 	SEC_DESC *sd, *old;
 	size_t sd_size;
 
-	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ, 0,
-				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
-		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
-		return EXIT_FAILED;
-	}
-
 	if (!StringToSid(cli, &sid, new_username))
 		return EXIT_PARSE_ERROR;
 
-	old = cli_query_secdesc(cli, fnum, talloc_tos());
-
-	cli_close(cli, fnum);
+	old = get_secdesc(cli, filename);
 
 	if (!old) {
-		printf("owner_set: Failed to query old descriptor\n");
 		return EXIT_FAILED;
 	}
 
@@ -735,20 +800,10 @@ static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
 				(change_mode == REQUEST_CHGRP) ? &sid : NULL,
 			   NULL, NULL, &sd_size);
 
-	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, WRITE_OWNER_ACCESS, 0,
-			FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
-		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);
+	if (!set_secdesc(cli, filename, sd)) {
 		return EXIT_FAILED;
 	}
 
-	cli_close(cli, fnum);
-
 	return EXIT_OK;
 }
 
@@ -799,7 +854,7 @@ static void sort_acl(SEC_ACL *the_acl)
 	uint32 i;
 	if (!the_acl) return;
 
-	TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare);
+	TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces,ace_compare);
 
 	for (i=1;i<the_acl->num_aces;) {
 		if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
@@ -821,39 +876,26 @@ set the ACLs on a file given an ascii description
 static int cacl_set(struct cli_state *cli, char *filename, 
 		    char *the_acl, enum acl_mode mode)
 {
-	uint16_t fnum;
 	SEC_DESC *sd, *old;
 	uint32 i, j;
 	size_t sd_size;
 	int result = EXIT_OK;
 
-	if (sddl) {
+        if (sddl) {
 		sd = sddl_decode(talloc_tos(), the_acl, get_global_sam_sid());
-	} else {
+        } else {
 		sd = sec_desc_parse(talloc_tos(), cli, 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 */
-
-	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ, 0,
-				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
-		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
-		return EXIT_FAILED;
-	}
-
-	old = cli_query_secdesc(cli, fnum, talloc_tos());
+	old = get_secdesc(cli, filename);
 
 	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:
@@ -939,20 +981,100 @@ static int cacl_set(struct cli_state *cli, char *filename,
 			   old->owner_sid, old->group_sid,
 			   NULL, old->dacl, &sd_size);
 
-	if (!NT_STATUS_IS_OK(cli_ntcreate(cli, filename, 0, WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS, 0,
-			FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
-		printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+	if (!set_secdesc(cli, filename, sd)) {
+		result = EXIT_FAILED;
+	}
+
+	return result;
+}
+
+/***************************************************** 
+set the inherit on a file
+*******************************************************/
+
+static int inherit(struct cli_state *cli, char *filename, const char *type)
+{
+	uint16_t fnum;
+	SEC_DESC *old,*sd;
+	uint32 i, j;
+	size_t sd_size;
+	int result = EXIT_OK;
+
+	old = get_secdesc(cli, filename);
+
+	if (!old) {
 		return EXIT_FAILED;
 	}
 
-	if (!cli_set_secdesc(cli, fnum, sd)) {
-		printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
-		result = EXIT_FAILED;
+        uint32 oldattr = get_fileinfo(cli,filename);
+
+	if (strcmp(type,"allow")==0) {
+                old->type=old->type & (~SEC_DESC_DACL_PROTECTED);
+
+                //look at parent and copy in all its inheritable ACL's.
+	        string_replace(filename, '\\', '/');
+                char *parentname;
+                if (!parent_dirname(talloc_tos(),filename,&parentname,NULL)) {
+			return EXIT_FAILED;
+                }
+	        string_replace(filename, '/', '\\');
+	        string_replace(parentname, '/', '\\');
+	        SEC_DESC *parent = get_secdesc(cli,parentname);
+	        for (i=0;i<parent->dacl->num_aces;i++) {
+	          SEC_ACE *ace=&parent->dacl->aces[i];
+                  if ((oldattr & aDIR) == aDIR) {
+		    if ((ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) ==
+                        SEC_ACE_FLAG_CONTAINER_INHERIT) {
+			add_ace(&old->dacl, ace);
+                    }
+                  } else {
+		    if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) ==
+                        SEC_ACE_FLAG_OBJECT_INHERIT) {
+			add_ace(&old->dacl, ace);
+                    }
+                  }
+                }
+	} else if (strcmp(type,"remove")==0) {
+                old->type=old->type | SEC_DESC_DACL_PROTECTED;
+
+                //remove all inherited ACL's.
+	        if (old->dacl) {
+                  SEC_ACL *temp=old->dacl;
+                  old->dacl=make_sec_acl(talloc_tos(), 3, 0, NULL);
+                  int i;
+	          for (i=temp->num_aces-1;i>=0;i--) {
+	            SEC_ACE *ace=&temp->aces[i];
+                    //Remove all ace with INHERITED flag set
+		    if ((ace->flags & SEC_ACE_FLAG_INHERITED_ACE) !=
+                        SEC_ACE_FLAG_INHERITED_ACE) {
+                      add_ace(&old->dacl,ace);
+		    }
+	          }
+                }
+	} else if (strcmp(type,"copy")==0) {
+                old->type=old->type | SEC_DESC_DACL_PROTECTED;
+
+                //convert all inherited ACL's to non inherated ACL's.
+	        if (old->dacl) {
+                  int i;
+	          for (i=0;i<old->dacl->num_aces;i++) {
+	            SEC_ACE *ace=&old->dacl->aces[i];
+                    //Remove INHERITED FLAG from all aces
+                    ace->flags=ace->flags&(~SEC_ACE_FLAG_INHERITED_ACE);
+	          }
+                }
 	}
 
-	/* Clean up */
+	/* Denied ACE entries must come before allowed ones */
+	sort_acl(old->dacl);
 
-	cli_close(cli, fnum);
+	sd = make_sec_desc(talloc_tos(),old->revision, old->type,
+			   old->owner_sid, old->group_sid,
+			   NULL, old->dacl, &sd_size);
+
+	if (!set_secdesc(cli, filename, sd)) {
+		result = EXIT_FAILED;
+	}
 
 	return result;
 }
@@ -1034,6 +1156,7 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info,
 		{ "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" },
+		{ "inherit", 'I', POPT_ARG_STRING, NULL, 'I', "Inherit allow|remove|copy" },
 		{ "numeric", 0, POPT_ARG_NONE, &numeric, 1, "Don't resolve sids or masks to names" },
 		{ "sddl", 0, POPT_ARG_NONE, &sddl, 1, "Output and input acls in sddl format" },
 		{ "test-args", 't', POPT_ARG_NONE, &test_args, 1, "Test arguments"},
@@ -1106,6 +1229,11 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info,
 			owner_username = poptGetOptArg(pc);
 			change_mode = REQUEST_CHGRP;
 			break;
+
+		case 'I':
+			owner_username = poptGetOptArg(pc);
+			change_mode = REQUEST_INHERIT;
+			break;
 		}
 	}
 
@@ -1166,7 +1294,9 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info,
 
 	/* Perform requested action */
 
-	if (change_mode != REQUEST_NONE) {
+	if (change_mode == REQUEST_INHERIT) {
+		result = inherit(cli, filename, owner_username);
+	} else if (change_mode != REQUEST_NONE) {
 		result = owner_set(cli, change_mode, filename, owner_username);
 	} else if (the_acl) {
 		result = cacl_set(cli, filename, the_acl, mode);
-- 
1.6.2.5



More information about the samba-technical mailing list