diff options
28 files changed, 793 insertions, 433 deletions
diff --git a/source/Makefile.in b/source/Makefile.in index e6f7901dd5a..bff46a528b6 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -62,7 +62,7 @@ LOCKDIR = @lockdir@ CODEPAGEDIR = $(LIBDIR)/codepages # The current codepage definition list. -CODEPAGELIST= 437 737 775 850 852 861 932 866 949 950 936 1251 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI-R +CODEPAGELIST= 437 737 775 850 852 861 932 866 949 950 936 1251 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI-R 857 ISO8859-9 # where you are going to have the smbrun binary. This defaults to the # install directory. This binary is needed for correct printing diff --git a/source/include/proto.h b/source/include/proto.h index 8289412d7bc..1e6bee4badf 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -436,6 +436,7 @@ struct cli_connection* RpcHndList_get_connection(const POLICY_HND *hnd); /*The following definitions come from lib/util_seaccess.c */ +void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping); BOOL se_access_check(SEC_DESC *sd, struct current_user *user, uint32 acc_desired, uint32 *acc_granted, uint32 *status); @@ -694,6 +695,7 @@ BOOL cli_unlink(struct cli_state *cli, char *fname); BOOL cli_mkdir(struct cli_state *cli, char *dname); BOOL cli_rmdir(struct cli_state *cli, char *dname); int cli_nt_create(struct cli_state *cli, char *fname, uint32 DesiredAccess); +int cli_nt_create_uni(struct cli_state *cli, char *fname, uint32 DesiredAccess); int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode); BOOL cli_close(struct cli_state *cli, int fnum); BOOL cli_lock(struct cli_state *cli, int fnum, @@ -814,14 +816,17 @@ BOOL deal_with_creds(uchar sess_key[8], /*The following definitions come from libsmb/namequery.c */ -BOOL name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master,char *rname); +struct node_status *name_status_query(int fd,struct nmb_name *name, + struct in_addr to_ip, int *num_names); +BOOL name_status_find(int type, struct in_addr to_ip, char *name); struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse, struct in_addr to_ip, int *count); FILE *startlmhosts(char *fname); BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr); void endlmhosts(FILE *fp); +BOOL name_resolve_bcast(const char *name, int name_type, + struct in_addr **return_ip_list, int *return_count); BOOL is_ip_address(const char *name); BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type); BOOL resolve_srv_name(const char* srv_name, fstring dest_host, @@ -856,7 +861,7 @@ int name_len(char *s1); /*The following definitions come from libsmb/nterr.c */ BOOL get_safe_nt_error_msg(uint32 nt_code,char *msg, size_t len); -const char *get_nt_error_msg(uint32 nt_code); +char *get_nt_error_msg(uint32 nt_code); /*The following definitions come from libsmb/passchange.c */ @@ -1790,6 +1795,7 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, fstring value, uint8 **data, uint32 *type, uint32 *len); uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr); BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr); +void map_printer_permissions(SEC_DESC *sd); BOOL print_access_check(struct current_user *user, int snum, int access_type); BOOL print_time_access_check(int snum); #endif diff --git a/source/include/rpc_secdes.h b/source/include/rpc_secdes.h index a5c5758434f..ab8a24d2d61 100644 --- a/source/include/rpc_secdes.h +++ b/source/include/rpc_secdes.h @@ -156,4 +156,14 @@ typedef struct sec_desc_buf_info #define _SEC_DESC_BUF #endif +/* A type to describe the mapping of generic access rights to object + specific access rights. */ + +typedef struct generic_mapping { + uint32 generic_read; + uint32 generic_write; + uint32 generic_execute; + uint32 generic_all; +} GENERIC_MAPPING; + #endif /* _RPC_SECDES_H */ diff --git a/source/include/rpc_spoolss.h b/source/include/rpc_spoolss.h index 94cfb45dfed..33541c12fe0 100755 --- a/source/include/rpc_spoolss.h +++ b/source/include/rpc_spoolss.h @@ -148,24 +148,19 @@ #define PRINTER_STATUS_POWER_SAVE 0x01000000 -/* Printer permissions ACE settings. NT4 uses generic and standard access - rights whereas NT5 converts them all to object specific access rights. */ - -#define PRINTER_ACE_FULL_CONTROL GENERIC_ALL_ACCESS -#define PRINTER_ACE_MANAGE_DOCUMENTS READ_CONTROL_ACCESS -#define PRINTER_ACE_PRINT \ - (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS) - -#define PRINTER_ACE_NT5_FULL_CONTROL 0x000f000c -#define PRINTER_ACE_NT5_PRINT 0x00020000 -#define PRINTER_ACE_NT5_MANAGE_DOCUMENTS 0x00020008 - #define SERVER_ACCESS_ADMINISTER 0x00000001 #define SERVER_ACCESS_ENUMERATE 0x00000002 #define PRINTER_ACCESS_ADMINISTER 0x00000004 #define PRINTER_ACCESS_USE 0x00000008 #define JOB_ACCESS_ADMINISTER 0x00000010 +/* ACE masks for the various print permissions */ + +#define PRINTER_ACE_FULL_CONTROL GENERIC_ALL_ACCESS +#define PRINTER_ACE_MANAGE_DOCUMENTS READ_CONTROL_ACCESS +#define PRINTER_ACE_PRINT \ + (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS) + /* Access rights for print servers */ #define SERVER_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE #define SERVER_READ STANDARD_RIGHTS_READ_ACCESS|SERVER_ACCESS_ENUMERATE @@ -1824,5 +1819,4 @@ SPOOL_R_REPLY_RRPCN; #define PRINTER_DRIVER_VERSION 2 #define PRINTER_DRIVER_ARCHITECTURE "Windows NT x86" - #endif /* _RPC_SPOOLSS_H */ diff --git a/source/include/smb.h b/source/include/smb.h index 0d802009fdf..a57cdc0e518 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -1622,6 +1622,16 @@ struct nmb_name { unsigned int name_type; }; + +/* A netbios node status array element. */ +struct node_status { + char name[16]; + unsigned char type; + unsigned char flags; +}; + + + #define AGENT_CMD_CON 0 #define AGENT_CMD_CON_ANON 2 #define AGENT_CMD_CON_REUSE 1 diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c index 2916f0cedab..a5355aa7c88 100644 --- a/source/lib/charcnv.c +++ b/source/lib/charcnv.c @@ -166,6 +166,29 @@ update_map("\266\352"); update_map("\270\353\271\354\272\355\274\356\276\357\277\360"); } +/* Added by Deniz Akkus (akkus@alum.mit.edu) */ + +static void init_iso8859_9(void) +{ + setupmaps(); + + /* MSDOS Code Page 857 -> ISO-8859-9 (Turkish) */ + + update_map("\xa0\xff\xa1\xad\xa2\xbd\xa3\x9c\xa4\xcf\xA5\xbe\xa6\xdd\xa7\xf5"); + update_map("\xa8\xf9\xa9\xb8\xaa\xd1\xab\xae\xac\xaa\xad\xf0\xae\xa9\xaf\xee"); + update_map("\xb0\xf8\xb1\xf1\xb2\xfd\xb3\xfc\xb4\xef\xb5\xe6\xb6\xf4\xb7\xfa"); + update_map("\xb8\xf7\xb9\xfb\xba\xd0\xbb\xaf\xbc\xac\xbd\xab\xbe\xf3\xbf\xa8"); + update_map("\xc0\xb7\xc1\xb5\xc2\xb6\xc3\xc7\xc4\x8e\xc5\x8f\xc6\x92\xc7\x80"); + update_map("\xc8\xd4\xc9\x90\xca\xd2\xcb\xd3\xcc\xde\xcd\xd6\xce\xd7\xcf\xd8"); + update_map("\xd0\xa6\xd1\xa5\xd2\xe3\xd3\xe0\xd4\xe2\xd5\xe5\xd6\x99\xd7\xe8"); + update_map("\xd8\x9d\xd9\xeb\xda\xe9\xdb\xea\xdc\x9a\xdd\x98\xde\x9e\xdf\xe1"); + update_map("\xe0\x85\xe1\xa0\xe2\x83\xe3\xc6\xe4\x84\xe5\x86\xe6\x91\xe7\x87"); + update_map("\xe8\x8a\xe9\x82\xea\x88\xeb\x89\xec\xec\xed\xa1\xee\x8c\xef\x8b"); + update_map("\xf0\xa7\xf1\xa4\xf2\x95\xf3\xa2\xf4\x93\xf5\xe4\xf6\x94\xf7\xf6"); + update_map("\xf8\x9b\xf9\x97\xfa\xa3\xfb\x96\xfc\x81\xfd\x8d\xfe\x9f\xff\xed"); +} + + /* Init for russian language (koi8) */ static void init_koi8_r(void) @@ -273,6 +296,8 @@ void interpret_character_set(char *str, int codepage) init_iso8859_5(); } else if (strequal (str, "iso8859-7")) { init_iso8859_7(); + } else if (strequal (str, "iso8859-9")) { + init_iso8859_9(); } else if (strequal (str, "koi8-r")) { init_koi8_r(); } else if (strequal (str, "roman8")) { diff --git a/source/lib/util_seaccess.c b/source/lib/util_seaccess.c index 87d0f3bb688..68f900b34db 100644 --- a/source/lib/util_seaccess.c +++ b/source/lib/util_seaccess.c @@ -51,6 +51,32 @@ static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired, { uint32 mask = ace->info.mask; +#if 0 + + /* I think there is some aspect of inheritable ACEs that we don't + understand. A 'Manage Documents' permission has the following + ACE entries (after generic mapping has been applied): + + S-1-5-21-1067277791-1719175008-3000797951-1033 0 9 0x000f000c + S-1-5-21-1067277791-1719175008-3000797951-1033 0 2 0x00020000 + + Now a user wanting to print calls se_access_check() with desired + access PRINTER_ACCESS_USE (0x00000008). This is only allowed if + the inherit only ACE, flags & SEC_ACE_FLAG_INHERIT_ONLY (0x8) is + checked. A similar argument is used to explain how a user with + 'Full Control' permission can print. + + Having both the flags SEC_ACE_FLAG_INHERIT_ONLY and + SEC_ACE_FLAG_OBJECT_INHERIT set in an ACE doesn't seem to make + sense. According to the MSDN, an inherit only ACE "indicates an + [...] ACE which does not control access to the object to which + it is attached" and an object inherit ACE for "non-container + child objects [they] inherit the ACE as an effective ACE". + These two flags don't seem to make sense when combined. Does + the object inherit override the inherit only flag? We are also + talking about access to a printer object, not a printer job so + inheritance shouldn't even be involved. -tpot */ + /* * Inherit only is ignored. */ @@ -59,6 +85,7 @@ static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired, return acc_desired; } +#endif /* * If this ACE has no SID in common with the token, @@ -159,13 +186,48 @@ static BOOL get_max_access( SEC_ACL *acl, NT_USER_TOKEN *token, uint32 *granted, return True; } -/********************************************************************************* +/* Map generic access rights to object specific rights. This technique is + used to give meaning to assigning read, write, execute and all access to + objects. Each type of object has its own mapping of generic to object + specific access rights. */ + +void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping) +{ + uint32 old_mask = *access_mask; + + if (*access_mask & GENERIC_READ_ACCESS) { + *access_mask &= ~GENERIC_READ_ACCESS; + *access_mask |= mapping->generic_read; + } + + if (*access_mask & GENERIC_WRITE_ACCESS) { + *access_mask &= ~GENERIC_WRITE_ACCESS; + *access_mask |= mapping->generic_write; + } + + if (*access_mask & GENERIC_EXECUTE_ACCESS) { + *access_mask &= ~GENERIC_EXECUTE_ACCESS; + *access_mask |= mapping->generic_execute; + } + + if (*access_mask & GENERIC_ALL_ACCESS) { + *access_mask &= ~GENERIC_ALL_ACCESS; + *access_mask |= mapping->generic_all; + } + + if (old_mask != *access_mask) { + DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n", + old_mask, *access_mask)); + } +} + +/***************************************************************************** Check access rights of a user against a security descriptor. Look at each ACE in the security descriptor until an access denied ACE denies any of the desired rights to the user or any of the users groups, or one or more ACEs explicitly grant all requested access rights. See "Access-Checking" document in MSDN. -**********************************************************************************/ +*****************************************************************************/ BOOL se_access_check(SEC_DESC *sd, struct current_user *user, uint32 acc_desired, uint32 *acc_granted, uint32 *status) @@ -204,6 +266,11 @@ BOOL se_access_check(SEC_DESC *sd, struct current_user *user, DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &token->user_sids[0]) )); + for (i = 1; i < token->num_sids; i++) { + DEBUG(3, ("se_access_check: also %s\n", + sid_to_string(sid_str, &token->user_sids[i]))); + } + /* Is the token the owner of the SID ? */ if (sd->owner_sid) { @@ -230,9 +297,11 @@ BOOL se_access_check(SEC_DESC *sd, struct current_user *user, for ( i = 0 ; i < acl->num_aces && tmp_acc_desired != 0; i++) { SEC_ACE *ace = &acl->ace[i]; - DEBUG(10,("se_access_check: ACE %u: SID = %s mask = %x, current desired = %x\n", - (unsigned int)i, sid_to_string(sid_str, &ace->sid), - (unsigned int) ace->info.mask, (unsigned int)tmp_acc_desired )); + DEBUG(10,("se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x\n", + (unsigned int)i, ace->type, ace->flags, + sid_to_string(sid_str, &ace->sid), + (unsigned int) ace->info.mask, + (unsigned int)tmp_acc_desired )); tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status); if (*status != NT_STATUS_NOPROBLEMO) { diff --git a/source/lib/util_str.c b/source/lib/util_str.c index 822267f5d5f..e07e5ef6ada 100644 --- a/source/lib/util_str.c +++ b/source/lib/util_str.c @@ -1296,4 +1296,5 @@ void parse_domain_user(char *domuser, fstring domain, fstring user) fstrcpy(user, p+1); fstrcpy(domain, domuser); domain[PTR_DIFF(p, domuser)] = 0; + strupper(domain); } diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c index 8a7c6da1afb..3e41ec82960 100644 --- a/source/libsmb/cliconnect.c +++ b/source/libsmb/cliconnect.c @@ -438,7 +438,7 @@ BOOL cli_negprot(struct cli_state *cli) cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1); memcpy(cli->cryptkey,smb_buf(cli->inbuf),8); cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1); - if (cli->capabilities & 1) { + if (cli->capabilities & CAP_RAW_MODE) { cli->readbraw_supported = True; cli->writebraw_supported = True; } diff --git a/source/libsmb/clierror.c b/source/libsmb/clierror.c index 4c6d9a49f23..eb2ca624e85 100644 --- a/source/libsmb/clierror.c +++ b/source/libsmb/clierror.c @@ -202,7 +202,7 @@ int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num, uint32 *nt_rpc_ } if (rcls == ERRSRV) { switch (code) { - case ERRbadpw: return EPERM; + case ERRbadpw: return EACCES; case ERRaccess: return EACCES; case ERRnoresource: return ENOMEM; case ERRinvdevice: return ENODEV; diff --git a/source/libsmb/clifile.c b/source/libsmb/clifile.c index cb492f1539b..ce9a79ede34 100644 --- a/source/libsmb/clifile.c +++ b/source/libsmb/clifile.c @@ -163,8 +163,6 @@ BOOL cli_rmdir(struct cli_state *cli, char *dname) return True; } - - /**************************************************************************** open a file ****************************************************************************/ @@ -212,6 +210,55 @@ int cli_nt_create(struct cli_state *cli, char *fname, uint32 DesiredAccess) return SVAL(cli->inbuf,smb_vwv2 + 1); } +/**************************************************************************** +open a file +****************************************************************************/ +int cli_nt_create_uni(struct cli_state *cli, char *fname, uint32 DesiredAccess) +{ + pstring uni; + char *p; + + memset(cli->outbuf,'\0',smb_size); + memset(cli->inbuf,'\0',smb_size); + + set_message(cli->outbuf,24,(strlen(fname) + 1) * 2 + 1,True); + + CVAL(cli->outbuf,smb_com) = SMBntcreateX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,0xFF); + if (cli->use_oplocks) + SIVAL(cli->outbuf,smb_ntcreate_Flags, REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK); + else + SIVAL(cli->outbuf,smb_ntcreate_Flags, 0); + SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0); + SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess); + SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, 0x0); + SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, 0x03); + SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, 0x01); + SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, 0x0); + SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02); + SSVAL(cli->outbuf,smb_ntcreate_NameLength, strlen(fname) * 2); + + p = smb_buf(cli->outbuf); + p++; /* Alignment */ + pstrcpy(uni, fname); + unix_to_dos(uni, True); + dos_struni2(p, uni, (strlen(fname) + 1) * 2); + + cli_send_smb(cli); + if (!cli_receive_smb(cli)) { + return -1; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return -1; + } + + return SVAL(cli->inbuf,smb_vwv2 + 1); +} + /**************************************************************************** open a file diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c index 92879871102..59a3856cfb8 100644 --- a/source/libsmb/namequery.c +++ b/source/libsmb/namequery.c @@ -45,168 +45,155 @@ static int generate_trn_id(void) /**************************************************************************** - Interpret a node status response. + parse a node status response into an array of structures ****************************************************************************/ - -static void _interpret_node_status(char *p, char *master,char *rname) +static struct node_status *parse_node_status(char *p, int *num_names) { - int numnames = CVAL(p,0); - DEBUG(1,("received %d names\n",numnames)); - - if (rname) *rname = 0; - if (master) *master = 0; - - p += 1; - while (numnames--) { - char qname[17]; - int type; - fstring flags; - int i; - *flags = 0; - StrnCpy(qname,p,15); - type = CVAL(p,15); - p += 16; - - fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " "); - if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B "); - if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P "); - if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M "); - if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H "); - if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> "); - if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> "); - if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> "); - if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> "); - - if (master && !*master && type == 0x1d) { - StrnCpy(master,qname,15); - trim_string(master,NULL," "); - } + struct node_status *ret; + int i; - if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { - StrnCpy(rname,qname,15); - trim_string(rname,NULL," "); - } - - for (i = strlen( qname) ; --i >= 0 ; ) { - if (!isprint((int)qname[i])) qname[i] = '.'; - } - DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags)); - p+=2; - } + *num_names = CVAL(p,0); + + if (*num_names == 0) return NULL; + + ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names)); + if (!ret) return NULL; - DEBUG(1,("num_good_sends=%d num_good_receives=%d\n", - IVAL(p,20),IVAL(p,24))); + p++; + for (i=0;i< *num_names;i++) { + StrnCpy(ret[i].name,p,15); + trim_string(ret[i].name,NULL," "); + ret[i].type = CVAL(p,15); + ret[i].flags = p[16]; + p += 18; + } + return ret; } + /**************************************************************************** - Internal function handling a netbios name status query on a host. +do a NBT node status query on an open socket and return an array of +structures holding the returned names or NULL if the query failed **************************************************************************/ -static BOOL internal_name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master, - char *rname, BOOL verbose, - void (*fn_interpret_node_status)(char *, char *,char *)) +struct node_status *name_status_query(int fd,struct nmb_name *name, + struct in_addr to_ip, int *num_names) { - BOOL found=False; - int retries = 2; - int retry_time = 2000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - - memset((char *)&p,'\0',sizeof(p)); - - nmb->header.name_trn_id = generate_trn_id(); - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = False; - nmb->header.nm_flags.recursion_available = False; - nmb->header.nm_flags.recursion_desired = False; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - - make_nmb_name(&nmb->question.question_name,name,name_type); + BOOL found=False; + int retries = 2; + int retry_time = 2000; + struct timeval tval; + struct packet_struct p; + struct packet_struct *p2; + struct nmb_packet *nmb = &p.packet.nmb; + struct node_status *ret; + + ZERO_STRUCT(p); + + nmb->header.name_trn_id = generate_trn_id(); + nmb->header.opcode = 0; + nmb->header.response = False; + nmb->header.nm_flags.bcast = False; + nmb->header.nm_flags.recursion_available = False; + nmb->header.nm_flags.recursion_desired = False; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = False; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + nmb->question.question_name = *name; + nmb->question.question_type = 0x21; + nmb->question.question_class = 0x1; + + p.ip = to_ip; + p.port = NMB_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = NMB_PACKET; + + GetTimeOfDay(&tval); + + if (!send_packet(&p)) + return NULL; - nmb->question.question_type = 0x21; - nmb->question.question_class = 0x1; + retries--; - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; + while (1) { + struct timeval tval2; + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) + break; + if (!found && !send_packet(&p)) + return NULL; + GetTimeOfDay(&tval); + retries--; + } - GetTimeOfDay(&tval); + if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) { + struct nmb_packet *nmb2 = &p2->packet.nmb; + debug_nmb_packet(p2); + + if (nmb2->header.opcode != 0 || + nmb2->header.nm_flags.bcast || + nmb2->header.rcode || + !nmb2->header.ancount || + nmb2->answers->rr_type != 0x21) { + /* XXXX what do we do with this? could be a + redirect, but we'll discard it for the + moment */ + free_packet(p2); + continue; + } - if (!send_packet(&p)) - return(False); + ret = parse_node_status(&nmb2->answers->rdata[0], num_names); + free_packet(p2); + return ret; + } + } + + return NULL; +} - retries--; - while (1) { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) - break; - if (!found && !send_packet(&p)) - return False; - GetTimeOfDay(&tval); - retries--; - } +/**************************************************************************** +find the first type XX name in a node status reply - used for finding +a servers name given its IP +return the matched name in *name +**************************************************************************/ +BOOL name_status_find(int type, struct in_addr to_ip, char *name) +{ + struct node_status *status; + struct nmb_name nname; + int count, i; + int sock; - if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) { - struct nmb_packet *nmb2 = &p2->packet.nmb; - debug_nmb_packet(p2); + sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True); + if (sock == -1) return False; - if (nmb2->header.opcode != 0 || - nmb2->header.nm_flags.bcast || - nmb2->header.rcode || - !nmb2->header.ancount || - nmb2->answers->rr_type != 0x21) { - /* XXXX what do we do with this? could be a - redirect, but we'll discard it for the - moment */ - free_packet(p2); - continue; - } + make_nmb_name(&nname, "*", 0); + status = name_status_query(sock, &nname, to_ip, &count); + close(sock); + if (!status) return False; - if(fn_interpret_node_status) - (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname); - free_packet(p2); - return(True); - } - } + for (i=0;i<count;i++) { + if (status[i].type == type) break; + } + if (i == count) return False; - if(verbose) - DEBUG(0,("No status response (this is not unusual)\n")); + StrnCpy(name, status[i].name, 15); - return(False); + free(status); + return True; } -/**************************************************************************** - Do a netbios name status query on a host. - The "master" parameter is a hack used for finding workgroups. -**************************************************************************/ -BOOL name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master,char *rname) -{ - return internal_name_status(fd,name,name_type,recurse, - to_ip,master,rname,True, - _interpret_node_status); -} /**************************************************************************** Do a netbios name query to find someones IP. Returns an array of IP addresses or NULL if none. *count will be set to the number of addresses returned. ****************************************************************************/ - struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse, struct in_addr to_ip, int *count) @@ -471,8 +458,8 @@ void endlmhosts(FILE *fp) Resolve via "bcast" method. *********************************************************/ -static BOOL resolve_bcast(const char *name, int name_type, - struct in_addr **return_ip_list, int *return_count) +BOOL name_resolve_bcast(const char *name, int name_type, + struct in_addr **return_ip_list, int *return_count) { int sock, i; int num_interfaces = iface_count(); @@ -484,7 +471,7 @@ static BOOL resolve_bcast(const char *name, int name_type, * "bcast" means do a broadcast lookup on all the local interfaces. */ - DEBUG(3,("resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type)); + DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type)); sock = open_socket_in( SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True ); @@ -714,7 +701,7 @@ static BOOL internal_resolve_name(const char *name, int name_type, return True; } } else if(strequal( tok, "bcast")) { - if (resolve_bcast(name, name_type, return_iplist, return_count)) { + if (name_resolve_bcast(name, name_type, return_iplist, return_count)) { return True; } } else { @@ -822,30 +809,6 @@ BOOL find_master_ip(char *group, struct in_addr *master_ip) return False; } -#if !defined(I_HATE_WINDOWS_REPLY_CODE) -/******************************************************** - Internal function to extract the MACHINE<0x20> name. -*********************************************************/ - -static void _lookup_pdc_name(char *p, char *master,char *rname) -{ - int numnames = CVAL(p,0); - - *rname = '\0'; - - p += 1; - while (numnames--) { - int type = CVAL(p,15); - if(type == 0x20) { - StrnCpy(rname,p,15); - trim_string(rname,NULL," "); - return; - } - p += 18; - } -} -#endif /* I_HATE_WINDOWS_REPLY_CODE */ - /******************************************************** Lookup a PDC name given a Domain name and IP address. *********************************************************/ @@ -862,17 +825,9 @@ BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pd * query here... JRA. */ - int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True ); - - if(sock == -1) - return False; - *pdc_name = '\0'; - ret = internal_name_status(sock,"*SMBSERVER",0x20,True, - *pdc_ip,NULL,pdc_name,False,_lookup_pdc_name); - - close(sock); + ret = name_status_find(0x20,*pdc_ip,pdc_name); if(ret && *pdc_name) { fstrcpy(ret_name, pdc_name); diff --git a/source/libsmb/nterr.c b/source/libsmb/nterr.c index f9d717477a0..17bb825219f 100644 --- a/source/libsmb/nterr.c +++ b/source/libsmb/nterr.c @@ -540,9 +540,10 @@ BOOL get_safe_nt_error_msg(uint32 nt_code,char *msg, size_t len) /***************************************************************************** returns an NT error message. not amazingly helpful, but better than a number. *****************************************************************************/ -const char *get_nt_error_msg(uint32 nt_code) +char *get_nt_error_msg(uint32 nt_code) { static pstring msg; + get_safe_nt_error_msg(nt_code, msg, sizeof(msg)); return msg; } diff --git a/source/nmbd/nmbd_packets.c b/source/nmbd/nmbd_packets.c index e26d7f1b166..8b102985611 100644 --- a/source/nmbd/nmbd_packets.c +++ b/source/nmbd/nmbd_packets.c @@ -1902,17 +1902,17 @@ BOOL send_mailslot(BOOL unique, char *mailslot,char *buf,int len, memset((char *)&p,'\0',sizeof(p)); - if(ismyip(dest_ip) && dest_port == 138) /* FIXME, change from constant */ + if(ismyip(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */ loopback_this_packet = True; - generate_name_trn_id(); + /* generate_name_trn_id(); */ /* Not used, so gone, RJS */ /* DIRECT GROUP or UNIQUE datagram. */ dgram->header.msg_type = unique ? 0x10 : 0x11; dgram->header.flags.node_type = M_NODE; dgram->header.flags.first = True; dgram->header.flags.more = False; - dgram->header.dgm_id = name_trn_id; + dgram->header.dgm_id = generate_name_trn_id(); dgram->header.source_ip = src_ip; dgram->header.source_port = DGRAM_PORT; dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */ diff --git a/source/nsswitch/wb_client.c b/source/nsswitch/wb_client.c index 3e32fa3ac9f..142c61d9c1c 100644 --- a/source/nsswitch/wb_client.c +++ b/source/nsswitch/wb_client.c @@ -266,7 +266,8 @@ int winbind_initgroups(char *user, gid_t gid) result = wb_getgroups(user, &groups); - DEBUG(10,("wb_getgroups: %s: result = %s\n", user, result == NSS_STATUS_SUCCESS ? "SUCCESS" : "FAIL")); + DEBUG(10,("wb_getgroups: %s: result = %s\n", user, result == -1 ? + "FAIL" : "SUCCESS")); if (result != -1) { int ngroups = result, i; diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index 91679235cd7..699ddc60b2c 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -35,6 +35,15 @@ static TDB_CONTEXT *tdb; /* used for driver files */ #define DATABASE_VERSION 1 +/* Map generic permissions to printer object specific permissions */ + +struct generic_mapping printer_generic_mapping = { + PRINTER_READ, + PRINTER_WRITE, + PRINTER_EXECUTE, + PRINTER_ALL_ACCESS +}; + /* We need one default form to support our default printer. Msoft adds the forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an array index). Letter is always first, so (for the current code) additions @@ -2833,11 +2842,16 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) prs_struct ps; TALLOC_CTX *mem_ctx = NULL; fstring key; + char *temp; mem_ctx = talloc_init(); if (mem_ctx == NULL) return False; + if ((temp = strchr(printername + 2, '\\'))) { + printername = temp + 1; + } + /* Fetch security descriptor from tdb */ slprintf(key, sizeof(key), "SECDESC/%s", printername); @@ -2910,8 +2924,9 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) sid_to_string(sid_str, &acl->ace[i].sid); - DEBUG(10, ("%s 0x%08x\n", sid_str, - acl->ace[i].info.mask)); + DEBUG(10, ("%s %d %d 0x%08x\n", sid_str, + acl->ace[i].type, acl->ace[i].flags, + acl->ace[i].info.mask)); } } @@ -2956,6 +2971,20 @@ jfm: I should use this comment for the text file to explain */ +/* Convert generic access rights to printer object specific access rights. + It turns out that NT4 security descriptors use generic access rights and + NT5 the object specific ones. */ + +void map_printer_permissions(SEC_DESC *sd) +{ + int i; + + for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { + se_map_generic(&sd->dacl->ace[i].info.mask, + &printer_generic_mapping); + } +} + /**************************************************************************** Check a user has permissions to perform the given operation. We use some constants defined in include/rpc_spoolss.h that look relevant to check @@ -2969,7 +2998,7 @@ jfm: I should use this comment for the text file to explain PRINTER_ACCESS_USE: print_job_start - JOB_ACCESS_ADMINISTER: + PRINTER_ACCESS_ADMINISTER (should really be JOB_ACCESS_ADMINISTER): print_job_delete, print_job_pause, print_job_resume, print_queue_purge @@ -2977,7 +3006,7 @@ jfm: I should use this comment for the text file to explain BOOL print_access_check(struct current_user *user, int snum, int access_type) { SEC_DESC_BUF *secdesc = NULL; - uint32 access_granted, status, required_access = 0; + uint32 access_granted, status; BOOL result; char *pname; extern struct current_user current_user; @@ -3008,77 +3037,14 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) /* Get printer security descriptor */ nt_printing_getsec(pname, &secdesc); - - /* Check against NT4 ACE mask values. From observation these - values are: - - Access Type ACE Mask Constant - ------------------------------------- - Full Control 0x10000000 PRINTER_ACE_FULL_CONTROL - Print 0xe0000000 PRINTER_ACE_PRINT - Manage Documents 0x00020000 PRINTER_ACE_MANAGE_DOCUMENTS - */ - - switch (access_type) { - case PRINTER_ACCESS_USE: - required_access = PRINTER_ACE_PRINT; - break; - case PRINTER_ACCESS_ADMINISTER: - /* - * This should be set to PRINTER_ACE_FULL_CONTROL, not to - * (PRINTER_ACE_PRINT | PRINTER_ACE_MANAGE_DOCUMENTS). - * Doing the latter gives anyone with both PRINTER_ACE_PRINT - * and PRINTER_ACE_MANAGE_DOCUMENTS (in any combination of ACLs) - * full control over all printer functions. This isn't what - * we want. - */ - required_access = PRINTER_ACE_FULL_CONTROL; - break; - case JOB_ACCESS_ADMINISTER: - required_access = PRINTER_ACE_MANAGE_DOCUMENTS; - break; - default: - DEBUG(0, ("invalid value passed to print_access_check()\n")); - result = False; - goto done; - } - if ((result = se_access_check(secdesc->sec, user, required_access, - &access_granted, &status))) { - goto done; - } - - /* Check against NT5 ACE mask values. From observation these - values are: - - Access Type ACE Mask Constant - ------------------------------------- - Full Control 0x000f000c PRINTER_ACE_NT5_FULL_CONTROL - Print 0x00020008 PRINTER_ACE_NT5_PRINT - Manage Documents 0x00020000 PRINTER_ACE_NT5_MANAGE_DOCUMENTS - - NT5 likes to rewrite the security descriptor and change the ACE - masks from NT4 format to NT5 format making them unreadable by - NT4 clients. */ - - switch (access_type) { - case PRINTER_ACCESS_USE: - required_access = PRINTER_ACE_NT5_PRINT; - break; - case PRINTER_ACCESS_ADMINISTER: - required_access = PRINTER_ACE_NT5_FULL_CONTROL; - break; - case JOB_ACCESS_ADMINISTER: - required_access = PRINTER_ACE_NT5_MANAGE_DOCUMENTS; - break; - } - - result = se_access_check(secdesc->sec, user, required_access, + map_printer_permissions(secdesc->sec); + + result = se_access_check(secdesc->sec, user, access_type, &access_granted, &status); /* Check access */ - done: DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE")); /* Free mallocated memory */ diff --git a/source/printing/printing.c b/source/printing/printing.c index 842b97f9c5b..ad7f66fdac9 100644 --- a/source/printing/printing.c +++ b/source/printing/printing.c @@ -168,7 +168,9 @@ static int print_run_command(int snum,char *command, pstring_sub(syscmd, "%p", p); standard_sub_snum(snum,syscmd); - + + /* Convert script args to unix-codepage */ + dos_to_unix(syscmd, True); ret = smbrun(syscmd,outfile,False); DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret)); @@ -575,7 +577,7 @@ BOOL print_job_delete(struct current_user *user, int jobid, int *errcode) owns their job. */ if (!owner && - !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { + !print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { DEBUG(3, ("delete denied by security descriptor\n")); *errcode = ERROR_ACCESS_DENIED; return False; @@ -617,7 +619,7 @@ BOOL print_job_pause(struct current_user *user, int jobid, int *errcode) owner = is_owner(user, jobid); if (!owner && - !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { + !print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { DEBUG(3, ("pause denied by security descriptor\n")); *errcode = ERROR_ACCESS_DENIED; return False; @@ -668,7 +670,7 @@ BOOL print_job_resume(struct current_user *user, int jobid, int *errcode) owner = is_owner(user, jobid); if (!is_owner(user, jobid) && - !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { + !print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { DEBUG(3, ("resume denied by security descriptor\n")); *errcode = ERROR_ACCESS_DENIED; return False; @@ -807,7 +809,7 @@ int print_job_start(struct current_user *user, int snum, char *jobname) return -1; } - if (print_queue_length(snum) > lp_maxprintjobs(snum)) { + if (lp_maxprintjobs(snum) && print_queue_length(snum) > lp_maxprintjobs(snum)) { errno = ENOSPC; return -1; } @@ -1202,7 +1204,7 @@ BOOL print_queue_purge(struct current_user *user, int snum, int *errcode) njobs = print_queue_status(snum, &queue, &status); for (i=0;i<njobs;i++) { - if (print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { + if (print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { print_job_delete1(queue[i].job); } } diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index cd67a3b88a1..155bda7cd51 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -655,10 +655,16 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername, uint32 user_switch, SPOOL_USER_CTR user_ctr, POLICY_HND *handle) { + uint32 result = NT_STATUS_NO_PROBLEMO; + SEC_DESC_BUF *sec_desc = NULL; + uint32 acc_granted, status; fstring name; + extern struct current_user current_user; - if (printername == NULL) - return ERROR_INVALID_PRINTER_NAME; + if (printername == NULL) { + result = ERROR_INVALID_PRINTER_NAME; + goto done; + } /* some sanity check because you can open a printer or a print server */ /* aka: \\server\printer or \\server */ @@ -666,8 +672,10 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername, DEBUGADD(3,("checking name: %s\n",name)); - if (!open_printer_hnd(handle, name)) - return ERROR_INVALID_PRINTER_NAME; + if (!open_printer_hnd(handle, name)) { + result = ERROR_INVALID_PRINTER_NAME; + goto done; + } /* if (printer_default->datatype_ptr != NULL) @@ -681,7 +689,8 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername, if (!set_printer_hnd_accesstype(handle, printer_default->access_required)) { close_printer_handle(handle); - return ERROR_ACCESS_DENIED; + result = ERROR_ACCESS_DENIED; + goto done; } /* Disallow MS AddPrinterWizard if parameter disables it. A Win2k @@ -696,13 +705,41 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername, if (handle_is_printserver(handle) && !lp_ms_add_printer_wizard()) { - if (printer_default->access_required == 0) - return NT_STATUS_NO_PROBLEMO; - else if (printer_default->access_required != (SERVER_READ)) - return ERROR_ACCESS_DENIED; + if (printer_default->access_required == 0) { + goto done; + } + else if (printer_default->access_required != (SERVER_READ)) { + close_printer_handle(handle); + result = ERROR_ACCESS_DENIED; + goto done; + } } - return NT_STATUS_NO_PROBLEMO; + /* NT doesn't let us connect to a printer if the connecting user + doesn't have print permission. If no security descriptor just + return OK. */ + + if (!nt_printing_getsec(name, &sec_desc)) { + goto done; + } + + /* Yuck - we should use the pipe_user rather than current_user but + it doesn't seem to be filled in correctly. )-: */ + + map_printer_permissions(sec_desc->sec); + + if (!se_access_check(sec_desc->sec, ¤t_user, PRINTER_ACCESS_USE, + &acc_granted, &status)) { + DEBUG(3, ("access DENIED for printer open\n")); + close_printer_handle(handle); + result = ERROR_ACCESS_DENIED; + goto done; + } + + done: + free_sec_desc_buf(&sec_desc); + + return result; } /**************************************************************************** @@ -3509,6 +3546,9 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer) printer->info_2->location, driverlocation); unlink(tmp_file); + + /* Convert script args to unix-codepage */ + dos_to_unix(command, True); DEBUG(10,("Running [%s > %s]\n", command,tmp_file)); ret = smbrun(command, tmp_file, False); DEBUGADD(10,("returned [%d]\n", ret)); @@ -3519,9 +3559,10 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer) } numlines = 0; + /* Get lines and convert them back to dos-codepage */ qlines = file_lines_load(tmp_file, &numlines, True); DEBUGADD(10,("Lines returned = [%d]\n", numlines)); - DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file)); + DEBUGADD(10,("Unlinking script output file [%s]\n", tmp_file)); unlink(tmp_file); if(numlines) { diff --git a/source/rpcclient/cmd_spoolss.c b/source/rpcclient/cmd_spoolss.c index 392f31b625d..58ee1ca0c11 100644 --- a/source/rpcclient/cmd_spoolss.c +++ b/source/rpcclient/cmd_spoolss.c @@ -149,7 +149,7 @@ uint32 cmd_spoolss_enum_ports(struct client_info *info, int argc, char *argv[]) uint32 level; fstring srv_name; - if (argc < 1) + if (argc < 2) { report (out_hnd, "spoolenumports <level>\n"); return NT_STATUS_INVALID_PARAMETER; @@ -179,7 +179,7 @@ uint32 cmd_spoolss_enum_printerdata(struct client_info *info, int argc, char *ar fstring station; char *printer_name; - if (argc < 1) { + if (argc < 2) { report(out_hnd, "spoolenumdata <printer name>\n"); return NT_STATUS_INVALID_PARAMETER; } @@ -224,7 +224,7 @@ uint32 cmd_spoolss_getprinter(struct client_info *info, int argc, char *argv[]) char *printer_name; uint32 level; - if (argc < 1) { + if (argc < 2) { report(out_hnd, "spoolgetprinter <printer name>\n"); return NT_STATUS_INVALID_PARAMETER; } @@ -246,7 +246,7 @@ uint32 cmd_spoolss_getprinter(struct client_info *info, int argc, char *argv[]) printer_name = srv_name; } - if (argc < 3) + if (argc < 4) level=2; else level = atoi(argv[2]); @@ -282,7 +282,7 @@ uint32 cmd_spoolss_enum_jobs(struct client_info *info, int argc, char *argv[]) void **ctr = NULL; uint32 level = 1; - if (argc < 1) { + if (argc < 2) { report(out_hnd, "spooljobs <printer name>\n"); return NT_STATUS_INVALID_PARAMETER; } @@ -330,7 +330,7 @@ uint32 cmd_spoolss_open_printer_ex(struct client_info *info, int argc, char *arg BOOL res = True; - if (argc < 1) + if (argc < 2) { report(out_hnd, "spoolopen <printer name>\n"); return NT_STATUS_INVALID_PARAMETER; @@ -385,7 +385,7 @@ uint32 cmd_spoolss_getprinterdata(struct client_info *info, int argc, char *argv uint32 status; uint32 type = 1; - if (argc < 2) { + if (argc < 3) { report(out_hnd, "spoolgetdata <printer name> <value name>\n"); return NT_STATUS_INVALID_PARAMETER; } @@ -441,7 +441,7 @@ uint32 cmd_spoolss_getprinterdriver(struct client_info *info, int argc, char *ar fstring environment; uint32 level; - if (argc < 1) { + if (argc < 2) { report(out_hnd, "spoolgetprinterdriver <printer name>\n"); return NT_STATUS_INVALID_PARAMETER; } @@ -524,14 +524,14 @@ uint32 cmd_spoolss_getprinterdriverdir(struct client_info *info, int argc, char fstrcat(srv_name, info->dest_host); strupper(srv_name); - if (argc < 1) { + if (argc < 2) { report(out_hnd, "spoolgetprinterdriverdir <arch>\n"); return NT_STATUS_NOPROBLEMO; } fstrcpy(env, argv[1]); - for (i=2; i<=argc; i++) { + for (i=3; i<=argc; i++) { fstrcat(env, " "); fstrcat(env, argv[i]); } @@ -571,7 +571,7 @@ uint32 cmd_spoolss_addprinterex(struct client_info *info, int argc, char *argv[] strupper(srv_name); /* check (and copy) the command line arguments */ - if (argc < 4) { + if (argc < 5) { report(out_hnd, "spooladdprinterex <name> <shared name> <driver> <port>\n"); return NT_STATUS_INVALID_PARAMETER; } @@ -701,7 +701,7 @@ uint32 cmd_spoolss_addprinterdriver(struct client_info *info, int argc, char *ar uint32 result = NT_STATUS_NO_PROBLEMO; /* parse the command arguements */ - if (argc < 2) + if (argc < 3) { report (out_hnd, "spooladdprinterdriver <arch>\\\n"); report (out_hnd, "\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n"); diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk index b36eaca33bb..c66fe07972f 100644 --- a/source/script/mkproto.awk +++ b/source/script/mkproto.awk @@ -108,17 +108,22 @@ END { gotstart = 1; } - if( $0 ~ /^vuser_key|^UNISTR2|^LOCAL_GRP|^DOMAIN_GRP|^SMB_STRUCT_DIRENT|^SEC_ACL|^SEC_DESC|^SEC_DESC_BUF|^DOM_SID|^RPC_HND_NODE/ ) { + if( $0 ~ /^vuser_key|^UNISTR2|^LOCAL_GRP|^DOMAIN_GRP|^SMB_STRUCT_DIRENT|^SEC_ACL|^SEC_DESC|^SEC_DESC_BUF|^DOM_SID|^RPC_HND_NODE|^BYTE/ ) { gotstart = 1; } - if( $0 ~ /^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum nss_status|^NT_USER_TOKEN/ ) { + if( $0 ~ /^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum nss_status|^NT_USER_TOKEN|^SAM_ACCOUNT/ ) { gotstart = 1; } if( $0 ~ /^long|^char|^uint|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^enum remote_arch_types|^FILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT/ ) { gotstart = 1; } + + if( $0 ~ /^SAM_ACCT_INFO_NODE|^SMB_ACL_T/ ) { + gotstart = 1; + } + if(!gotstart) { next; } diff --git a/source/smbd/password.c b/source/smbd/password.c index 5e31d1837ad..411098fbc96 100644 --- a/source/smbd/password.c +++ b/source/smbd/password.c @@ -176,6 +176,7 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, DOM_SID *psids; int i, psid_ndx = 0; size_t num_sids = 0; + fstring sid_str; if ((token = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) return NULL; @@ -229,6 +230,13 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, token->num_sids = psid_ndx; + /* Dump list of sids in token */ + + for (i = 0; i < token->num_sids; i++) { + DEBUG(5, ("user token sid %s\n", + sid_to_string(sid_str, &token->user_sids[i]))); + } + return token; } diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c index eaaae9ace77..f3cc9e04e0b 100644 --- a/source/smbd/sec_ctx.c +++ b/source/smbd/sec_ctx.c @@ -305,11 +305,23 @@ BOOL push_sec_ctx(void) void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token) { struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; - + /* Set the security context */ DEBUG(3, ("setting sec ctx (%d, %d) - sec_ctx_stack_ndx = %d\n", uid, gid, sec_ctx_stack_ndx)); + if (ngroups) { + int i; + + DEBUG(3, ("%d user groups: \n", ngroups)); + for (i = 0; i < ngroups; i++) { + DEBUGADD(3, ("%d ", groups[i])); + } + + DEBUG(3, ("\n")); + } + + gain_root(); #ifdef HAVE_SETGROUPS diff --git a/source/smbwrapper/smbw.c b/source/smbwrapper/smbw.c index 07b450505ec..91009af1c58 100644 --- a/source/smbwrapper/smbw.c +++ b/source/smbwrapper/smbw.c @@ -79,6 +79,10 @@ void smbw_init(void) load_interfaces(); + if ((p=smbw_getshared("SERVICESF"))) { + pstrcpy(servicesf, p); + } + lp_load(servicesf,True,False,False); get_myname(global_myname); @@ -246,87 +250,106 @@ void clean_fname(char *name) } + +/***************************************************** +find a workgroup (any workgroup!) that has a master +browser on the local network +*******************************************************/ +static char *smbw_find_workgroup(void) +{ + fstring server; + char *p; + struct in_addr *ip_list = NULL; + int count = 0; + int i; + + /* first off see if an existing workgroup name exists */ + p = smbw_getshared("WORKGROUP"); + if (!p) p = lp_workgroup(); + + slprintf(server, sizeof(server), "%s#1D", p); + if (smbw_server(server, "IPC$")) return p; + + /* go looking for workgroups */ + if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { + DEBUG(1,("No workgroups found!")); + return p; + } + + for (i=0;i<count;i++) { + static fstring name; + if (name_status_find(0x1d, ip_list[i], name)) { + slprintf(server, sizeof(server), "%s#1D", name); + if (smbw_server(server, "IPC$")) { + free(ip_list); + return name; + } + } + } + + free(ip_list); + + return p; +} + /***************************************************** parse a smb path into its components. +server is one of + 1) the name of the SMB server + 2) WORKGROUP#1D for share listing + 3) WORKGROUP#__ for workgroup listing +share is the share on the server to query +path is the SMB path on the server +return the full path (ie. add cwd if needed) *******************************************************/ char *smbw_parse_path(const char *fname, char *server, char *share, char *path) { static pstring s; - char *p, *p2; - int len = strlen(smbw_prefix)-1; - - *server = *share = *path = 0; + char *p; + int len; + fstring workgroup; - if (fname[0] == '/') { - pstrcpy(s, fname); + /* add cwd if necessary */ + if (fname[0] != '/') { + slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname); } else { - slprintf(s,sizeof(s)-1, "%s/%s", smbw_cwd, fname); + pstrcpy(s, fname); } clean_fname(s); - DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n", - s, fname, smbw_cwd)); - + /* see if it has the right prefix */ + len = strlen(smbw_prefix)-1; if (strncmp(s,smbw_prefix,len) || (s[len] != '/' && s[len] != 0)) return s; - p = s + len; + /* ok, its for us. Now parse out the workgroup, share etc. */ + p = s+len; if (*p == '/') p++; - - p2 = strchr(p,'/'); - - if (p2) { - len = (int)(p2-p); - } else { - len = strlen(p); - } - - len = MIN(len,sizeof(fstring)-1); - - strncpy(server, p, len); - server[len] = 0; - - p = p2; - if (!p) { - if (len == 0) { - char *workgroup = smbw_getshared("WORKGROUP"); - if (!workgroup) workgroup = lp_workgroup(); - slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup); - } + if (!next_token(&p, workgroup, "/", sizeof(fstring))) { + /* we're in /smb - give a list of workgroups */ + slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup()); fstrcpy(share,"IPC$"); pstrcpy(path,""); - goto ok; + return s; } - p++; - p2 = strchr(p,'/'); - - if (p2) { - len = (int)(p2-p); - } else { - len = strlen(p); + if (!next_token(&p, server, "/", sizeof(fstring))) { + /* we are in /smb/WORKGROUP */ + slprintf(server,sizeof(fstring), "%s#1D", workgroup); + fstrcpy(share,"IPC$"); + pstrcpy(path,""); } - len = MIN(len,sizeof(fstring)-1); - - strncpy(share, p, len); - share[len] = 0; - - p = p2; - if (!p) { - pstrcpy(path,"\\"); - goto ok; + if (!next_token(&p, share, "/", sizeof(fstring))) { + /* we are in /smb/WORKGROUP/SERVER */ + fstrcpy(share,"IPC$"); + pstrcpy(path,""); } - pstrcpy(path,p); + pstrcpy(path, p); all_string_sub(path, "/", "\\", 0); - ok: - DEBUG(4,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n", - fname, smbw_cwd, - server, share, path)); - return s; } @@ -437,7 +460,7 @@ struct smbw_server *smbw_server(char *server, char *share) ip = ipzero; ZERO_STRUCT(c); - + get_auth_data_fn(server, share, &workgroup, &username, &password); /* try to use an existing connection */ @@ -459,7 +482,8 @@ struct smbw_server *smbw_server(char *server, char *share) DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server)); - if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) { + if ((p=strchr(server_n,'#')) && + (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) { struct in_addr sip; pstring s; diff --git a/source/smbwrapper/smbw_dir.c b/source/smbwrapper/smbw_dir.c index 09294282736..89d137473f3 100644 --- a/source/smbwrapper/smbw_dir.c +++ b/source/smbwrapper/smbw_dir.c @@ -78,7 +78,7 @@ static struct smbw_dir *cur_dir; /***************************************************** add a entry to a directory listing *******************************************************/ -static void smbw_dir_add(struct file_info *finfo, const char *mask) +static void smbw_dir_add(struct file_info *finfo, const char *mask, void * NULL) { DEBUG(5,("%s\n", finfo->name)); @@ -100,7 +100,8 @@ static void smbw_dir_add(struct file_info *finfo, const char *mask) /***************************************************** add a entry to a directory listing *******************************************************/ -static void smbw_share_add(const char *share, uint32 type, const char *comment) +static void smbw_share_add(const char *share, uint32 type, + const char *comment, void *state) { struct file_info finfo; @@ -119,7 +120,7 @@ static void smbw_share_add(const char *share, uint32 type, const char *comment) add a server to a directory listing *******************************************************/ static void smbw_server_add(const char *name, uint32 type, - const char *comment) + const char *comment, void *state) { struct file_info finfo; @@ -199,36 +200,45 @@ int smbw_dir_open(const char *fname) slprintf(mask, sizeof(mask)-1, "%s\\*", path); all_string_sub(mask,"\\\\","\\",0); - if ((p=strstr(srv->server_name,"#1D"))) { + if ((p=strstr(srv->server_name,"#01"))) { + *p = 0; + smbw_server_add(".",0,"", NULL); + smbw_server_add("..",0,"", NULL); + cli_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_DOMAIN_ENUM, + smbw_server_add, NULL); + *p = '#'; + } else if ((p=strstr(srv->server_name,"#1D"))) { DEBUG(4,("doing NetServerEnum\n")); *p = 0; - smbw_server_add(".",0,""); - smbw_server_add("..",0,""); + smbw_server_add(".",0,"", NULL); + smbw_server_add("..",0,"", NULL); cli_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL, - smbw_server_add); + smbw_server_add, NULL); *p = '#'; } else if (strcmp(srv->cli.dev,"IPC") == 0) { DEBUG(4,("doing NetShareEnum\n")); - smbw_share_add(".",0,""); - smbw_share_add("..",0,""); - if (cli_RNetShareEnum(&srv->cli, smbw_share_add) < 0) { + smbw_share_add(".",0,"", NULL); + smbw_share_add("..",0,"", NULL); + if (cli_RNetShareEnum(&srv->cli, smbw_share_add, NULL) < 0) { errno = smbw_errno(&srv->cli); goto failed; } } else if (strncmp(srv->cli.dev,"LPT",3) == 0) { - smbw_share_add(".",0,""); - smbw_share_add("..",0,""); + smbw_share_add(".",0,"", NULL); + smbw_share_add("..",0,"", NULL); if (cli_print_queue(&srv->cli, smbw_printjob_add) < 0) { errno = smbw_errno(&srv->cli); goto failed; } } else { +#if 0 if (strcmp(path,"\\") == 0) { smbw_share_add(".",0,""); smbw_share_add("..",0,""); } +#endif if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR, - smbw_dir_add) < 0) { + smbw_dir_add, NULL) < 0) { errno = smbw_errno(&srv->cli); goto failed; } diff --git a/source/smbwrapper/smbw_stat.c b/source/smbwrapper/smbw_stat.c index c84140f3629..926075c864f 100644 --- a/source/smbwrapper/smbw_stat.c +++ b/source/smbwrapper/smbw_stat.c @@ -180,6 +180,7 @@ int smbw_stat(const char *fname, struct stat *st) size_t size=0; uint16 mode=0; SMB_INO_T ino = 0; + int result = 0; ZERO_STRUCTP(st); @@ -200,8 +201,19 @@ int smbw_stat(const char *fname, struct stat *st) /* get a connection to the server */ srv = smbw_server(server, share); if (!srv) { + + /* For shares we aren't allowed to connect to, return + an empty directory */ + + if (server[0] && share[0] && !path[0] && errno == EACCES) { + mode = aDIR | aRONLY; + smbw_setup_stat(st, path, size, mode); + goto done; + } + /* smbw_server sets errno */ - goto failed; + result = -1; + goto done; } DEBUG(4,("smbw_stat\n")); @@ -221,7 +233,8 @@ int smbw_stat(const char *fname, struct stat *st) &mode, &size, &c_time, &a_time, &m_time, &ino)) { errno = smbw_errno(&srv->cli); - goto failed; + result = -1; + goto done; } } @@ -234,10 +247,7 @@ int smbw_stat(const char *fname, struct stat *st) st->st_mtime = m_time; st->st_dev = srv->dev; + done: smbw_busy--; - return 0; - - failed: - smbw_busy--; - return -1; + return result; } diff --git a/source/tdb/tdb.c b/source/tdb/tdb.c index afc87b7da07..474d0c7adb3 100644 --- a/source/tdb/tdb.c +++ b/source/tdb/tdb.c @@ -850,9 +850,14 @@ int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state) { TDB_DATA key, dbuf; struct list_struct rec; - struct tdb_traverse_lock tl = { tdb->travlocks.next, 0, 0 }; + struct tdb_traverse_lock tl = { NULL, 0, 0 }; int ret, count = 0; + /* This was in the initializaton, above, but the IRIX compiler + * did not like it. crh + */ + tl.next = tdb->travlocks.next; + /* fcntl locks don't stack: beware traverse inside traverse */ tdb->travlocks.next = &tl; diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c index 2cdd85fae85..4e85f6ac456 100644 --- a/source/utils/nmblookup.c +++ b/source/utils/nmblookup.c @@ -80,6 +80,55 @@ static void usage(void) printf("\n"); } +/**************************************************************************** +turn a node status flags field into a string +****************************************************************************/ +static char *node_status_flags(unsigned char flags) +{ + static fstring ret; + fstrcpy(ret,""); + + fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " "); + if ((flags & 0x60) == 0x00) fstrcat(ret,"B "); + if ((flags & 0x60) == 0x20) fstrcat(ret,"P "); + if ((flags & 0x60) == 0x40) fstrcat(ret,"M "); + if ((flags & 0x60) == 0x60) fstrcat(ret,"H "); + if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> "); + if (flags & 0x08) fstrcat(ret,"<CONFLICT> "); + if (flags & 0x04) fstrcat(ret,"<ACTIVE> "); + if (flags & 0x02) fstrcat(ret,"<PERMANENT> "); + + return ret; +} + +/**************************************************************************** +do a node status query +****************************************************************************/ +static void do_node_status(int fd, char *name, int type, struct in_addr ip) +{ + struct nmb_name nname; + int count, i, j; + struct node_status *status; + fstring cleanname; + + printf("Looking up status of %s\n",inet_ntoa(ip)); + make_nmb_name(&nname, name, type); + status = name_status_query(fd,&nname,ip, &count); + if (status) { + for (i=0;i<count;i++) { + fstrcpy(cleanname, status[i].name); + for (j=0;cleanname[j];j++) { + if (!isprint(cleanname[j])) cleanname[j] = '.'; + } + printf("\t%-15s <%02x> - %s\n", + cleanname,status[i].type, + node_status_flags(status[i].flags)); + } + free(status); + } + printf("\n"); +} + /**************************************************************************** send out one query @@ -125,9 +174,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type) was valid - ie. name_query returned true. */ if (find_status) { - printf("Looking up status of %s\n",inet_ntoa(ip_list[0])); - name_status(ServerFD,lookup,lookup_type,True,ip_list[0],NULL,NULL); - printf("\n"); + do_node_status(ServerFD, lookup, lookup_type, ip_list[0]); } safe_free(ip_list); @@ -245,9 +292,7 @@ int main(int argc,char *argv[]) { fstrcpy(lookup,"*"); ip = *interpret_addr2(argv[i]); - printf("Looking up status of %s\n",inet_ntoa(ip)); - name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL); - printf("\n"); + do_node_status(ServerFD, lookup, lookup_type, ip); continue; } diff --git a/source/utils/smbcacls.c b/source/utils/smbcacls.c index f8059a8b8b8..7600989655e 100644 --- a/source/utils/smbcacls.c +++ b/source/utils/smbcacls.c @@ -37,6 +37,7 @@ static int numeric; enum acl_mode {ACL_SET, ACL_DELETE, ACL_MODIFY, 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; @@ -108,18 +109,19 @@ static void SidToString(fstring str, DOM_SID *sid) /* Ask LSA to convert the sid to a name */ - if (open_policy_hnd() && + if (!open_policy_hnd() || cli_lsa_lookup_sids(&lsa_cli, &pol, 1, sid, &names, &types, - &num_names) == NT_STATUS_NOPROBLEMO) { - - /* Converted OK */ - - fstrcpy(str, names[0]); - - safe_free(names[0]); - safe_free(names); - safe_free(types); + &num_names) != NT_STATUS_NOPROBLEMO) { + return; } + + /* Converted OK */ + + fstrcpy(str, names[0]); + + safe_free(names[0]); + safe_free(names); + safe_free(types); } /* convert a string to a SID, either numeric or username/group */ @@ -130,17 +132,14 @@ static BOOL StringToSid(DOM_SID *sid, char *str) int num_sids; BOOL result = True; - /* Short cut */ - if (strncmp(str, "S-", 2) == 0) { - result = string_to_sid(sid, str); - goto done; + return string_to_sid(sid, str); } - if (open_policy_hnd() && + if (!open_policy_hnd() || cli_lsa_lookup_names(&lsa_cli, &pol, 1, &str, &sids, &types, &num_sids) != NT_STATUS_NOPROBLEMO) { - result = string_to_sid(sid, str); + result = False; goto done; } @@ -347,7 +346,7 @@ static SEC_DESC *sec_desc_parse(char *str) SEC_ACL *dacl=NULL; int revision=1; - while (next_token(&p, tok, " \t,\r\n", sizeof(tok))) { + while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { if (strncmp(tok,"REVISION:", 9) == 0) { revision = strtol(tok+9, NULL, 16); @@ -438,28 +437,51 @@ static void sec_desc_print(FILE *f, SEC_DESC *sd) } +/* Some systems seem to require unicode pathnames for the ntcreate&x call + despite Samba negotiating ascii filenames. Try with unicode pathname if + the ascii version fails. */ + +int do_cli_nt_create(struct cli_state *cli, char *fname, uint32 DesiredAccess) +{ + int result; + + result = cli_nt_create(cli, fname, DesiredAccess); + + if (result == -1) { + uint32 errnum, nt_rpc_error; + uint8 errclass; + + cli_error(cli, &errclass, &errnum, &nt_rpc_error); + + if (errclass == ERRDOS && errnum == ERRbadpath) { + result = cli_nt_create_uni(cli, fname, DesiredAccess); + } + } + + return result; +} /***************************************************** dump the acls for a file *******************************************************/ -static void cacl_dump(struct cli_state *cli, char *filename) +static int cacl_dump(struct cli_state *cli, char *filename) { int fnum; SEC_DESC *sd; - if (test_args) return; + if (test_args) return EXIT_OK; - fnum = cli_nt_create(cli, filename, 0x20000); + fnum = do_cli_nt_create(cli, filename, 0x20000); if (fnum == -1) { printf("Failed to open %s: %s\n", filename, cli_errstr(cli)); - return; + return EXIT_FAILED; } sd = cli_query_secdesc(cli, fnum); if (!sd) { printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli)); - return; + return EXIT_FAILED; } sec_desc_print(stdout, sd); @@ -467,6 +489,8 @@ static void cacl_dump(struct cli_state *cli, char *filename) free_sec_desc(&sd); cli_close(cli, fnum); + + return EXIT_OK; } /***************************************************** @@ -474,21 +498,25 @@ Change the ownership or group ownership of a file. Just because the NT docs say this can't be done :-). JRA. *******************************************************/ -static void owner_set(struct cli_state *cli, enum chown_mode change_mode, char *filename, char *new_username) +static int owner_set(struct cli_state *cli, enum chown_mode change_mode, + char *filename, char *new_username) { int fnum; DOM_SID sid; SEC_DESC *sd, *old; size_t sd_size; - fnum = cli_nt_create(cli, filename, READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS); + fnum = do_cli_nt_create(cli, filename, + READ_CONTROL_ACCESS | WRITE_DAC_ACCESS + | WRITE_OWNER_ACCESS); + if (fnum == -1) { printf("Failed to open %s: %s\n", filename, cli_errstr(cli)); - return; + return EXIT_FAILED; } if (!StringToSid(&sid, new_username)) - return; + return EXIT_PARSE_ERROR; old = cli_query_secdesc(cli, fnum); @@ -505,30 +533,81 @@ static void owner_set(struct cli_state *cli, enum chown_mode change_mode, char * free_sec_desc(&old); cli_close(cli, fnum); + + return EXIT_OK; +} + +/* 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 void sort_acl(SEC_ACL *the_acl) +{ + SEC_ACE *tmp_ace; + int i, ace_ndx = 0; + BOOL do_denied = True; + + tmp_ace = (SEC_ACE *)malloc(sizeof(SEC_ACE) * the_acl->num_aces); + + if (!tmp_ace) return; + + copy_aces: + + for (i = 0; i < the_acl->num_aces; i++) { + + /* Copy denied ACEs */ + + if (do_denied && + the_acl->ace[i].type == SEC_ACE_TYPE_ACCESS_DENIED) { + tmp_ace[ace_ndx] = the_acl->ace[i]; + ace_ndx++; + } + + /* Copy other ACEs */ + + if (!do_denied && + the_acl->ace[i].type != SEC_ACE_TYPE_ACCESS_DENIED) { + tmp_ace[ace_ndx] = the_acl->ace[i]; + ace_ndx++; + } + } + + if (do_denied) { + do_denied = False; + goto copy_aces; + } + + free(the_acl->ace); + the_acl->ace = tmp_ace; } /***************************************************** set the ACLs on a file given an ascii description *******************************************************/ -static void cacl_set(struct cli_state *cli, char *filename, - char *the_acl, enum acl_mode mode) +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; - if (test_args) return; + 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 = do_cli_nt_create(cli, filename, + MAXIMUM_ALLOWED_ACCESS | 0x60000); - /* the desired access below is the only one I could find that works with - NT4, W2KP and Samba */ - fnum = cli_nt_create(cli, filename, MAXIMUM_ALLOWED_ACCESS | 0x60000); if (fnum == -1) { printf("Failed to open %s: %s\n", filename, cli_errstr(cli)); - return; + return EXIT_FAILED; } old = cli_query_secdesc(cli, fnum); @@ -605,17 +684,28 @@ static void cacl_set(struct cli_state *cli, char *filename, free_sec_desc(&sd); } + /* Denied ACE entries must come before allowed ones */ + + sort_acl(old->dacl); + + /* Create new security descriptor and set it */ + sd = make_sec_desc(old->revision, old->owner_sid, old->grp_sid, NULL, old->dacl, &sd_size); if (!cli_set_secdesc(cli, fnum, sd)) { printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli)); + result = EXIT_FAILED; } + /* Clean up */ + free_sec_desc(&sd); free_sec_desc(&old); cli_close(cli, fnum); + + return result; } @@ -712,7 +802,7 @@ struct cli_state *connect_one(char *share) static void usage(void) { printf( -"Usage: smbcacls //server1/share1 filename -U username [options]\n\ +"Usage: smbcacls //server1/share1 filename [options]\n\ \n\ \t-D <acls> delete an acl\n\ \t-M <acls> modify an acl\n\ @@ -748,14 +838,15 @@ You can string acls together with spaces, commas or newlines\n\ enum acl_mode mode; char *the_acl = NULL; enum chown_mode change_mode = REQUEST_NONE; + int result; setlinebuf(stdout); dbf = stderr; - if (argc < 4 || argv[1][0] == '-') { + if (argc < 3 || argv[1][0] == '-') { usage(); - exit(1); + exit(EXIT_PARSE_ERROR); } setup_logging(argv[0],True); @@ -776,6 +867,14 @@ You can string acls together with spaces, commas or newlines\n\ if (getenv("USER")) { pstrcpy(username,getenv("USER")); + + if ((p=strchr(username,'%'))) { + *p = 0; + pstrcpy(password,p+1); + got_pass = True; + memset(strchr(getenv("USER"), '%') + 1, 'X', + strlen(password)); + } } seed = time(NULL); @@ -832,11 +931,11 @@ You can string acls together with spaces, commas or newlines\n\ case 'h': usage(); - exit(1); + exit(EXIT_PARSE_ERROR); default: printf("Unknown option %c (%d)\n", (char)opt, opt); - exit(1); + exit(EXIT_PARSE_ERROR); } } @@ -845,21 +944,35 @@ You can string acls together with spaces, commas or newlines\n\ if (argc > 0) { usage(); - exit(1); + exit(EXIT_PARSE_ERROR); } + /* Make connection to server */ + if (!test_args) { cli = connect_one(share); - if (!cli) exit(1); + if (!cli) exit(EXIT_FAILED); + } + + { + char *s; + + s = filename; + while(*s) { + if (*s == '/') *s = '\\'; + s++; + } } + /* Perform requested action */ + if (change_mode != REQUEST_NONE) { - owner_set(cli, change_mode, filename, owner_username); + result = owner_set(cli, change_mode, filename, owner_username); } else if (the_acl) { - cacl_set(cli, filename, the_acl, mode); + result = cacl_set(cli, filename, the_acl, mode); } else { - cacl_dump(cli, filename); + result = cacl_dump(cli, filename); } - return(0); + return result; } |