partial smbclient / smbcalcs merge

Roger Standridge roger at digitalfountain.com
Tue Jan 29 22:27:20 GMT 2002


My first post, I am going to write it as if I have targeted the right 
place, sorry if I haven't... where should it go?

Attached is a patch against the 2.2.2 release that adds a 'showacl' 
(show access control list) command to smbclient.  Essentially I copied 
part of util/smbcalcs.c into client/client.c and modified the display 
format.

<example interaction>

smb: \> help showacl
HELP showacl:
	<remote name> [-n | --numeric | -x | --explicit]
	show access control list for remote file

smb: \> showacl 1.txt
REVISION:1
OWNER:BUILTIN\Administrators
GROUP:DIGITALFOUNTAIN\Developers
ACL:DIGITALFOUNTAIN\joeuser:ALLOWED/3/Modify
ACL:Everyone:ALLOWED/16/Full Control
smb: \> showacl 1.txt -n
REVISION:1
OWNER:S-1-5-32-544
GROUP:S-1-5-21-1533814122-1651835022-184960113-1005
ACL:S-1-5-21-1533814122-1651835022-184960113-1087:0/3/0x001301bf
ACL:S-1-1-0:0/16/0x001f01ff
smb: \> showacl 1.txt --explicit
REVISION:1
OWNER:BUILTIN\Administrators
GROUP:DIGITALFOUNTAIN\Developers
ACL:DIGITALFOUNTAIN\joeuser:ALLOWED/3/
         FILE_READ_DATA
         FILE_WRITE_DATA
         FILE_APPEND_DATA
         FILE_READ_EA
         FILE_WRITE_EA
         FILE_EXECUTE
         FILE_READ_ATTRIBUTES
         FILE_WRITE_ATTRIBUTES
         DELETE
         READ_CONTROL
         SYNCHRONIZE
ACL:Everyone:ALLOWED/16/
         FILE_READ_DATA
         FILE_WRITE_DATA
         FILE_APPEND_DATA
         FILE_READ_EA
         FILE_WRITE_EA
         FILE_EXECUTE
         FILE_DELETE_CHILD
         FILE_READ_ATTRIBUTES
         FILE_WRITE_ATTRIBUTES
         DELETE
         READ_CONTROL
         WRITE_DAC
         WRITE_OWNER
         SYNCHRONIZE

</example interaction>

Notes:

   o Permission summary strings mimic those from W2K permission control
     dialog (Read / Write / Read & Execute / Modify / Full Control).
     I found the MS cacls program too broken to bother imitating.

   o -n or --numeric option displays in the numeric format of the
     original smbcacls program

   o -x or --explicit option displays the string equivelant of
     each permission, one per line below the ace (much like the
     MS cacls program.

   o tried to mimic the code style of the original, sorry if I missed

   o only compiled on Debian GNU/Linux i386, Potato and Sid
     (But there is very little new code here).

   o usage extends multiple lines, sorry, not consistent

   o accepts relative and absolute paths of filenames as well
     as '.' and '..' (other commands do not)

   o tested only against W2K

   o Makefile.in patch needlessly changes style of CLIENT_OBJ and
     SMBCACLS_OBJ variables.

   o options follow filename... seemed the right thing to do,
     but I don't see any other commands that take options (similar
     things seem to be done by placing smbclient in recursive mode,
     etc.).

   o Summary permission strings work both for ALLOWED and DENIED
     access control lists, but I discovered that SYNCHRONIZE was
     not in the bit-mask for DENIED ACEs..., so I blanked out
     checking for it... blah, blah... needs investigation.


