diff options
Diffstat (limited to 'source/smbd/nttrans.c')
-rw-r--r-- | source/smbd/nttrans.c | 1200 |
1 files changed, 664 insertions, 536 deletions
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 1f3bbd488e5..b80cac8d3c3 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -1,5 +1,6 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 1.9. SMB NT transaction handling Copyright (C) Jeremy Allison 1994-1998 @@ -28,28 +29,30 @@ extern BOOL case_preserve; extern BOOL short_case_preserve; static char *known_nt_pipes[] = { - "\\LANMAN", - "\\srvsvc", - "\\samr", - "\\wkssvc", - "\\NETLOGON", - "\\ntlsa", - "\\ntsvcs", - "\\lsass", - "\\lsarpc", - "\\winreg", - "\\spoolss", - "\\netdfs", - NULL + "\\LANMAN", + "\\srvsvc", + "\\samr", + "\\wkssvc", + "\\NETLOGON", + "\\ntlsa", + "\\ntsvcs", + "\\lsass", + "\\lsarpc", + "\\winreg", + "\\spoolss", +#ifdef WITH_MSDFS + "\\netdfs", +#endif + NULL }; /* Map generic permissions to file object specific permissions */ struct generic_mapping file_generic_mapping = { - FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_GENERIC_ALL + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_GENERIC_ALL }; /**************************************************************************** @@ -62,183 +65,257 @@ struct generic_mapping file_generic_mapping = { static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params, int paramsize, char *pdata, int datasize) { - extern int max_send; - int data_to_send = datasize; - int params_to_send = paramsize; - int useable_space; - char *pp = params; - char *pd = pdata; - int params_sent_thistime, data_sent_thistime, total_sent_thistime; - int alignment_offset = 3; - int data_alignment_offset = 0; - - /* - * Initially set the wcnt area to be 18 - this is true for all - * transNT replies. - */ + extern int max_send; + int data_to_send = datasize; + int params_to_send = paramsize; + int useable_space; + char *pp = params; + char *pd = pdata; + int params_sent_thistime, data_sent_thistime, total_sent_thistime; + int alignment_offset = 3; + int data_alignment_offset = 0; + + /* + * Initially set the wcnt area to be 18 - this is true for all + * transNT replies. + */ + + set_message(outbuf,18,0,True); + + if(NT_STATUS_V(nt_error)) { + ERROR_NT(nt_error); + } + + /* + * If there genuinely are no parameters or data to send just send + * the empty packet. + */ + + if(params_to_send == 0 && data_to_send == 0) { + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_nt_replies: send_smb failed."); + return 0; + } + + /* + * When sending params and data ensure that both are nicely aligned. + * Only do this alignment when there is also data to send - else + * can cause NT redirector problems. + */ + + if (((params_to_send % 4) != 0) && (data_to_send != 0)) + data_alignment_offset = 4 - (params_to_send % 4); + + /* + * Space is bufsize minus Netbios over TCP header minus SMB header. + * The alignment_offset is to align the param bytes on a four byte + * boundary (2 bytes for data len, one byte pad). + * NT needs this to work correctly. + */ + + useable_space = bufsize - ((smb_buf(outbuf)+ + alignment_offset+data_alignment_offset) - + outbuf); + + /* + * useable_space can never be more than max_send minus the + * alignment offset. + */ + + useable_space = MIN(useable_space, + max_send - (alignment_offset+data_alignment_offset)); + + + while (params_to_send || data_to_send) { + + /* + * Calculate whether we will totally or partially fill this packet. + */ + + total_sent_thistime = params_to_send + data_to_send + + alignment_offset + data_alignment_offset; + + /* + * We can never send more than useable_space. + */ + + total_sent_thistime = MIN(total_sent_thistime, useable_space); + + set_message(outbuf, 18, total_sent_thistime, True); + + /* + * Set total params and data to be sent. + */ + + SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize); + SIVAL(outbuf,smb_ntr_TotalDataCount,datasize); + + /* + * Calculate how many parameters and data we can fit into + * this packet. Parameters get precedence. + */ + + params_sent_thistime = MIN(params_to_send,useable_space); + data_sent_thistime = useable_space - params_sent_thistime; + data_sent_thistime = MIN(data_sent_thistime,data_to_send); + + SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime); + + if(params_sent_thistime == 0) { + SIVAL(outbuf,smb_ntr_ParameterOffset,0); + SIVAL(outbuf,smb_ntr_ParameterDisplacement,0); + } else { + /* + * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the + * parameter bytes, however the first 4 bytes of outbuf are + * the Netbios over TCP header. Thus use smb_base() to subtract + * them from the calculation. + */ + + SIVAL(outbuf,smb_ntr_ParameterOffset, + ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); + /* + * Absolute displacement of param bytes sent in this packet. + */ + + SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params); + } + + /* + * Deal with the data portion. + */ + + SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime); + + if(data_sent_thistime == 0) { + SIVAL(outbuf,smb_ntr_DataOffset,0); + SIVAL(outbuf,smb_ntr_DataDisplacement, 0); + } else { + /* + * The offset of the data bytes is the offset of the + * parameter bytes plus the number of parameters being sent this time. + */ + + SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) - + smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); + SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata); + } - set_message(outbuf,18,0,True); + /* + * Copy the param bytes into the packet. + */ - if (NT_STATUS_V(nt_error)) - ERROR_NT(nt_error); + if(params_sent_thistime) + memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + + /* + * Copy in the data bytes + */ - /* - * If there genuinely are no parameters or data to send just send - * the empty packet. - */ - - if(params_to_send == 0 && data_to_send == 0) { - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_nt_replies: send_smb failed."); - return 0; - } + if(data_sent_thistime) + memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ + data_alignment_offset,pd,data_sent_thistime); + + DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", + params_sent_thistime, data_sent_thistime, useable_space)); + DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", + params_to_send, data_to_send, paramsize, datasize)); + + /* Send the packet */ + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_nt_replies: send_smb failed."); + + pp += params_sent_thistime; + pd += data_sent_thistime; + + params_to_send -= params_sent_thistime; + data_to_send -= data_sent_thistime; - /* - * When sending params and data ensure that both are nicely aligned. - * Only do this alignment when there is also data to send - else - * can cause NT redirector problems. - */ + /* + * Sanity check + */ - if (((params_to_send % 4) != 0) && (data_to_send != 0)) - data_alignment_offset = 4 - (params_to_send % 4); + if(params_to_send < 0 || data_to_send < 0) { + DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!", + params_to_send, data_to_send)); + return -1; + } + } - /* - * Space is bufsize minus Netbios over TCP header minus SMB header. - * The alignment_offset is to align the param bytes on a four byte - * boundary (2 bytes for data len, one byte pad). - * NT needs this to work correctly. - */ + return 0; +} - useable_space = bufsize - ((smb_buf(outbuf)+ - alignment_offset+data_alignment_offset) - - outbuf); +/**************************************************************************** + (Hopefully) temporary call to fix bugs in NT5.0beta2. This OS sends unicode + strings in NT calls AND DOESN'T SET THE UNICODE BIT !!!!!!! +****************************************************************************/ +static void get_filename( char *fname, char *inbuf, int data_offset, int data_len, int fname_len) +{ /* - * useable_space can never be more than max_send minus the - * alignment offset. + * We need various heuristics here to detect a unicode string... JRA. */ - useable_space = MIN(useable_space, - max_send - (alignment_offset+data_alignment_offset)); - - - while (params_to_send || data_to_send) { - - /* - * Calculate whether we will totally or partially fill this packet. - */ - - total_sent_thistime = params_to_send + data_to_send + - alignment_offset + data_alignment_offset; - - /* - * We can never send more than useable_space. - */ - - total_sent_thistime = MIN(total_sent_thistime, useable_space); - - set_message(outbuf, 18, total_sent_thistime, True); + DEBUG(10,("get_filename: data_offset = %d, data_len = %d, fname_len = %d\n", + data_offset, data_len, fname_len )); + if(data_len - fname_len > 1) { /* - * Set total params and data to be sent. + * NT 5.0 Beta 2 has kindly sent us a UNICODE string + * without bothering to set the unicode bit. How kind. + * + * Firstly - ensure that the data offset is aligned + * on a 2 byte boundary - add one if not. */ + fname_len = fname_len/2; + if(data_offset & 1) + data_offset++; + pstrcpy(fname, dos_unistrn2((uint16 *)(inbuf+data_offset), fname_len)); + } else { + StrnCpy(fname,inbuf+data_offset,fname_len); + fname[fname_len] = '\0'; + } +} - SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize); - SIVAL(outbuf,smb_ntr_TotalDataCount,datasize); - - /* - * Calculate how many parameters and data we can fit into - * this packet. Parameters get precedence. - */ - - params_sent_thistime = MIN(params_to_send,useable_space); - data_sent_thistime = useable_space - params_sent_thistime; - data_sent_thistime = MIN(data_sent_thistime,data_to_send); - - SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime); - - if(params_sent_thistime == 0) { - SIVAL(outbuf,smb_ntr_ParameterOffset,0); - SIVAL(outbuf,smb_ntr_ParameterDisplacement,0); - } else { - /* - * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the - * parameter bytes, however the first 4 bytes of outbuf are - * the Netbios over TCP header. Thus use smb_base() to subtract - * them from the calculation. - */ - - SIVAL(outbuf,smb_ntr_ParameterOffset, - ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - /* - * Absolute displacement of param bytes sent in this packet. - */ - - SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params); - } - - /* - * Deal with the data portion. - */ - - SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime); - - if(data_sent_thistime == 0) { - SIVAL(outbuf,smb_ntr_DataOffset,0); - SIVAL(outbuf,smb_ntr_DataDisplacement, 0); - } else { - /* - * The offset of the data bytes is the offset of the - * parameter bytes plus the number of parameters being sent this time. - */ - - SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); - SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata); - } +/**************************************************************************** + Fix bugs in Win2000 final release. In trans calls this OS sends unicode + strings AND DOESN'T SET THE UNICODE BIT !!!!!!! +****************************************************************************/ - /* - * Copy the param bytes into the packet. - */ +static void get_filename_transact( char *fname, char *inbuf, int data_offset, int data_len, int fname_len) +{ + DEBUG(10,("get_filename_transact: data_offset = %d, data_len = %d, fname_len = %d\n", + data_offset, data_len, fname_len )); - if(params_sent_thistime) - memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + /* + * Win2K sends a unicode filename plus one extra alingment byte. + * WinNT4.x send an ascii string with multiple garbage bytes on + * the end here. + */ - /* - * Copy in the data bytes - */ + /* + * We need various heuristics here to detect a unicode string... JRA. + */ - if(data_sent_thistime) - memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ - data_alignment_offset,pd,data_sent_thistime); - - DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", - params_to_send, data_to_send, paramsize, datasize)); - - /* Send the packet */ - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_nt_replies: send_smb failed."); - - pp += params_sent_thistime; - pd += data_sent_thistime; - - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; + if( ((fname_len % 2) == 0) && + ( + (data_len == 1) || + (inbuf[data_offset] == '\0') || + ((fname_len > 1) && (inbuf[data_offset+1] == '\\') && (inbuf[data_offset+2] == '\0')) + )) { /* - * Sanity check + * Ensure that the data offset is aligned + * on a 2 byte boundary - add one if not. */ - - if(params_to_send < 0 || data_to_send < 0) { - DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } - - return 0; + fname_len = fname_len/2; + if(data_offset & 1) + data_offset++; + pstrcpy(fname, dos_unistrn2((uint16 *)(inbuf+data_offset), fname_len)); + } else { + StrnCpy(fname,inbuf+data_offset,fname_len); + fname[fname_len] = '\0'; + } } /**************************************************************************** @@ -319,7 +396,7 @@ static int map_create_disposition( uint32 create_disposition) } DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n", - (unsigned long)create_disposition, ret )); + (unsigned long)create_disposition, ret )); return ret; } @@ -372,9 +449,9 @@ static int map_share_mode( char *fname, uint32 create_options, if (smb_open_mode == -1) { if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS| - FILE_EXECUTE|FILE_READ_ATTRIBUTES| - FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS| - FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) { + FILE_EXECUTE|FILE_READ_ATTRIBUTES| + FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS| + FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) { smb_open_mode = DOS_OPEN_RDONLY; } else if(*desired_access == 0) { @@ -457,7 +534,7 @@ to open_mode 0x%x\n", (unsigned long)*desired_access, (unsigned long)share_acces static int nt_open_pipe(char *fname, connection_struct *conn, char *inbuf, char *outbuf, int *ppnum) { - smb_np_struct *p = NULL; + pipes_struct *p = NULL; uint16 vuid = SVAL(inbuf, smb_uid); int i; @@ -501,9 +578,11 @@ static int do_ntcreate_pipe_open(connection_struct *conn, int ret; int pnum = -1; char *p = NULL; + uint32 fname_len = MIN(((uint32)SVAL(inbuf,smb_ntcreate_NameLength)), + ((uint32)sizeof(fname)-1)); - srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); - + get_filename(fname, inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) return ret; @@ -547,6 +626,8 @@ int reply_ntcreate_and_X(connection_struct *conn, uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess); uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition); uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions); + uint32 fname_len = MIN(((uint32)SVAL(inbuf,smb_ntcreate_NameLength)), + ((uint32)sizeof(fname)-1)); uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid); SMB_OFF_T allocation_size = 0; int smb_ofun; @@ -572,7 +653,7 @@ int reply_ntcreate_and_X(connection_struct *conn, file_attributes = 0x%x, share_access = 0x%x, create_disposition = 0x%x \ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attributes, share_access, create_disposition, - create_options, root_dir_fid )); + root_dir_fid, create_options )); /* If it's an IPC, use the pipe handler. */ @@ -619,13 +700,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib if(!dir_fsp->is_directory) { - srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); + get_filename(&fname[0], inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); /* * Check to see if this is a mac fork of some kind. */ - if( strchr_m(fname, ':')) { + if( strchr(fname, ':')) { END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); } @@ -649,15 +731,29 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib dir_name_len++; } - srvstr_pull_buf(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, STR_TERMINATE); + /* + * This next calculation can refuse a correct filename if we're dealing + * with the Win2k unicode bug, but that would be rare. JRA. + */ + + if(fname_len + dir_name_len >= sizeof(pstring)) { + END_PROFILE(SMBntcreateX); + return(ERROR_DOS(ERRSRV,ERRfilespecs)); + } + + get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); + } else { - srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); + + get_filename(fname, inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); /* * Check to see if this is a mac fork of some kind. */ - if( strchr_m(fname, ':')) { + if( strchr(fname, ':')) { END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); } @@ -738,7 +834,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib fsp = open_file_shared1(conn,fname,&sbuf, desired_access, smb_open_mode, - smb_ofun,unixmode, oplock_request, + smb_ofun, unixmode, oplock_request, &rmode,&smb_action); if (!fsp) { @@ -788,6 +884,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib restore_case_semantics(file_attributes); set_bad_path_error(errno, bad_path); + END_PROFILE(SMBntcreateX); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -834,7 +931,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) extended_oplock_granted = True; -#if 0 +#if 0 /* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */ set_message(outbuf,42,0,True); #else @@ -889,7 +986,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); + SOFF_T(p, 0, get_allocation_size(fsp, &sbuf)); p += 8; SOFF_T(p,0,file_len); p += 12; @@ -912,6 +1009,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char **ppdata) { pstring fname; + uint32 fname_len; int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount); char *params = *ppparams; int ret; @@ -927,29 +1025,32 @@ static int do_nt_transact_create_pipe( connection_struct *conn, return ERROR_DOS(ERRDOS,ERRnoaccess); } - srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + fname_len = MIN(((uint32)IVAL(params,44)),((uint32)sizeof(fname)-1)); + + get_filename_transact(&fname[0], params, 53, + total_parameter_count - 53 - fname_len, fname_len); if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) return ret; - + /* Realloc the size of parameters and data we will return */ params = Realloc(*ppparams, 69); if(params == NULL) return ERROR_DOS(ERRDOS,ERRnomem); - + *ppparams = params; - + memset((char *)params,'\0',69); - + p = params; SCVAL(p,0,NO_OPLOCK_RETURN); - + p += 2; SSVAL(p,0,pnum); p += 2; SIVAL(p,0,FILE_WAS_OPENED); p += 8; - + p += 32; SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */ p += 20; @@ -957,12 +1058,12 @@ static int do_nt_transact_create_pipe( connection_struct *conn, SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE); /* Device state. */ SSVAL(p,2, 0x5FF); /* ? */ - + DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); - + /* Send the required number of replies */ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); - + return -1; } @@ -970,15 +1071,17 @@ static int do_nt_transact_create_pipe( connection_struct *conn, Internal fn to set security descriptors. ****************************************************************************/ -static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent) +static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent, int *pdef_class,uint32 *pdef_code) { prs_struct pd; SEC_DESC *psd = NULL; TALLOC_CTX *mem_ctx; BOOL ret; - + if (sd_len == 0) { - return NT_STATUS_OK; + *pdef_class = 0; + *pdef_code = 0; + return True; } /* @@ -987,7 +1090,9 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu if ((mem_ctx = talloc_init()) == NULL) { DEBUG(0,("set_sd: talloc_init failed.\n")); - return NT_STATUS_NO_MEMORY; + *pdef_class = ERRDOS; + *pdef_code = ERRnomem; + return False; } prs_init(&pd, 0, mem_ctx, UNMARSHALL); @@ -1009,9 +1114,11 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu * Return access denied for want of a better error message.. */ talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; + *pdef_class = ERRDOS; + *pdef_code = ERRnomem; + return False; } - + if (psd->off_owner_sid==0) security_info_sent &= ~OWNER_SECURITY_INFORMATION; if (psd->off_grp_sid==0) @@ -1022,15 +1129,19 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu security_info_sent &= ~DACL_SECURITY_INFORMATION; ret = fsp->conn->vfs_ops.fset_nt_acl( fsp, fsp->fd, security_info_sent, psd); - + if (!ret) { talloc_destroy(mem_ctx); - return NT_STATUS_ACCESS_DENIED; + *pdef_class = ERRDOS; + *pdef_code = ERRnoaccess; + return False; } - + talloc_destroy(mem_ctx); - - return NT_STATUS_OK; + + *pdef_class = 0; + *pdef_code = 0; + return True; } /**************************************************************************** @@ -1063,14 +1174,16 @@ static int call_nt_transact_create(connection_struct *conn, uint32 share_access; uint32 create_disposition; uint32 create_options; + uint32 fname_len; uint32 sd_len; uint16 root_dir_fid; - SMB_OFF_T allocation_size = 0; + SMB_OFF_T allocation_size; int smb_ofun; int smb_open_mode; int smb_attr; + int error_class; + uint32 error_code; time_t c_time; - NTSTATUS nt_status; DEBUG(5,("call_nt_transact_create\n")); @@ -1102,6 +1215,7 @@ static int call_nt_transact_create(connection_struct *conn, create_disposition = IVAL(params,28); create_options = IVAL(params,32); sd_len = IVAL(params,36); + fname_len = MIN(((uint32)IVAL(params,44)),((uint32)sizeof(fname)-1)); root_dir_fid = (uint16)IVAL(params,4); smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK); @@ -1134,17 +1248,17 @@ static int call_nt_transact_create(connection_struct *conn, return ERROR_DOS(ERRDOS,ERRbadfid); if(!dir_fsp->is_directory) { - - srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + get_filename_transact(&fname[0], params, 53, + total_parameter_count - 53 - fname_len, fname_len); /* * Check to see if this is a mac fork of some kind. */ - if( strchr_m(fname, ':')) - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + if( strchr(fname, ':')) + return(ERROR_BOTH(NT_STATUS_OBJECT_PATH_NOT_FOUND,ERRDOS,ERRbadpath)); - return ERROR_DOS(ERRDOS,ERRbadfid); + return(ERROR_DOS(ERRDOS,ERRbadfid)); } /* @@ -1163,17 +1277,27 @@ static int call_nt_transact_create(connection_struct *conn, dir_name_len++; } - srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len, - total_parameter_count-53, STR_TERMINATE); + /* + * This next calculation can refuse a correct filename if we're dealing + * with the Win2k unicode bug, but that would be rare. JRA. + */ + + if(fname_len + dir_name_len >= sizeof(pstring)) + return(ERROR_DOS(ERRSRV,ERRfilespecs)); + + get_filename_transact(&fname[dir_name_len], params, 53, + total_parameter_count - 53 - fname_len, fname_len); + } else { - srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + get_filename_transact(&fname[0], params, 53, + total_parameter_count - 53 - fname_len, fname_len); /* * Check to see if this is a mac fork of some kind. */ - if( strchr_m(fname, ':')) - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + if( strchr(fname, ':')) + return(ERROR_BOTH(NT_STATUS_OBJECT_PATH_NOT_FOUND,ERRDOS,ERRbadpath)); } /* @@ -1182,7 +1306,7 @@ static int call_nt_transact_create(connection_struct *conn, */ if((smb_open_mode = map_share_mode( fname, create_options, &desired_access, - share_access, file_attributes)) == -1) + share_access, file_attributes)) == -1) return ERROR_DOS(ERRDOS,ERRnoaccess); oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -1234,9 +1358,8 @@ static int call_nt_transact_create(connection_struct *conn, * Ordinary file case. */ - fsp = open_file_shared1(conn,fname,&sbuf,desired_access, - smb_open_mode,smb_ofun,unixmode, - oplock_request,&rmode,&smb_action); + fsp = open_file_shared1(conn,fname,&sbuf,desired_access,smb_open_mode,smb_ofun,unixmode, + oplock_request,&rmode,&smb_action); if (!fsp) { @@ -1254,15 +1377,17 @@ static int call_nt_transact_create(connection_struct *conn, oplock_request = 0; fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action); - + if(!fsp) { restore_case_semantics(file_attributes); set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRnoaccess)); } } else { + restore_case_semantics(file_attributes); set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); } } @@ -1295,12 +1420,12 @@ static int call_nt_transact_create(connection_struct *conn, * Now try and apply the desired SD. */ - if (sd_len && !NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) { + if (sd_len && !set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) { close_file(fsp,False); restore_case_semantics(file_attributes); - return ERROR_NT(nt_status); + return ERROR_DOS(error_class, error_code); } - + restore_case_semantics(file_attributes); /* Save the requested allocation size. */ @@ -1416,7 +1541,6 @@ int reply_nttranss(connection_struct *conn, Reply to a notify change - queue the request and don't allow a directory to be opened. ****************************************************************************/ - static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, @@ -1461,12 +1585,15 @@ static int call_nt_transact_rename(connection_struct *conn, files_struct *fsp = file_fsp(params, 0); BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; NTSTATUS status; + uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)), + ((uint32)sizeof(new_name)-1)); CHECK_FSP(fsp, conn); - srvstr_pull(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE); + StrnCpy(new_name,params+4,fname_len); + new_name[fname_len] = '\0'; status = rename_internals(conn, fsp->fsp_name, - new_name, replace_if_exists); + new_name, replace_if_exists); if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); @@ -1474,15 +1601,15 @@ static int call_nt_transact_rename(connection_struct *conn, * Rename was successful. */ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - + DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", - fsp->fsp_name, new_name)); - + fsp->fsp_name, new_name)); + /* * Win2k needs a changenotify request response before it will * update after a rename.. */ - + process_pending_change_notify_queue((time_t)0); return -1; @@ -1502,7 +1629,7 @@ static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n")); sd_size = 0; } - + return sd_size; } @@ -1517,107 +1644,107 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, int length, int bufsize, char **ppsetup, char **ppparams, char **ppdata) { - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); - char *params = *ppparams; - char *data = *ppdata; - prs_struct pd; - SEC_DESC *psd = NULL; - size_t sd_size; - TALLOC_CTX *mem_ctx; + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + char *params = *ppparams; + char *data = *ppdata; + prs_struct pd; + SEC_DESC *psd = NULL; + size_t sd_size; + TALLOC_CTX *mem_ctx; - files_struct *fsp = file_fsp(params,0); + files_struct *fsp = file_fsp(params,0); - if(!fsp) - return ERROR_DOS(ERRDOS,ERRbadfid); + if(!fsp) + return ERROR_DOS(ERRDOS,ERRbadfid); - DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); + DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); - params = Realloc(*ppparams, 4); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); + params = Realloc(*ppparams, 4); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); - *ppparams = params; + *ppparams = params; - if ((mem_ctx = talloc_init()) == NULL) { - DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); - return ERROR_DOS(ERRDOS,ERRnomem); - } + if ((mem_ctx = talloc_init()) == NULL) { + DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); + return ERROR_DOS(ERRDOS,ERRnomem); + } - /* - * Get the permissions to return. - */ + /* + * Get the permissions to return. + */ - if (!lp_nt_acl_support(SNUM(conn))) - sd_size = get_null_nt_acl(mem_ctx, &psd); - else - sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + if (!lp_nt_acl_support(SNUM(conn))) + sd_size = get_null_nt_acl(mem_ctx, &psd); + else + sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); - if (sd_size == 0) { - talloc_destroy(mem_ctx); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + if (sd_size == 0) { + talloc_destroy(mem_ctx); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size)); + DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size)); - SIVAL(params,0,(uint32)sd_size); + SIVAL(params,0,(uint32)sd_size); - if(max_data_count < sd_size) { + if(max_data_count < sd_size) { - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, - params, 4, *ppdata, 0); - talloc_destroy(mem_ctx); - return -1; - } + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, + params, 4, *ppdata, 0); + talloc_destroy(mem_ctx); + return -1; + } - /* - * Allocate the data we will point this at. - */ + /* + * Allocate the data we will point this at. + */ - data = Realloc(*ppdata, sd_size); - if(data == NULL) { - talloc_destroy(mem_ctx); - return ERROR_DOS(ERRDOS,ERRnomem); - } + data = Realloc(*ppdata, sd_size); + if(data == NULL) { + talloc_destroy(mem_ctx); + return ERROR_DOS(ERRDOS,ERRnomem); + } - *ppdata = data; + *ppdata = data; - memset(data, '\0', sd_size); + memset(data, '\0', sd_size); - /* - * Init the parse struct we will marshall into. - */ + /* + * Init the parse struct we will marshall into. + */ - prs_init(&pd, 0, mem_ctx, MARSHALL); + prs_init(&pd, 0, mem_ctx, MARSHALL); - /* - * Setup the prs_struct to point at the memory we just - * allocated. - */ + /* + * Setup the prs_struct to point at the memory we just + * allocated. + */ - prs_give_memory( &pd, data, (uint32)sd_size, False); + prs_give_memory( &pd, data, (uint32)sd_size, False); - /* - * Finally, linearize into the outgoing buffer. - */ + /* + * Finally, linearize into the outgoing buffer. + */ - if(!sec_io_desc( "sd data", &psd, &pd, 1)) { - DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \ + if(!sec_io_desc( "sd data", &psd, &pd, 1)) { + DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \ security descriptor.\n")); - /* - * Return access denied for want of a better error message.. - */ - talloc_destroy(mem_ctx); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + /* + * Return access denied for want of a better error message.. + */ + talloc_destroy(mem_ctx); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - /* - * Now we can delete the security descriptor. - */ + /* + * Now we can delete the security descriptor. + */ - talloc_destroy(mem_ctx); + talloc_destroy(mem_ctx); - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size); - return -1; + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size); + return -1; } /**************************************************************************** @@ -1635,7 +1762,8 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, uint32 total_data_count = (uint32)IVAL(inbuf, smb_nts_TotalDataCount); files_struct *fsp = NULL; uint32 security_info_sent = 0; - NTSTATUS nt_status; + int error_class; + uint32 error_code; if(total_parameter_count < 8) return ERROR_DOS(ERRDOS,ERRbadfunc); @@ -1654,8 +1782,8 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, if (total_data_count == 0) return ERROR_DOS(ERRDOS, ERRnoaccess); - if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, total_data_count, security_info_sent))) - return ERROR_NT(nt_status); + if (!set_sd( fsp, data, total_data_count, security_info_sent, &error_class, &error_code)) + return ERROR_DOS(error_class, error_code); done: @@ -1664,263 +1792,263 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, } /**************************************************************************** - Reply to NT IOCTL + Reply to IOCTL. ****************************************************************************/ + static int call_nt_transact_ioctl(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **ppsetup, int setup_count, - char **ppparams, int parameter_count, - char **ppdata, int data_count) + char *inbuf, char *outbuf, int length, + int bufsize, + char **ppsetup, int setup_count, + char **ppparams, int parameter_count, + char **ppdata, int data_count) { unsigned fnum, control; static BOOL logged_message; - + if (setup_count != 8) { DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count)); return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - + fnum = SVAL(*ppsetup, 4); control = IVAL(*ppsetup, 0); - - DEBUG(6,("call_nt_transact_ioctl: fnum=%d control=0x%x\n", - fnum, control)); - + + DEBUG(6,("call_nt_transact_ioctl: fnum=%d control=0x%x\n", + fnum, control)); + switch (control) { case NTIOCTL_SET_SPARSE: /* pretend this succeeded - tho strictly we should - mark the file sparse (if the local fs supports it) - so we can know if we need to pre-allocate or not */ + mark the file sparse (if the local fs supports it) + so we can know if we need to pre-allocate or not */ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; - + default: if (!logged_message) { logged_message = True; /* Only print this once... */ DEBUG(3,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", - control)); + control)); } } - + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } /**************************************************************************** Reply to a SMBNTtrans. ****************************************************************************/ - int reply_nttrans(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) + char *inbuf,char *outbuf,int length,int bufsize) { - int outsize = 0; + int outsize = 0; #if 0 /* Not used. */ - uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount); - uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount); - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount); + uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount); + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); #endif /* Not used. */ - uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount); - uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount); - uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount); - uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset); - uint32 data_count = IVAL(inbuf,smb_nt_DataCount); - uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset); - uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */ - uint16 function_code = SVAL( inbuf, smb_nt_Function); - char *params = NULL, *data = NULL, *setup = NULL; - uint32 num_params_sofar, num_data_sofar; - START_PROFILE(SMBnttrans); - - if(global_oplock_break && - ((function_code == NT_TRANSACT_CREATE) || - (function_code == NT_TRANSACT_RENAME))) { - /* - * Queue this open message as we are the process of an oplock break. - */ - - DEBUG(2,("reply_nttrans: queueing message code 0x%x \ + uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount); + uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount); + uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount); + uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset); + uint32 data_count = IVAL(inbuf,smb_nt_DataCount); + uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset); + uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */ + uint16 function_code = SVAL( inbuf, smb_nt_Function); + char *params = NULL, *data = NULL, *setup = NULL; + uint32 num_params_sofar, num_data_sofar; + START_PROFILE(SMBnttrans); + + if(global_oplock_break && + ((function_code == NT_TRANSACT_CREATE) || + (function_code == NT_TRANSACT_RENAME))) { + /* + * Queue this open message as we are the process of an oplock break. + */ + + DEBUG(2,("reply_nttrans: queueing message code 0x%x \ due to being in oplock break state.\n", (unsigned int)function_code )); - push_oplock_pending_smb_message( inbuf, length); - END_PROFILE(SMBnttrans); - return -1; - } - - if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRaccess); - } - - outsize = set_message(outbuf,0,0,True); - - /* - * All nttrans messages we handle have smb_wct == 19 + setup_count. - * Ensure this is so as a sanity check. - */ - - if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) { - DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", - CVAL(inbuf, smb_wct), 19 + (setup_count/2))); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); - } + push_oplock_pending_smb_message( inbuf, length); + END_PROFILE(SMBnttrans); + return -1; + } + + if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRaccess); + } + + outsize = set_message(outbuf,0,0,True); + + /* + * All nttrans messages we handle have smb_wct == 19 + setup_count. + * Ensure this is so as a sanity check. + */ + + if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) { + DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", + CVAL(inbuf, smb_wct), 19 + (setup_count/2))); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRerror); + } - /* Allocate the space for the setup, the maximum needed parameters and data */ - - if(setup_count > 0) - setup = (char *)malloc(setup_count); - if (total_parameter_count > 0) - params = (char *)malloc(total_parameter_count); - if (total_data_count > 0) - data = (char *)malloc(total_data_count); + /* Allocate the space for the setup, the maximum needed parameters and data */ + + if(setup_count > 0) + setup = (char *)malloc(setup_count); + if (total_parameter_count > 0) + params = (char *)malloc(total_parameter_count); + if (total_data_count > 0) + data = (char *)malloc(total_data_count); - if ((total_parameter_count && !params) || (total_data_count && !data) || - (setup_count && !setup)) { - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); - DEBUG(0,("reply_nttrans : Out of memory\n")); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - /* Copy the param and data bytes sent with this request into the params buffer */ - num_params_sofar = parameter_count; - num_data_sofar = data_count; - - if (parameter_count > total_parameter_count || data_count > total_data_count) - exit_server("reply_nttrans: invalid sizes in packet."); - - if(setup) { - memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); - DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); - dump_data(10, setup, setup_count); - } - if(params) { - memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); - DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); - dump_data(10, params, parameter_count); - } - if(data) { - memcpy( data, smb_base(inbuf) + data_offset, data_count); - DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); - dump_data(10, data, data_count); - } - - if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_nttrans: send_smb failed."); - - while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { - BOOL ret; - - ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); - - if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) { - outsize = set_message(outbuf,0,0,True); - if(ret) { - DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); - } else { - DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", - (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - } - SAFE_FREE(params); - SAFE_FREE(data); - SAFE_FREE(setup); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); - } - - /* Revise total_params and total_data in case they have changed downwards */ - total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); - total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); - num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount)); - num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount)); - if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) - exit_server("reply_nttrans2: data overflow in secondary nttrans packet"); - - memcpy( ¶ms[ IVAL(inbuf, smb_nts_ParameterDisplacement)], - smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count); - memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)], - smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count); - } + if ((total_parameter_count && !params) || (total_data_count && !data) || + (setup_count && !setup)) { + safe_free(setup); + safe_free(params); + safe_free(data); + DEBUG(0,("reply_nttrans : Out of memory\n")); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRDOS,ERRnomem); + } + + /* Copy the param and data bytes sent with this request into + the params buffer */ + num_params_sofar = parameter_count; + num_data_sofar = data_count; + + if (parameter_count > total_parameter_count || data_count > total_data_count) + exit_server("reply_nttrans: invalid sizes in packet."); + + if(setup) { + memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); + DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); + dump_data(10, setup, setup_count); + } + if(params) { + memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); + DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); + dump_data(10, params, parameter_count); + } + if(data) { + memcpy( data, smb_base(inbuf) + data_offset, data_count); + DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); + dump_data(10, data, data_count); + } + + if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { + /* We need to send an interim response then receive the rest + of the parameter/data bytes */ + outsize = set_message(outbuf,0,0,True); + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("reply_nttrans: send_smb failed."); + + while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { + BOOL ret; + + ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); + + if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) { + outsize = set_message(outbuf,0,0,True); + if(ret) { + DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); + } else { + DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", + (smb_read_error == READ_ERROR) ? "error" : "timeout" )); } - - if (Protocol >= PROTOCOL_NT1) - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME); - - /* Now we must call the relevant NT_TRANS function */ - switch(function_code) { - case NT_TRANSACT_CREATE: - START_PROFILE_NESTED(NT_transact_create); - outsize = call_nt_transact_create(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_create); - break; - case NT_TRANSACT_IOCTL: - START_PROFILE_NESTED(NT_transact_ioctl); - outsize = call_nt_transact_ioctl(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, parameter_count, - &data, data_count); - END_PROFILE_NESTED(NT_transact_ioctl); - break; - case NT_TRANSACT_SET_SECURITY_DESC: - START_PROFILE_NESTED(NT_transact_set_security_desc); - outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_set_security_desc); - break; - case NT_TRANSACT_NOTIFY_CHANGE: - START_PROFILE_NESTED(NT_transact_notify_change); - outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_notify_change); - break; - case NT_TRANSACT_RENAME: - START_PROFILE_NESTED(NT_transact_rename); - outsize = call_nt_transact_rename(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_rename); - break; - - case NT_TRANSACT_QUERY_SECURITY_DESC: - START_PROFILE_NESTED(NT_transact_query_security_desc); - outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); - END_PROFILE_NESTED(NT_transact_query_security_desc); - break; - default: - /* Error in request */ - DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); - } - - /* As we do not know how many data packets will need to be - returned here the various call_nt_transact_xxxx calls - must send their own. Thus a call_nt_transact_xxxx routine only - returns a value other than -1 when it wants to send - an error packet. - */ - - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); + SAFE_FREE(params); + SAFE_FREE(data); + SAFE_FREE(setup); END_PROFILE(SMBnttrans); - return outsize; /* If a correct response was needed the call_nt_transact_xxxx - calls have already sent it. If outsize != -1 then it is - returning an error packet. */ + return ERROR_DOS(ERRSRV,ERRerror); + } + + /* Revise total_params and total_data in case they have changed downwards */ + total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); + total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); + num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount)); + num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount)); + if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) + exit_server("reply_nttrans2: data overflow in secondary nttrans packet"); + + memcpy( ¶ms[ IVAL(inbuf, smb_nts_ParameterDisplacement)], + smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count); + memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)], + smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count); + } + } + + if (Protocol >= PROTOCOL_NT1) + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME); + + /* Now we must call the relevant NT_TRANS function */ + switch(function_code) { + case NT_TRANSACT_CREATE: + START_PROFILE_NESTED(NT_transact_create); + outsize = call_nt_transact_create(conn, inbuf, outbuf, length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_create); + break; + case NT_TRANSACT_IOCTL: + START_PROFILE_NESTED(NT_transact_ioctl); + outsize = call_nt_transact_ioctl(conn, inbuf, outbuf, + length, bufsize, + &setup, setup_count, + ¶ms, parameter_count, + &data, data_count); + END_PROFILE_NESTED(NT_transact_ioctl); + break; + case NT_TRANSACT_SET_SECURITY_DESC: + START_PROFILE_NESTED(NT_transact_set_security_desc); + outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_set_security_desc); + break; + case NT_TRANSACT_NOTIFY_CHANGE: + START_PROFILE_NESTED(NT_transact_notify_change); + outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_notify_change); + break; + case NT_TRANSACT_RENAME: + START_PROFILE_NESTED(NT_transact_rename); + outsize = call_nt_transact_rename(conn, inbuf, outbuf, length, + bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_rename); + break; + + case NT_TRANSACT_QUERY_SECURITY_DESC: + START_PROFILE_NESTED(NT_transact_query_security_desc); + outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, + length, bufsize, + &setup, ¶ms, &data); + END_PROFILE_NESTED(NT_transact_query_security_desc); + break; + default: + /* Error in request */ + DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); + END_PROFILE(SMBnttrans); + return ERROR_DOS(ERRSRV,ERRerror); + } + + /* As we do not know how many data packets will need to be + returned here the various call_nt_transact_xxxx calls + must send their own. Thus a call_nt_transact_xxxx routine only + returns a value other than -1 when it wants to send + an error packet. + */ + + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); + END_PROFILE(SMBnttrans); + return outsize; /* If a correct response was needed the call_nt_transact_xxxx + calls have already sent it. If outsize != -1 then it is + returning an error packet. */ } |