-Roger Standridge
<roger @ digitalfountain.com>
-------------- next part --------------
diff -rc samba-2.2.2-10.orig/source/Makefile.in samba-2.2.2-10-smbclient-showalc-patched/source/Makefile.in
*** samba-2.2.2-10.orig/source/Makefile.in	Wed Jan 23 11:33:19 2002
--- samba-2.2.2-10-smbclient-showalc-patched/source/Makefile.in	Tue Jan 29 10:37:25 2002
***************
*** 283,290 ****
  LIBSMBCLIENT_OBJ = libsmb/libsmbclient.o $(LIB_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
  
  CLIENT_OBJ = client/client.o client/clitar.o \
!              $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
!              $(READLINE_OBJ)
  
  CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
  
--- 283,309 ----
  LIBSMBCLIENT_OBJ = libsmb/libsmbclient.o $(LIB_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
  
  CLIENT_OBJ = client/client.o client/clitar.o \
! 	$(PARAM_OBJ)       \
! 	$(LIBSMB_OBJ)      \
! 	$(UBIQX_OBJ)       \
! 	$(LIB_OBJ)         \
! 	$(LIBMSRPC_OBJ)    \
! 	$(RPC_PARSE_OBJ)   \
! 	$(PASSDB_OBJ)      \
! 	\
! 	$(READLINE_OBJ)
! 
! SMBCACLS_OBJ = utils/smbcacls.o \
! 	$(PARAM_OBJ)       \
! 	$(LIBSMB_OBJ)      \
! 	$(UBIQX_OBJ)       \
! 	$(LIB_OBJ)         \
! 	$(LIBMSRPC_OBJ)    \
! 	$(RPC_PARSE_OBJ)   \
! 	$(PASSDB_OBJ)      \
! 	\
! 	$(LOCKING_OBJ)
! 
  
  CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
  
***************
*** 311,321 ****
  
  LOCKTEST_OBJ = utils/locktest.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
                   $(UBIQX_OBJ) $(LIB_OBJ)
- 
- SMBCACLS_OBJ = utils/smbcacls.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
- 				$(UBIQX_OBJ) $(LIB_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) \
- 				$(LIBMSRPC_OBJ)
- 
  
  LOCKTEST2_OBJ = utils/locktest2.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
                   $(UBIQX_OBJ) $(LIB_OBJ)
--- 330,335 ----
diff -rc samba-2.2.2-10.orig/source/client/client.c samba-2.2.2-10-smbclient-showalc-patched/source/client/client.c
*** samba-2.2.2-10.orig/source/client/client.c	Wed Jan 23 11:33:19 2002
--- samba-2.2.2-10-smbclient-showalc-patched/source/client/client.c	Tue Jan 29 10:37:09 2002
***************
*** 34,39 ****
--- 34,40 ----
  pstring cd_path = "";
  static pstring service;
  static pstring desthost;
+ static pstring servername;
  extern pstring global_myname;
  static pstring password;
  static pstring username;
***************
*** 1682,1687 ****
--- 1683,1986 ----
  }
  
  /****************************************************************************
+ show access control list for file. (rws)
+ (Code taken from utils/smbcalcs.c)
+ ****************************************************************************/
+ 
+ struct cli_state lsa_cli;
+ POLICY_HND pol;
+ 
+ /* Open cli connection and policy handle */
+ static BOOL open_policy_hnd(void)
+ {
+         /* Were globals in smbcalcs.*/
+         static BOOL got_policy_hnd = False;
+         static struct ntuser_creds creds;
+ 
+ 	creds.pwd.null_pwd = 1;
+ 
+  	/* Initialise cli LSA connection */ 
+ 	if (!lsa_cli.initialised && 
+ 	    !cli_lsa_initialise(&lsa_cli, servername, &creds)) {
+ 		return False;
+ 	}
+ 
+ 	/* Open policy handle */
+ 
+ 	if (!got_policy_hnd) {
+ 
+ 		/* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
+ 		   but NT sends 0x2000000 so we might as well do it too. */
+ 
+ 		if (cli_lsa_open_policy(&lsa_cli, lsa_cli.mem_ctx, True, 
+ 					GENERIC_EXECUTE_ACCESS, &pol)
+ 		    != NT_STATUS_OK) {
+ 			return False;
+ 		}
+ 
+ 		got_policy_hnd = True;
+ 	}
+ 	
+ 	return True;
+ }
+ 
+ /* Access Control Entry output format codes. */
+ enum AceDisplayForm
+ {
+     FORM_NORMAL,  /* Attempt standard string description first. */
+     FORM_NUMERIC, /* Only output numeric values.                */
+     FORM_EXPLICIT /* Explicitly list the permissions.           */
+ };
+ 
+ /* convert a SID to a string, either numeric or username/group */
+ static void SidToString(fstring str, DOM_SID *sid, enum AceDisplayForm form)
+ {
+ 	char **names = NULL;
+ 	uint32 *types = NULL;
+ 	int num_names;
+ 
+ 	sid_to_string(str, sid);
+ 
+ 	if (FORM_NUMERIC == form) 
+             return;
+ 
+ 	/* Ask LSA to convert the sid to a name */
+         if (!open_policy_hnd())
+         {
+                 DEBUG(0, ("Error in open_policy_hnd()\n"));
+                 return;
+         }
+ 	if (cli_lsa_lookup_sids(&lsa_cli, lsa_cli.mem_ctx,  
+                                 &pol, 1, sid, &names, &types, 
+ 				&num_names) != NT_STATUS_OK ||
+ 	    !names || !names[0]) {
+ 		return;
+ 	}
+ 
+ 	/* Converted OK */
+ 	fstrcpy(str, names[0]);
+ }
+ 
+ /* Structure for mapping bit fields in access 
+    control entries to string descriptions. */
+ struct perm_value {
+ 	char *perm;
+ 	uint32 mask;
+ };
+ 
+ /* Names of bit fields within acess control entry permission mask */
+ static struct perm_value explicit_values[] = 
+ {
+         { "FILE_READ_DATA",        FILE_READ_DATA },
+         { "FILE_WRITE_DATA",       FILE_WRITE_DATA },
+         { "FILE_APPEND_DATA",      FILE_APPEND_DATA },
+         { "FILE_READ_EA",          FILE_READ_EA },
+         { "FILE_WRITE_EA",         FILE_WRITE_EA },
+         { "FILE_EXECUTE",          FILE_EXECUTE },
+         { "FILE_DELETE_CHILD",     FILE_DELETE_CHILD },
+         { "FILE_READ_ATTRIBUTES",  FILE_READ_ATTRIBUTES },
+         { "FILE_WRITE_ATTRIBUTES", FILE_WRITE_ATTRIBUTES },
+ 
+         { "DELETE",         DELETE_ACCESS },
+         { "READ_CONTROL",   READ_CONTROL_ACCESS },
+         { "WRITE_DAC",      WRITE_DAC_ACCESS },
+         { "WRITE_OWNER",    WRITE_OWNER_ACCESS }, 
+         { "SYNCHRONIZE",    SYNCHRONIZE_ACCESS },
+         { NULL, 0 },
+ };
+ 
+ /* 
+    Standard values for file permissions (in W2K).  Discovered by
+    testing... then looking in smb.h ;).
+ 
+    MS cacls just seemed too messed up to imitate its behavior.
+ 
+    Masking out the SYNCHRONIZE_ACCESS values because the 'denied'
+    access control entries do not seem to have them for standard values.
+ */
+ static struct perm_value standard_values[] = 
+ {
+         { "Read",             
+           (FILE_GENERIC_READ)      
+           & ~SYNCHRONIZE_ACCESS },
+ 
+         { "Read & Execute",   
+           (FILE_GENERIC_EXECUTE 
+            | FILE_GENERIC_READ)    
+           & ~SYNCHRONIZE_ACCESS },
+ 
+         /* I don't think smb.h has FILE_GENERIC_WRITE correct
+            (or it isn't what I think it is ;). */
+         { "Write",            
+           (FILE_WRITE_DATA 
+            | FILE_APPEND_DATA
+            | FILE_WRITE_EA
+            | FILE_WRITE_ATTRIBUTES)
+           & ~SYNCHRONIZE_ACCESS },
+ 
+         { "Modify",           
+           (FILE_GENERIC_READ 
+            | FILE_GENERIC_WRITE 
+            | FILE_GENERIC_EXECUTE 
+            | DELETE_ACCESS)
+           & ~SYNCHRONIZE_ACCESS },
+ 
+         { "Full Control",     
+           (FILE_GENERIC_ALL)
+           & ~SYNCHRONIZE_ACCESS },
+ 
+         { NULL, 0 },
+ };
+ 
+ static void print_ace(SEC_ACE *ace, enum AceDisplayForm form)
+ {
+         const char * indent = "        ";
+ 	struct perm_value *v;
+ 	fstring sidstr;
+ 	uint32 leftover;
+         uint32 tmp_mask;
+ 
+ 	SidToString(sidstr, &ace->sid, form);
+ 
+         DEBUG(0,("%s:", sidstr));
+ 
+ 	if (FORM_NUMERIC == form ) {
+ 		DEBUG(0,("%d/%d/0x%08x", 
+                          ace->type, ace->flags, ace->info.mask));
+ 		return;
+  	} 
+ 
+ 	/* Ace type */
+ 
+ 	if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
+ 		DEBUG(0,("ALLOWED"));
+ 	} else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ 		DEBUG(0,("DENIED"));
+ 	} else {
+ 		DEBUG(0,("%d", ace->type));
+ 	}
+ 
+ 	/* Not sure what flags can be set in a file ACL */
+ 	DEBUG(0,("/%d/", ace->flags));
+ 
+ 	/* Standard permissions, (rws : w2k form) */
+         if (FORM_NORMAL == form) {
+                 /* Mask out the SYNCHRONIZE_ACCESS */
+                 tmp_mask = ace->info.mask & ~SYNCHRONIZE_ACCESS;
+                 for (v = standard_values; v->perm; v++) {
+                         if (tmp_mask == v->mask) {
+                                 DEBUG(0,("%s", v->perm));
+                                 return;
+                         }
+                 }
+                 DEBUG(0,("(special access:)"));
+         }
+ 
+         /* Print each access description, 1 per line, indented. */
+         leftover = ace->info.mask;
+         for (v = explicit_values; v->perm; v++) {
+                 if ((ace->info.mask & v->mask)) {
+                         leftover &= ~v->mask;
+                         DEBUG(0,("\n%s%s", indent, v->perm));
+                 }
+         }
+         if (leftover) DEBUG(0,("\n%suninterpreted : 0x%08x",
+                                indent, leftover));
+ }
+ 
+ static void cmd_showacl(void)
+ {
+ #define SHOWACL_USAGE  "<remote name> [-n | --numeric | -x | --explicit] \n"
+ 
+         int fnum;
+         fstring filename;
+         fstring buf;
+         enum AceDisplayForm form = FORM_NORMAL;
+         int i;
+ 	SEC_DESC *sd;
+         TALLOC_CTX *ctx;
+ 
+         /*                  - get/convert filename option -                  */
+         if (!next_token(NULL,buf,NULL,sizeof(filename))) {
+                 DEBUG(0,(SHOWACL_USAGE));
+                 return;
+         }
+         string_replace( buf, '/','\\');
+ 
+         /* allow '.' and '..' converting them to '.\' and '.\\' */
+         if (strequal(buf, ".") || strequal(buf, ".."))
+                 pstrcat(buf, "\\");
+ 
+         /* construct full name, leading '\' 
+            indicates absolute path */
+         if (strnequal(buf, "\\", 1)) {
+                 pstrcpy(filename, buf);
+         } else {
+                 pstrcpy(filename, cur_dir);
+                 pstrcat(filename, buf);
+         }
+         dos_clean_name(filename);
+         DEBUG(3,("file name : %s\n", filename));
+ 
+         /*                     - get format option -                         */
+         if (next_token(NULL,buf,NULL,sizeof(buf))) {
+                 if (strequal("-n", buf) || 
+                     strnequal("--n", buf, strlen("--n"))) {
+                         form = FORM_NUMERIC;
+ 
+                 } else if(strequal("-x", buf) || 
+                           strnequal("--e",buf, strlen("--e"))) {
+                         form = FORM_EXPLICIT;
+ 
+                 } else {
+                         DEBUG(0, (SHOWACL_USAGE));
+                         return;
+                 }
+         }
+ 
+         /*                   - Reject further options -                     */
+         if (next_token(NULL,buf,NULL,sizeof(buf))) {
+                 DEBUG(0, (SHOWACL_USAGE));
+                 return;
+         }
+ 
+         /*                        - Retrieve -                              */
+         if (-1 == (fnum = cli_nt_create(cli, filename, READ_CONTROL_ACCESS))) {
+ 		printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ 		return;
+ 	}
+ 
+         if (!(sd = cli_query_secdesc(cli, fnum, ctx))) {
+ 		printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
+ 		return;
+ 	}
+ 
+         /*                          - Print -                                */
+         /* revision should be '1' */
+ 	DEBUG(0,("REVISION:%d\n", sd->revision));
+ 
+ 	/* Print owner sid */
+ 	if (sd->owner_sid)  SidToString(buf, sd->owner_sid, form);
+ 	else fstrcpy(buf, "");
+         DEBUG(0,("OWNER:%s\n", buf));
+ 
+ 	/* Print group sid */
+ 	if (sd->grp_sid) SidToString(buf, sd->grp_sid, form);
+         else fstrcpy(buf, "");
+         DEBUG(0,("GROUP:%s\n", buf));
+ 
+ 	/* Print access control entries */
+ 	for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ 		SEC_ACE *ace = &sd->dacl->ace[i];
+ 		DEBUG(0,("ACL:")); 
+                 print_ace(ace, form); 
+                 DEBUG(0,("\n"));
+ 	}
+ 
+ 	cli_close(cli, fnum);
+ }
+ 
+ /****************************************************************************
  try and browse available connections on a host
  ****************************************************************************/
  static BOOL list_servers(char *wk_grp)
***************
*** 1756,1761 ****
--- 2055,2063 ----
    {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
    {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
    {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
+   {"showacl",cmd_showacl, 
+    SHOWACL_USAGE "\tshow access control list for remote file",
+    {COMPL_NONE,COMPL_NONE}},
    {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
    {"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
  };
***************
*** 1984,1989 ****
--- 2286,2292 ----
  		sharename = strchr(server,'\\');
  		if (!sharename) return NULL;
  		*sharename = 0;
+         fstrcpy(servername, servicename);
  		sharename++;
  	}
  


More information about the smb-clients mailing list