diff options
Diffstat (limited to 'source3/smbd/trans2.c')
-rw-r--r-- | source3/smbd/trans2.c | 2623 |
1 files changed, 1084 insertions, 1539 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f1dfb39aacf..1972e9c8c8e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -37,261 +37,255 @@ extern pstring global_myname; HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -static int send_trans2_replies(char *outbuf, - int bufsize, - char *params, - int paramsize, - char *pdata, - int datasize) +static int send_trans2_replies(char *outbuf, int bufsize, char *params, + int paramsize, char *pdata, int datasize) { - /* As we are using a protocol > LANMAN1 then the max_send - variable must have been set in the sessetupX call. - This takes precedence over the max_xmit field in the - global struct. These different max_xmit variables should - be merged as this is now too confusing */ - - 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 = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ - int data_alignment_offset = 0; - - /* Initially set the wcnt area to be 10 - this is true for all trans2 replies */ - - set_message(outbuf,10,0,True); - - /* 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_trans2_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 an even byte - boundary. NT 4.0 Beta 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 */ - /* - * Note that 'useable_space' does not include the alignment offsets, - * but we must include the alignment offsets in the calculation of - * the length of the data we send over the wire, as the alignment offsets - * are sent here. Fix from Marc_Jacobsen@hp.com. - */ - - total_sent_thistime = MIN(total_sent_thistime, useable_space+ alignment_offset + data_alignment_offset); - - set_message(outbuf, 10, total_sent_thistime, True); - - /* Set total params and data to be sent */ - SSVAL(outbuf,smb_tprcnt,paramsize); - SSVAL(outbuf,smb_tdrcnt,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); - - SSVAL(outbuf,smb_prcnt, params_sent_thistime); - - /* smb_proff 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 */ - - SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - - if(params_sent_thistime == 0) - SSVAL(outbuf,smb_prdisp,0); - else - /* Absolute displacement of param bytes sent in this packet */ - SSVAL(outbuf,smb_prdisp,pp - params); - - SSVAL(outbuf,smb_drcnt, data_sent_thistime); - if(data_sent_thistime == 0) { - SSVAL(outbuf,smb_droff,0); - SSVAL(outbuf,smb_drdisp, 0); - } else { - /* The offset of the data bytes is the offset of the - parameter bytes plus the number of parameters being sent this time */ - SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); - SSVAL(outbuf,smb_drdisp, pd - pdata); - } - - /* Copy the param bytes into the packet */ - - if(params_sent_thistime) - memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); - - /* Copy in the data bytes */ - if(data_sent_thistime) - memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ - data_alignment_offset,pd,data_sent_thistime); - - DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("t2_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_trans2_replies: send_smb failed."); - - pp += params_sent_thistime; - pd += data_sent_thistime; - - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; - - /* Sanity check */ - if(params_to_send < 0 || data_to_send < 0) { - DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } - - return 0; + /* As we are using a protocol > LANMAN1 then the max_send + variable must have been set in the sessetupX call. + This takes precedence over the max_xmit field in the + global struct. These different max_xmit variables should + be merged as this is now too confusing */ + + 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 = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ + int data_alignment_offset = 0; + + /* Initially set the wcnt area to be 10 - this is true for all + trans2 replies */ + set_message(outbuf,10,0,True); + + /* 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_trans2_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 an even byte + boundary. NT 4.0 Beta 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 */ + /* + * Note that 'useable_space' does not include the alignment offsets, + * but we must include the alignment offsets in the calculation of + * the length of the data we send over the wire, as the alignment offsets + * are sent here. Fix from Marc_Jacobsen@hp.com. + */ + total_sent_thistime = MIN(total_sent_thistime, useable_space+ + alignment_offset + data_alignment_offset); + + set_message(outbuf, 10, total_sent_thistime, True); + + /* Set total params and data to be sent */ + SSVAL(outbuf,smb_tprcnt,paramsize); + SSVAL(outbuf,smb_tdrcnt,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); + + SSVAL(outbuf,smb_prcnt, params_sent_thistime); + + /* smb_proff 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 */ + + SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); + + if(params_sent_thistime == 0) + SSVAL(outbuf,smb_prdisp,0); + else + /* Absolute displacement of param bytes sent in this packet */ + SSVAL(outbuf,smb_prdisp,pp - params); + + SSVAL(outbuf,smb_drcnt, data_sent_thistime); + if(data_sent_thistime == 0) + { + SSVAL(outbuf,smb_droff,0); + SSVAL(outbuf,smb_drdisp, 0); + } + else + { + /* The offset of the data bytes is the offset of the + parameter bytes plus the number of parameters being sent this time */ + SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - + smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); + SSVAL(outbuf,smb_drdisp, pd - pdata); + } + + /* Copy the param bytes into the packet */ + if(params_sent_thistime) + memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + /* Copy in the data bytes */ + if(data_sent_thistime) + memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ + data_alignment_offset,pd,data_sent_thistime); + + DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", + params_sent_thistime, data_sent_thistime, useable_space)); + DEBUG(9,("t2_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_trans2_replies: send_smb failed."); + + pp += params_sent_thistime; + pd += data_sent_thistime; + + params_to_send -= params_sent_thistime; + data_to_send -= data_sent_thistime; + + /* Sanity check */ + if(params_to_send < 0 || data_to_send < 0) + { + DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", + params_to_send, data_to_send)); + return -1; + } + } + + return 0; } /**************************************************************************** Reply to a TRANSACT2_OPEN. ****************************************************************************/ -static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) +static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, + int bufsize, + char **pparams, char **ppdata) { - char *params = *pparams; - int16 open_mode; - int16 open_attr; - BOOL oplock_request; -#if 0 - BOOL return_additional_info; - int16 open_sattr; - time_t open_time; -#endif - int16 open_ofun; - int32 open_size; - char *pname; - pstring fname; - mode_t unixmode; - SMB_OFF_T size=0; - int fmode=0,mtime=0,rmode; - SMB_INO_T inode = 0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp; - - /* - * Ensure we have enough parameters to perform the operation. - */ - - if (total_params < 29) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - open_mode = SVAL(params, 2); - open_attr = SVAL(params,6); - oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); + char *params = *pparams; + int16 open_mode = SVAL(params, 2); + int16 open_attr = SVAL(params,6); + BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); #if 0 - return_additional_info = BITSETW(params,0); - open_sattr = SVAL(params, 4); - open_time = make_unix_date3(params+8); + BOOL return_additional_info = BITSETW(params,0); + int16 open_sattr = SVAL(params, 4); + time_t open_time = make_unix_date3(params+8); #endif - open_ofun = SVAL(params,12); - open_size = IVAL(params,14); - pname = ¶ms[28]; - - srvstr_pull(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE); - - DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", - fname,open_mode, open_attr, open_ofun, open_size)); - - if (IS_IPC(conn)) + int16 open_ofun = SVAL(params,12); + int32 open_size = IVAL(params,14); + char *pname = ¶ms[28]; + pstring fname; + mode_t unixmode; + SMB_OFF_T size=0; + int fmode=0,mtime=0,rmode; + SMB_INO_T inode = 0; + SMB_STRUCT_STAT sbuf; + int smb_action = 0; + BOOL bad_path = False; + files_struct *fsp; + + srvstr_pull(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE); + + DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", + fname,open_mode, open_attr, open_ofun, open_size)); + + if (IS_IPC(conn)) { return(ERROR_DOS(ERRSRV,ERRaccess)); + } - /* XXXX we need to handle passed times, sattr and flags */ + /* XXXX we need to handle passed times, sattr and flags */ - unix_convert(fname,conn,0,&bad_path,&sbuf); + unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - unixmode = unix_mode(conn,open_attr | aARCH, fname); + if (!check_name(fname,conn)) + { + if((errno == ENOENT) && bad_path) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + unixmode = unix_mode(conn,open_attr | aARCH, fname); - fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode, - oplock_request, &rmode,&smb_action); + fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode, + oplock_request, &rmode,&smb_action); - if (!fsp) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - mtime = sbuf.st_mtime; - inode = sbuf.st_ino; - if (fmode & aDIR) { - close_file(fsp,False); - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - } - - /* Realloc the size of parameters and data we will return */ - params = Realloc(*pparams, 28); - if( params == NULL ) - return(ERROR_DOS(ERRDOS,ERRnomem)); - *pparams = params; - - memset((char *)params,'\0',28); - SSVAL(params,0,fsp->fnum); - SSVAL(params,2,fmode); - put_dos_date2(params,4, mtime); - SIVAL(params,8, (uint32)size); - SSVAL(params,12,rmode); - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - smb_action |= EXTENDED_OPLOCK_GRANTED; - - SSVAL(params,18,smb_action); - - /* - * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes. - */ - SIVAL(params,20,inode); + if (!fsp) + { + if((errno == ENOENT) && bad_path) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + size = sbuf.st_size; + fmode = dos_mode(conn,fname,&sbuf); + mtime = sbuf.st_mtime; + inode = sbuf.st_ino; + if (fmode & aDIR) { + close_file(fsp,False); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + } + + /* Realloc the size of parameters and data we will return */ + params = Realloc(*pparams, 28); + if( params == NULL ) { + return(ERROR_DOS(ERRDOS,ERRnomem)); + } + *pparams = params; + + memset((char *)params,'\0',28); + SSVAL(params,0,fsp->fnum); + SSVAL(params,2,fmode); + put_dos_date2(params,4, mtime); + SIVAL(params,8, (uint32)size); + SSVAL(params,12,rmode); + + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { + smb_action |= EXTENDED_OPLOCK_GRANTED; + } + + SSVAL(params,18,smb_action); + /* + * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes. + */ + SIVAL(params,20,inode); - /* Send the required number of replies */ - send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); + /* Send the required number of replies */ + send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); - return -1; + return -1; } /********************************************************* @@ -310,6 +304,10 @@ static BOOL exact_match(char *str,char *mask, BOOL case_sig) return strcasecmp(str,mask) == 0; } +#if 0 + +Not finished yet - jra. + /**************************************************************************** Return the filetype for UNIX extensions. ****************************************************************************/ @@ -372,63 +370,35 @@ static uint32 unix_dev_minor(SMB_DEV_T dev) } /**************************************************************************** - Map wire perms onto standard UNIX permissions. Obey share restrictions. + Map standard UNIX permissions onto wire representations. ****************************************************************************/ -static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *pst, uint32 perms) +static uint32 unix_perms_to_wire(mode_t perms) { - mode_t ret = 0; - - if (perms == SMB_MODE_NO_CHANGE) - return pst->st_mode; - - ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0); - ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0); - ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0); - ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0); - ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0); - ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0); - ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0); - ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0); - ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0); + uint ret = 0; + + ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0); + ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0); + ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0); + ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0); + ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0); + ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0); + ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0); + ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0); + ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0); #ifdef S_ISVTX - ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0); + ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0); #endif #ifdef S_ISGID - ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0); + ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0); #endif #ifdef S_ISUID - ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0); + ret |= ((perms & S_ISVTX) ? UNIX_SET_UID : 0); #endif - - if (VALID_STAT(*pst) && S_ISDIR(pst->st_mode)) { - ret &= lp_dir_mask(SNUM(conn)); - /* Add in force bits */ - ret |= lp_force_dir_mode(SNUM(conn)); - } else { - /* Apply mode mask */ - ret &= lp_create_mask(SNUM(conn)); - /* Add in force bits */ - ret |= lp_force_create_mode(SNUM(conn)); - } - return ret; } -/**************************************************************************** -checks for SMB_TIME_NO_CHANGE and if not found -calls interpret_long_date -****************************************************************************/ -time_t interpret_long_unix_date(char *p) -{ - DEBUG(1,("interpret_long_unix_date\n")); - if(IVAL(p,0) == SMB_TIME_NO_CHANGE_LO && - IVAL(p,4) == SMB_TIME_NO_CHANGE_HI) { - return -1; - } else { - return interpret_long_date(p); - } -} +#endif /**************************************************************************** Get a level dependent lanman2 dir entry. @@ -538,23 +508,16 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, continue; } } else if (vfs_stat(conn,pathreal,&sbuf) != 0) { - - /* Needed to show the msdfs symlinks as - * directories */ - - if(lp_host_msdfs() && - lp_msdfs_root(SNUM(conn)) && - is_msdfs_link(conn, pathreal, NULL, NULL, - &sbuf)) { - - DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal)); - sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; - - } else { - + /* Needed to show the msdfs symlinks as directories */ + if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn)) + || !is_msdfs_link(conn, pathreal)) { DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", - pathreal,strerror(errno))); + pathreal,strerror(errno))); continue; + } else { + DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", + pathreal)); + sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; } } @@ -594,7 +557,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL; switch (info_level) { - case SMB_INFO_STANDARD: + case 1: if(requires_resume_key) { SIVAL(p,0,reskey); p += 4; @@ -613,7 +576,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, p += len; break; - case SMB_INFO_QUERY_EA_SIZE: + case 2: if(requires_resume_key) { SIVAL(p,0,reskey); p += 4; @@ -730,8 +693,14 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, /* CIFS UNIX Extension. */ +#if 0 /* JRA - FIXME - NEEDS UNICODE CONVERSION !!! */ case SMB_FIND_FILE_UNIX: - p+= 4; + + len = 108+strlen(fname)+1; /* (length of SMB_QUERY_FILE_UNIX_BASIC = 100)+4+4+strlen(fname)*/ + /* +1 to be sure to transmit the termination of fname */ + len = (len + 3) & ~3; + + SIVAL(p,0,len); p+= 4; /* Offset from this structure to the beginning of the next one */ SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ @@ -781,16 +750,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SIVAL(p,4,0); p+= 8; - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE); - p += len; - - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */ - p = pdata + len; /* End of SMB_QUERY_FILE_UNIX_BASIC */ + pstrcpy(p,fname); + p=pdata+len; break; +#endif default: return(False); @@ -817,664 +782,612 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, Reply to a TRANS2_FINDFIRST. ****************************************************************************/ -static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) +static int call_trans2findfirst(connection_struct *conn, + char *inbuf, char *outbuf, int bufsize, + char **pparams, char **ppdata) { - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dirtype = SVAL(params,0); - int maxentries = SVAL(params,2); - BOOL close_after_first = BITSETW(params+4,0); - BOOL close_if_end = BITSETW(params+4,1); - BOOL requires_resume_key = BITSETW(params+4,2); - int info_level = SVAL(params,6); - pstring directory; - pstring mask; - char *p, *wcard; - int last_name_off=0; - int dptr_num = -1; - int numentries = 0; - int i; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - - if (total_params < 12) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - *directory = *mask = 0; - - DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \ -close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", - dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, - info_level, max_data_bytes)); + /* We must be careful here that we don't return more than the + allowed number of data bytes. If this means returning fewer than + maxentries then so be it. We assume that the redirector has + enough room for the fixed number of parameter bytes it has + requested. */ + uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *params = *pparams; + char *pdata = *ppdata; + int dirtype = SVAL(params,0); + int maxentries = SVAL(params,2); + BOOL close_after_first = BITSETW(params+4,0); + BOOL close_if_end = BITSETW(params+4,1); + BOOL requires_resume_key = BITSETW(params+4,2); + int info_level = SVAL(params,6); + pstring directory; + pstring mask; + char *p, *wcard; + int last_name_off=0; + int dptr_num = -1; + int numentries = 0; + int i; + BOOL finished = False; + BOOL dont_descend = False; + BOOL out_of_space = False; + int space_remaining; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + + *directory = *mask = 0; + + DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", + dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, + info_level, max_data_bytes)); - switch (info_level) { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - case SMB_FIND_FILE_UNIX: - if (!lp_unix_extensions()) - return(ERROR_DOS(ERRDOS,ERRunknownlevel)); - break; - default: - return(ERROR_DOS(ERRDOS,ERRunknownlevel)); - } - - srvstr_pull(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE); - - RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); - - unix_convert(directory,conn,0,&bad_path,&sbuf); - if(!check_name(directory,conn)) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - p = strrchr_m(directory,'/'); - if(p == NULL) { - pstrcpy(mask,directory); - pstrcpy(directory,"./"); - } else { - pstrcpy(mask,p+1); - *p = 0; - } - - DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); - - pdata = Realloc(*ppdata, max_data_bytes + 1024); - if( pdata == NULL ) - return(ERROR_DOS(ERRDOS,ERRnomem)); - - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - /* Realloc the params space */ - params = Realloc(*pparams, 10); - if (params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - *pparams = params; - - dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid)); - if (dptr_num < 0) - return(UNIXERROR(ERRDOS,ERRbadfile)); - - /* Save the wildcard match and attribs we are using on this directory - - needed as lanman2 assumes these are being saved between calls */ - - if(!(wcard = strdup(mask))) { - dptr_close(&dptr_num); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - dptr_set_wcard(dptr_num, wcard); - dptr_set_attr(dptr_num, dirtype); - - DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); + switch (info_level) + { + case 1: + case 2: + case 3: + case 4: + case SMB_FIND_FILE_DIRECTORY_INFO: + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + case SMB_FIND_FILE_NAMES_INFO: + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + break; + default: + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + } + + srvstr_pull(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE); + + RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); + + unix_convert(directory,conn,0,&bad_path,&sbuf); + if(!check_name(directory,conn)) { + if((errno == ENOENT) && bad_path) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ +#if 0 + /* Ugly - NT specific hack - maybe not needed ? (JRA) */ + if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && + (get_remote_arch() == RA_WINNT)) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbaddirectory; + } +#endif + + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + + p = strrchr_m(directory,'/'); + if(p == NULL) { + pstrcpy(mask,directory); + pstrcpy(directory,"./"); + } else { + pstrcpy(mask,p+1); + *p = 0; + } + + DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); + + pdata = Realloc(*ppdata, max_data_bytes + 1024); + if( pdata == NULL ) { + return(ERROR_DOS(ERRDOS,ERRnomem)); + } + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + /* Realloc the params space */ + params = Realloc(*pparams, 10); + if (params == NULL) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *pparams = params; + + dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid)); + if (dptr_num < 0) + return(UNIXERROR(ERRDOS,ERRbadfile)); + + /* Save the wildcard match and attribs we are using on this directory - + needed as lanman2 assumes these are being saved between calls */ + + if(!(wcard = strdup(mask))) { + dptr_close(&dptr_num); + return ERROR_DOS(ERRDOS,ERRnomem); + } + + dptr_set_wcard(dptr_num, wcard); + dptr_set_attr(dptr_num, dirtype); + + DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); + + /* We don't need to check for VOL here as this is returned by + a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) - dont_descend = True; + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", + conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + dont_descend = True; - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - for (i=0;(i<maxentries) && !finished && !out_of_space;i++) { - BOOL got_exact_match = False; - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) { - out_of_space = True; - finished = False; - } else { - finished = !get_lanman2_dir_entry(conn, + p = pdata; + space_remaining = max_data_bytes; + out_of_space = False; + + for (i=0;(i<maxentries) && !finished && !out_of_space;i++) + { + BOOL got_exact_match = False; + + /* this is a heuristic to avoid seeking the dirptr except when + absolutely necessary. It allows for a filename of about 40 chars */ + if (space_remaining < DIRLEN_GUESS && numentries > 0) + { + out_of_space = True; + finished = False; + } + else + { + finished = !get_lanman2_dir_entry(conn, inbuf, outbuf, mask,dirtype,info_level, requires_resume_key,dont_descend, &p,pdata,space_remaining, &out_of_space, &got_exact_match, &last_name_off); - } + } - if (finished && out_of_space) - finished = False; + if (finished && out_of_space) + finished = False; - if (!finished && !out_of_space) - numentries++; + if (!finished && !out_of_space) + numentries++; - /* - * As an optimisation if we know we aren't looking - * for a wildcard name (ie. the name matches the wildcard exactly) - * then we can finish on any (first) match. - * This speeds up large directory searches. JRA. - */ + /* + * As an optimisation if we know we aren't looking + * for a wildcard name (ie. the name matches the wildcard exactly) + * then we can finish on any (first) match. + * This speeds up large directory searches. JRA. + */ - if(got_exact_match) - finished = True; + if(got_exact_match) + finished = True; - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } + space_remaining = max_data_bytes - PTR_DIFF(p,pdata); + } - /* Check if we can close the dirptr */ - if(close_after_first || (finished && close_if_end)) { - DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_close(&dptr_num); - } - - /* - * If there are no matching entries we must return ERRDOS/ERRbadfile - - * from observation of NT. - */ - - if(numentries == 0) { - dptr_close(&dptr_num); - return ERROR_DOS(ERRDOS,ERRbadfile); - } - - /* At this point pdata points to numentries directory entries. */ - - /* Set up the return parameter block */ - SSVAL(params,0,dptr_num); - SSVAL(params,2,numentries); - SSVAL(params,4,finished); - SSVAL(params,6,0); /* Never an EA error */ - SSVAL(params,8,last_name_off); - - send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); - - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - - DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); - - /* - * Force a name mangle here to ensure that the - * mask as an 8.3 name is top of the mangled cache. - * The reasons for this are subtle. Don't remove - * this code unless you know what you are doing - * (see PR#13758). JRA. - */ - - if(!mangle_is_8_3_wildcards( mask, False)) - mangle_map(mask, True, True, SNUM(conn)); - - return(-1); + /* Check if we can close the dirptr */ + if(close_after_first || (finished && close_if_end)) + { + DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); + dptr_close(&dptr_num); + } + + /* + * If there are no matching entries we must return ERRDOS/ERRbadfile - + * from observation of NT. + */ + + if(numentries == 0) { + dptr_close(&dptr_num); + return ERROR_DOS(ERRDOS,ERRbadfile); + } + + /* At this point pdata points to numentries directory entries. */ + + /* Set up the return parameter block */ + SSVAL(params,0,dptr_num); + SSVAL(params,2,numentries); + SSVAL(params,4,finished); + SSVAL(params,6,0); /* Never an EA error */ + SSVAL(params,8,last_name_off); + + send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); + + if ((! *directory) && dptr_path(dptr_num)) + slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + + DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); + + /* + * Force a name mangle here to ensure that the + * mask as an 8.3 name is top of the mangled cache. + * The reasons for this are subtle. Don't remove + * this code unless you know what you are doing + * (see PR#13758). JRA. + */ + + if(!mangle_is_8_3( mask, False)) + mangle_map(mask, True, True, SNUM(conn)); + + return(-1); } /**************************************************************************** Reply to a TRANS2_FINDNEXT. ****************************************************************************/ -static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) +static int call_trans2findnext(connection_struct *conn, + char *inbuf, char *outbuf, + int length, int bufsize, + char **pparams, char **ppdata) { - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dptr_num = SVAL(params,0); - int maxentries = SVAL(params,2); - uint16 info_level = SVAL(params,4); - uint32 resume_key = IVAL(params,6); - BOOL close_after_request = BITSETW(params+10,0); - BOOL close_if_end = BITSETW(params+10,1); - BOOL requires_resume_key = BITSETW(params+10,2); - BOOL continue_bit = BITSETW(params+10,3); - pstring resume_name; - pstring mask; - pstring directory; - char *p; - uint16 dirtype; - int numentries = 0; - int i, last_name_off=0; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - - if (total_params < 12) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - *mask = *directory = *resume_name = 0; - - srvstr_pull(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE); - - DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ + /* We must be careful here that we don't return more than the + allowed number of data bytes. If this means returning fewer than + maxentries then so be it. We assume that the redirector has + enough room for the fixed number of parameter bytes it has + requested. */ + int max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *params = *pparams; + char *pdata = *ppdata; + int dptr_num = SVAL(params,0); + int maxentries = SVAL(params,2); + uint16 info_level = SVAL(params,4); + uint32 resume_key = IVAL(params,6); + BOOL close_after_request = BITSETW(params+10,0); + BOOL close_if_end = BITSETW(params+10,1); + BOOL requires_resume_key = BITSETW(params+10,2); + BOOL continue_bit = BITSETW(params+10,3); + pstring resume_name; + pstring mask; + pstring directory; + char *p; + uint16 dirtype; + int numentries = 0; + int i, last_name_off=0; + BOOL finished = False; + BOOL dont_descend = False; + BOOL out_of_space = False; + int space_remaining; + + *mask = *directory = *resume_name = 0; + + srvstr_pull(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE); + + DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ close_after_request=%d, close_if_end = %d requires_resume_key = %d \ resume_key = %d resume name = %s continue=%d level = %d\n", - dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, - requires_resume_key, resume_key, resume_name, continue_bit, info_level)); - - switch (info_level) { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - case SMB_FIND_FILE_UNIX: - if (!lp_unix_extensions()) - return(ERROR_DOS(ERRDOS,ERRunknownlevel)); - break; - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - pdata = Realloc( *ppdata, max_data_bytes + 1024); - if(pdata == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - /* Realloc the params space */ - params = Realloc(*pparams, 6*SIZEOFWORD); - if( params == NULL ) - return ERROR_DOS(ERRDOS,ERRnomem); - - *pparams = params; - - /* Check that the dptr is valid */ - if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) - return ERROR_DOS(ERRDOS,ERRnofiles); - - string_set(&conn->dirpath,dptr_path(dptr_num)); - - /* Get the wildcard mask from the dptr */ - if((p = dptr_wcard(dptr_num))== NULL) { - DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - return ERROR_DOS(ERRDOS,ERRnofiles); - } - - pstrcpy(mask, p); - pstrcpy(directory,conn->dirpath); - - /* Get the attr mask from the dptr */ - dirtype = dptr_attr(dptr_num); - - DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n", - dptr_num, mask, dirtype, - (long)conn->dirptr, - TellDir(conn->dirptr))); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ - - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) - dont_descend = True; + dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, + requires_resume_key, resume_key, resume_name, continue_bit, info_level)); + + switch (info_level) + { + case 1: + case 2: + case 3: + case 4: + case SMB_FIND_FILE_DIRECTORY_INFO: + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + case SMB_FIND_FILE_NAMES_INFO: + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + break; + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + pdata = Realloc( *ppdata, max_data_bytes + 1024); + if(pdata == NULL) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + /* Realloc the params space */ + params = Realloc(*pparams, 6*SIZEOFWORD); + if( params == NULL ) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *pparams = params; + + /* Check that the dptr is valid */ + if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) + return ERROR_DOS(ERRDOS,ERRnofiles); + + string_set(&conn->dirpath,dptr_path(dptr_num)); + + /* Get the wildcard mask from the dptr */ + if((p = dptr_wcard(dptr_num))== NULL) { + DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); + return ERROR_DOS(ERRDOS,ERRnofiles); + } + pstrcpy(mask, p); + pstrcpy(directory,conn->dirpath); + + /* Get the attr mask from the dptr */ + dirtype = dptr_attr(dptr_num); + + DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n", + dptr_num, mask, dirtype, + (long)conn->dirptr, + TellDir(conn->dirptr))); + + /* We don't need to check for VOL here as this is returned by + a different TRANS2 call. */ + + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + dont_descend = True; - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - /* - * Seek to the correct position. We no longer use the resume key but - * depend on the last file name instead. - */ - - if(requires_resume_key && *resume_name && !continue_bit) { - - /* - * Fix for NT redirector problem triggered by resume key indexes - * changing between directory scans. We now return a resume key of 0 - * and instead look for the filename to continue from (also given - * to us by NT/95/smbfs/smbclient). If no other scans have been done between the - * findfirst/findnext (as is usual) then the directory pointer - * should already be at the correct place. Check this by scanning - * backwards looking for an exact (ie. case sensitive) filename match. - * If we get to the beginning of the directory and haven't found it then scan - * forwards again looking for a match. JRA. - */ - - int current_pos, start_pos; - char *dname = NULL; - void *dirptr = conn->dirptr; - start_pos = TellDir(dirptr); - for(current_pos = start_pos; current_pos >= 0; current_pos--) { - DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos)); - - SeekDir(dirptr, current_pos); - dname = ReadDirName(dirptr); - - /* - * Remember, mangle_map is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname != NULL) - mangle_map( dname, False, True, SNUM(conn)); - - if(dname && strcsequal( resume_name, dname)) { - SeekDir(dirptr, current_pos+1); - DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); - break; - } - } - - /* - * Scan forward from start if not found going backwards. - */ - - if(current_pos < 0) { - DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos)); - SeekDir(dirptr, start_pos); - for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) { - - /* - * Remember, mangle_map is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname != NULL) - mangle_map( dname, False, True, SNUM(conn)); - - if(dname && strcsequal( resume_name, dname)) { - SeekDir(dirptr, current_pos+1); - DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); - break; - } - } /* end for */ - } /* end if current_pos */ - } /* end if requires_resume_key && !continue_bit */ - - for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) { - BOOL got_exact_match = False; - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) { - out_of_space = True; - finished = False; - } else { - finished = !get_lanman2_dir_entry(conn, - inbuf, outbuf, - mask,dirtype,info_level, - requires_resume_key,dont_descend, - &p,pdata,space_remaining, &out_of_space, &got_exact_match, - &last_name_off); - } + p = pdata; + space_remaining = max_data_bytes; + out_of_space = False; + + /* + * Seek to the correct position. We no longer use the resume key but + * depend on the last file name instead. + */ + if(requires_resume_key && *resume_name && !continue_bit) + { + /* + * Fix for NT redirector problem triggered by resume key indexes + * changing between directory scans. We now return a resume key of 0 + * and instead look for the filename to continue from (also given + * to us by NT/95/smbfs/smbclient). If no other scans have been done between the + * findfirst/findnext (as is usual) then the directory pointer + * should already be at the correct place. Check this by scanning + * backwards looking for an exact (ie. case sensitive) filename match. + * If we get to the beginning of the directory and haven't found it then scan + * forwards again looking for a match. JRA. + */ + + int current_pos, start_pos; + char *dname = NULL; + void *dirptr = conn->dirptr; + start_pos = TellDir(dirptr); + for(current_pos = start_pos; current_pos >= 0; current_pos--) + { + DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos)); + + SeekDir(dirptr, current_pos); + dname = ReadDirName(dirptr); + + /* + * Remember, mangle_map is called by + * get_lanman2_dir_entry(), so the resume name + * could be mangled. Ensure we do the same + * here. + */ + + if(dname != NULL) + mangle_map( dname, False, True, SNUM(conn)); + + if(dname && strcsequal( resume_name, dname)) + { + SeekDir(dirptr, current_pos+1); + DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); + break; + } + } + + /* + * Scan forward from start if not found going backwards. + */ + + if(current_pos < 0) + { + DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos)); + SeekDir(dirptr, start_pos); + for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) + { + /* + * Remember, mangle_map is called by + * get_lanman2_dir_entry(), so the resume name + * could be mangled. Ensure we do the same + * here. + */ + + if(dname != NULL) + mangle_map( dname, False, True, SNUM(conn)); + + if(dname && strcsequal( resume_name, dname)) + { + SeekDir(dirptr, current_pos+1); + DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); + break; + } + } /* end for */ + } /* end if current_pos */ + } /* end if requires_resume_key && !continue_bit */ + + for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) + { + BOOL got_exact_match = False; + + /* this is a heuristic to avoid seeking the dirptr except when + absolutely necessary. It allows for a filename of about 40 chars */ + if (space_remaining < DIRLEN_GUESS && numentries > 0) + { + out_of_space = True; + finished = False; + } + else + { + finished = !get_lanman2_dir_entry(conn, + inbuf, outbuf, + mask,dirtype,info_level, + requires_resume_key,dont_descend, + &p,pdata,space_remaining, &out_of_space, &got_exact_match, + &last_name_off); + } - if (finished && out_of_space) - finished = False; + if (finished && out_of_space) + finished = False; - if (!finished && !out_of_space) - numentries++; + if (!finished && !out_of_space) + numentries++; - /* - * As an optimisation if we know we aren't looking - * for a wildcard name (ie. the name matches the wildcard exactly) - * then we can finish on any (first) match. - * This speeds up large directory searches. JRA. - */ + /* + * As an optimisation if we know we aren't looking + * for a wildcard name (ie. the name matches the wildcard exactly) + * then we can finish on any (first) match. + * This speeds up large directory searches. JRA. + */ - if(got_exact_match) - finished = True; + if(got_exact_match) + finished = True; - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } + space_remaining = max_data_bytes - PTR_DIFF(p,pdata); + } - /* Check if we can close the dirptr */ - if(close_after_request || (finished && close_if_end)) { - DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_close(&dptr_num); /* This frees up the saved mask */ - } + /* Check if we can close the dirptr */ + if(close_after_request || (finished && close_if_end)) + { + DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); + dptr_close(&dptr_num); /* This frees up the saved mask */ + } - /* Set up the return parameter block */ - SSVAL(params,0,numentries); - SSVAL(params,2,finished); - SSVAL(params,4,0); /* Never an EA error */ - SSVAL(params,6,last_name_off); + /* Set up the return parameter block */ + SSVAL(params,0,numentries); + SSVAL(params,2,finished); + SSVAL(params,4,0); /* Never an EA error */ + SSVAL(params,6,last_name_off); - send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); + send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + if ((! *directory) && dptr_path(dptr_num)) + slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); + DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); - return(-1); + return(-1); } /**************************************************************************** Reply to a TRANS2_QFSINFO (query filesystem info). ****************************************************************************/ -static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) +static int call_trans2qfsinfo(connection_struct *conn, + char *inbuf, char *outbuf, + int length, int bufsize, + char **pparams, char **ppdata) { - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *pdata = *ppdata; - char *params = *pparams; - uint16 info_level = SVAL(params,0); - int data_len, len; - SMB_STRUCT_STAT st; - char *vname = volume_label(SNUM(conn)); - int snum = SNUM(conn); - char *fstype = lp_fstype(SNUM(conn)); - - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - - if(vfs_stat(conn,".",&st)!=0) { - DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); - return ERROR_DOS(ERRSRV,ERRinvdevice); - } - - pdata = Realloc(*ppdata, max_data_bytes + 1024); - if ( pdata == NULL ) - return ERROR_DOS(ERRDOS,ERRnomem); - - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - switch (info_level) { - case SMB_INFO_ALLOCATION: - { - SMB_BIG_UINT dfree,dsize,bsize; - data_len = 18; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - SIVAL(pdata,l1_idFileSystem,st.st_dev); - SIVAL(pdata,l1_cSectorUnit,bsize/512); - SIVAL(pdata,l1_cUnit,dsize); - SIVAL(pdata,l1_cUnitAvail,dfree); - SSVAL(pdata,l1_cbSector,512); - DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n", - (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize, - (unsigned int)dfree, 512)); - break; - } - - case SMB_INFO_VOLUME: - /* Return volume name */ - /* - * Add volume serial number - hash of a combination of - * the called hostname and the service name. - */ - SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); - len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_TERMINATE); - SCVAL(pdata,l2_vol_cch,len); - data_len = l2_vol_szVolLabel + len; - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", - (unsigned)st.st_ctime, len, vname)); - break; - - case SMB_QUERY_FS_ATTRIBUTE_INFO: - case SMB_FS_ATTRIBUTE_INFORMATION: - - SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| - (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ - SIVAL(pdata,4,255); /* Max filename component length */ - /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it - and will think we can't do long filenames */ - len = srvstr_push(outbuf, pdata+12, fstype, -1, 0); - SIVAL(pdata,8,len); - data_len = 12 + len; - break; - - case SMB_QUERY_FS_LABEL_INFO: - case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(outbuf, pdata+4, vname, -1, STR_TERMINATE); - data_len = 4 + len; - SIVAL(pdata,0,len); - break; - - case SMB_QUERY_FS_VOLUME_INFO: - case SMB_FS_VOLUME_INFORMATION: - - /* - * Add volume serial number - hash of a combination of - * the called hostname and the service name. - */ - SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ - (str_checksum(local_machine)<<16)); - - len = srvstr_push(outbuf, pdata+18, vname, -1, STR_TERMINATE); - SIVAL(pdata,12,len); - data_len = 18+len; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", - (int)strlen(vname),vname, lp_servicename(snum))); - break; - - case SMB_QUERY_FS_SIZE_INFO: - case SMB_FS_SIZE_INFORMATION: - { - SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; - data_len = 24; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - block_size = lp_block_size(snum); - if (bsize < block_size) { - SMB_BIG_UINT factor = block_size/bsize; - bsize = block_size; - dsize /= factor; - dfree /= factor; - } - if (bsize > block_size) { - SMB_BIG_UINT factor = bsize/block_size; - bsize = block_size; - dsize *= factor; - dfree *= factor; - } - bytes_per_sector = 512; - sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ -cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, - (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); - SBIG_UINT(pdata,0,dsize); - SBIG_UINT(pdata,8,dfree); - SIVAL(pdata,16,sectors_per_unit); - SIVAL(pdata,20,bytes_per_sector); - break; - } - - case SMB_FS_FULL_SIZE_INFORMATION: - { - SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; - data_len = 32; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - block_size = lp_block_size(snum); - if (bsize < block_size) { - SMB_BIG_UINT factor = block_size/bsize; - bsize = block_size; - dsize /= factor; - dfree /= factor; - } - if (bsize > block_size) { - SMB_BIG_UINT factor = bsize/block_size; - bsize = block_size; - dsize *= factor; - dfree *= factor; - } - bytes_per_sector = 512; - sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ -cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, - (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); - SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */ - SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */ - SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */ - SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */ - SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */ - break; - } - - case SMB_QUERY_FS_DEVICE_INFO: - case SMB_FS_DEVICE_INFORMATION: - data_len = 8; - SIVAL(pdata,0,0); /* dev type */ - SIVAL(pdata,4,0); /* characteristics */ - break; - - case SMB_FS_OBJECTID_INFORMATION: - data_len = 64; - break; - - /* - * Query the version and capabilities of the CIFS UNIX extensions - * in use. - */ - - case SMB_QUERY_CIFS_UNIX_INFO: - if (!lp_unix_extensions()) - return ERROR_DOS(ERRDOS,ERRunknownlevel); - data_len = 12; - SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION); - SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION); - SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */ - break; - - case SMB_MAC_QUERY_FS_INFO: - /* - * Thursby MAC extension... ONLY on NTFS filesystems - * once we do streams then we don't need this - */ - if (strequal(lp_fstype(SNUM(conn)),"NTFS")) { - data_len = 88; - SIVAL(pdata,84,0x100); /* Don't support mac... */ - break; - } - /* drop through */ - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - - send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); + int max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *pdata = *ppdata; + char *params = *pparams; + uint16 info_level = SVAL(params,0); + int data_len, len; + SMB_STRUCT_STAT st; + char *vname = volume_label(SNUM(conn)); + int snum = SNUM(conn); + char *fstype = lp_fstype(SNUM(conn)); + + DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + + if(vfs_stat(conn,".",&st)!=0) { + DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); + return ERROR_DOS(ERRSRV,ERRinvdevice); + } + + pdata = Realloc(*ppdata, max_data_bytes + 1024); + if ( pdata == NULL ) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + switch (info_level) + { + case 1: + { + SMB_BIG_UINT dfree,dsize,bsize; + data_len = 18; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SIVAL(pdata,l1_idFileSystem,st.st_dev); + SIVAL(pdata,l1_cSectorUnit,bsize/512); + SIVAL(pdata,l1_cUnit,dsize); + SIVAL(pdata,l1_cUnitAvail,dfree); + SSVAL(pdata,l1_cbSector,512); + DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n", + (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize, + (unsigned int)dfree, 512)); + break; + } + case 2: + /* Return volume name */ + /* + * Add volume serial number - hash of a combination of + * the called hostname and the service name. + */ + SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); + len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, + STR_TERMINATE); + SCVAL(pdata,l2_vol_cch,len); + data_len = l2_vol_szVolLabel + len; + DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", + (unsigned)st.st_ctime, len, vname)); + break; - DEBUG( 4, ( "%s info_level = %d\n", smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); + case SMB_QUERY_FS_ATTRIBUTE_INFO: + SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| + (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ + SIVAL(pdata,4,255); /* Max filename component length */ + /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it + and will think we can't do long filenames */ + len = srvstr_push(outbuf, pdata+12, fstype, -1, 0); + SIVAL(pdata,8,len); + data_len = 12 + len; + break; - return -1; + case SMB_QUERY_FS_LABEL_INFO: + len = srvstr_push(outbuf, pdata+4, vname, -1, STR_TERMINATE); + data_len = 4 + len; + SIVAL(pdata,0,len); + break; + case SMB_QUERY_FS_VOLUME_INFO: + /* + * Add volume serial number - hash of a combination of + * the called hostname and the service name. + */ + SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ + (str_checksum(local_machine)<<16)); + + len = srvstr_push(outbuf, pdata+18, vname, -1, STR_TERMINATE); + SIVAL(pdata,12,len); + data_len = 18+len; + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", + (int)strlen(vname),vname, lp_servicename(snum))); + break; + case SMB_QUERY_FS_SIZE_INFO: + { + SMB_BIG_UINT dfree,dsize,bsize; + data_len = 24; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SBIG_UINT(pdata,0,dsize); + SBIG_UINT(pdata,8,dfree); + SIVAL(pdata,16,bsize/512); + SIVAL(pdata,20,512); + break; + } + case SMB_QUERY_FS_DEVICE_INFO: + data_len = 8; + SIVAL(pdata,0,0); /* dev type */ + SIVAL(pdata,4,0); /* characteristics */ + break; + case SMB_MAC_QUERY_FS_INFO: + /* + * Thursby MAC extension... ONLY on NTFS filesystems + * once we do streams then we don't need this + */ + if (strequal(lp_fstype(SNUM(conn)),"NTFS")) { + data_len = 88; + SIVAL(pdata,84,0x100); /* Don't support mac... */ + break; + } + /* drop through */ + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + + send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); + + DEBUG( 4, ( "%s info_level = %d\n", + smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); + + return -1; } /**************************************************************************** @@ -1482,20 +1395,21 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned ****************************************************************************/ static int call_trans2setfsinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char *inbuf, char *outbuf, int length, + int bufsize, + char **pparams, char **ppdata) { - /* Just say yes we did it - there is nothing that - can be set here so it doesn't matter. */ - int outsize; - DEBUG(3,("call_trans2setfsinfo\n")); + /* Just say yes we did it - there is nothing that + can be set here so it doesn't matter. */ + int outsize; + DEBUG(3,("call_trans2setfsinfo\n")); - if (!CAN_WRITE(conn)) - return ERROR_DOS(ERRSRV,ERRaccess); + if (!CAN_WRITE(conn)) + return ERROR_DOS(ERRSRV,ERRaccess); - outsize = set_message(outbuf,10,0,True); + outsize = set_message(outbuf,10,0,True); - return outsize; + return outsize; } /**************************************************************************** @@ -1520,7 +1434,8 @@ NTSTATUS set_bad_path_error(int err, BOOL bad_path) static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char **pparams,char **ppdata, + int total_data) { int max_data_bytes = SVAL(inbuf, smb_mdrcnt); char *params = *pparams; @@ -1533,7 +1448,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, unsigned int data_size; SMB_STRUCT_STAT sbuf; pstring fname, dos_fname; - char *fullpathname; char *base_name; char *p; SMB_OFF_T pos = 0; @@ -1542,8 +1456,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, int len; time_t c_time; - if (!params) + if (!params) { return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } if (tran_call == TRANSACT2_QFILEINFO) { files_struct *fsp = file_fsp(params,0); @@ -1559,25 +1474,16 @@ static int call_trans2qfilepathinfo(connection_struct *conn, */ pstrcpy(fname, fsp->fsp_name); unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (vfs_lstat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + if (!check_name(fname,conn) || + (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) { + DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; } - } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } - + delete_pending = fsp->directory_delete_on_close; } else { /* @@ -1597,9 +1503,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, } } else { /* qpathinfo */ - if (total_params < 6) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - info_level = SVAL(params,0); DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); @@ -1609,28 +1512,17 @@ static int call_trans2qfilepathinfo(connection_struct *conn, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (vfs_lstat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + if (!check_name(fname,conn) || + (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) { + DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; } - } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } } - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) - return ERROR_DOS(ERRDOS,ERRunknownlevel); DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n", fname,info_level,tran_call,total_data)); @@ -1642,9 +1534,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, base_name = p+1; mode = dos_mode(conn,fname,&sbuf); - fullpathname = fname; size = sbuf.st_size; allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size); + if (mode & aDIR) size = 0; @@ -1676,13 +1568,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn, sbuf.st_mtime &= ~1; } - /* NT expects the name to be in an exact form of the *full* - filename. See the trans2 torture test */ - if (strequal(base_name,".")) { + /* NT expects the name to be in an exact form */ + if (strequal(fname,".")) { pstrcpy(dos_fname, "\\"); } else { snprintf(dos_fname, sizeof(dos_fname), "\\%s", fname); - string_replace(dos_fname, '/', '\\'); + string_replace( dos_fname, '/', '\\'); } switch (info_level) { @@ -1745,7 +1636,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_FILE_STANDARD_INFORMATION: case SMB_QUERY_FILE_STANDARD_INFO: - data_size = 24; /* Fake up allocation size. */ SOFF_T(pdata,0,allocation_size); @@ -1768,7 +1658,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, pstrcpy(short_name,base_name); /* Mangle if not already 8.3 */ if(!mangle_is_8_3(short_name, True)) { - mangle_map(short_name,True,True,SNUM(conn)); + if(!mangle_map(short_name,True,True,SNUM(conn))) + *short_name = '\0'; } len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_TERMINATE|STR_UPPER); data_size = 4 + len; @@ -1785,18 +1676,18 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SIVAL(pdata,0,len); break; - case SMB_FILE_ALLOCATION_INFORMATION: - case SMB_QUERY_FILE_ALLOCATION_INFO: - data_size = 8; - SOFF_T(pdata,0,allocation_size); - break; - case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_QUERY_FILE_END_OF_FILEINFO: data_size = 8; SOFF_T(pdata,0,size); break; + case SMB_FILE_ALLOCATION_INFORMATION: + case SMB_QUERY_FILE_ALLOCATION_INFO: + data_size = 8; + SOFF_T(pdata,0,allocation_size); + break; + case SMB_QUERY_FILE_ALL_INFO: put_long_date(pdata,c_time); put_long_date(pdata+8,sbuf.st_atime); @@ -1902,14 +1793,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; } -#if 0 - /* - * NT4 server just returns "invalid query" to this - if we try to answer - * it then NTws gets a BSOD! (tridge). - * W2K seems to want this. JRA. - */ - case SMB_QUERY_FILE_STREAM_INFO: -#endif case SMB_FILE_STREAM_INFORMATION: if (mode & aDIR) { data_size = 0; @@ -1949,92 +1832,18 @@ static int call_trans2qfilepathinfo(connection_struct *conn, data_size = 8; break; - /* - * CIFS UNIX Extensions. - */ - - case SMB_QUERY_FILE_UNIX_BASIC: - - DEBUG(4,("call_trans2qfilepathinfo: st_mode=%o\n",(int)sbuf.st_mode)); - - SOFF_T(pdata,0,sbuf.st_size); /* File size 64 Bit */ - pdata += 8; - -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ -#else - /* Can't get the value - fake it using size. */ - SOFF_T(pdata,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */ -#endif - pdata += 8; - - put_long_date(pdata,sbuf.st_ctime); /* Creation Time 64 Bit */ - put_long_date(pdata+8,sbuf.st_atime); /* Last access time 64 Bit */ - put_long_date(pdata+16,sbuf.st_mtime); /* Last modification time 64 Bit */ - pdata += 24; - - SIVAL(pdata,0,sbuf.st_uid); /* user id for the owner */ - SIVAL(pdata,4,0); - pdata += 8; - - SIVAL(pdata,0,sbuf.st_gid); /* group id of owner */ - SIVAL(pdata,4,0); - pdata += 8; - - SIVAL(pdata,0,unix_filetype(sbuf.st_mode)); - pdata += 4; - - SIVAL(pdata,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */ - SIVAL(pdata,4,0); - pdata += 8; - - SIVAL(pdata,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */ - SIVAL(pdata,4,0); - pdata += 8; - - SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino); /* inode number */ - pdata += 8; - - SIVAL(pdata,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */ - SIVAL(pdata,4,0); - pdata += 8; - - SIVAL(pdata,0,sbuf.st_nlink); /* number of hard links */ - SIVAL(pdata,4,0); - pdata += 8+1; - data_size = PTR_DIFF(pdata,(*ppdata)); - - { - int i; - DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC")); - - for (i=0; i<100; i++) - DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); - DEBUG(4,("\n")); - } - +#if 0 + /* NT4 server just returns "invalid query" to this - if we try to answer + it then NTws gets a BSOD! (tridge) */ + case SMB_QUERY_FILE_STREAM_INFO: + SIVAL(pdata,0,pos); + SIVAL(pdata,4,(uint32)size); + SIVAL(pdata,12,(uint32)allocation_size); + len = srvstr_push(outbuf, pdata+24, fname, -1, STR_TERMINATE); + SIVAL(pdata,20,len); + data_size = 24 + len; break; - - case SMB_QUERY_FILE_UNIX_LINK: - { - pstring buffer; - -#ifdef S_ISLNK - if(!S_ISLNK(sbuf.st_mode)) - return(UNIXERROR(ERRSRV,ERRbadlink)); -#else - return(UNIXERROR(ERRDOS,ERRbadlink)); #endif - len = conn->vfs_ops.readlink(conn,fullpathname, buffer, sizeof(pstring)-1); /* read link */ - if (len == -1) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - buffer[len] = 0; - len = srvstr_push(outbuf, pdata, buffer, -1, STR_TERMINATE); - pdata += len; - data_size = PTR_DIFF(pdata,(*ppdata)); - - break; - } default: return ERROR_DOS(ERRDOS,ERRunknownlevel); @@ -2134,78 +1943,19 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close) } /**************************************************************************** - Returns true if this pathname is within the share, and thus safe. -****************************************************************************/ - -static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out) -{ -#ifdef PATH_MAX - char resolved_name[PATH_MAX+1]; -#else - pstring resolved_name; -#endif - fstring last_component; - pstring link_dest; - pstring link_test; - char *p; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - - pstrcpy(link_dest, link_dest_in); - unix_convert(link_dest,conn,0,&bad_path,&sbuf); - - /* Store the UNIX converted path. */ - pstrcpy(link_dest_out, link_dest); - - p = strrchr(link_dest, '/'); - if (p) { - fstrcpy(last_component, p+1); - *p = '\0'; - } else { - fstrcpy(last_component, link_dest); - pstrcpy(link_dest, "./"); - } - - if (conn->vfs_ops.realpath(conn,link_dest,resolved_name) == NULL) - return -1; - - pstrcpy(link_dest, resolved_name); - pstrcat(link_dest, "/"); - pstrcat(link_dest, last_component); - - if (*link_dest != '/') { - /* Relative path. */ - pstrcpy(link_test, conn->connectpath); - pstrcat(link_test, "/"); - pstrcat(link_test, link_dest); - } else { - pstrcpy(link_test, link_dest); - } - - /* - * Check if the link is within the share. - */ - - if (strncmp(conn->connectpath, link_test, strlen(conn->connectpath))) { - errno = EACCES; - return -1; - } - return 0; -} - -/**************************************************************************** Reply to a TRANS2_SETFILEINFO (set file info by fileid). ****************************************************************************/ static int call_trans2setfilepathinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char *inbuf, char *outbuf, int length, + int bufsize, char **pparams, + char **ppdata, int total_data) { char *params = *pparams; char *pdata = *ppdata; uint16 tran_call = SVAL(inbuf, smb_setup0); uint16 info_level; - int dosmode=0; + int mode=0; SMB_OFF_T size=0; struct utimbuf tvs; SMB_STRUCT_STAT sbuf; @@ -2213,9 +1963,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, int fd = -1; BOOL bad_path = False; files_struct *fsp = NULL; - uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; - gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; - mode_t unixmode = 0; if (tran_call == TRANSACT2_SETFILEINFO) { fsp = file_fsp(params,0); @@ -2230,8 +1977,11 @@ static int call_trans2setfilepathinfo(connection_struct *conn, pstrcpy(fname, fsp->fsp_name); unix_convert(fname,conn,0,&bad_path,&sbuf); if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { - DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); + DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } return(UNIXERROR(ERRDOS,ERRbadpath)); } } else if (fsp && fsp->print_file) { @@ -2257,30 +2007,29 @@ static int call_trans2setfilepathinfo(connection_struct *conn, fd = fsp->fd; if (vfs_fstat(fsp,fd,&sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } } } else { /* set path info */ - if (total_params < 6) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - info_level = SVAL(params,0); srvstr_pull(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE); unix_convert(fname,conn,0,&bad_path,&sbuf); if(!check_name(fname, conn)) { - set_bad_path_error(errno, bad_path); + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } return(UNIXERROR(ERRDOS,ERRbadpath)); } - - /* - * For CIFS UNIX extensions the target name may not exist. - */ - - if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) { - DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno))); - set_bad_path_error(errno, bad_path); + + if(!VALID_STAT(sbuf)) { + DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno))); + if((errno == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } return(UNIXERROR(ERRDOS,ERRbadpath)); } } @@ -2288,12 +2037,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (!CAN_WRITE(conn)) return ERROR_DOS(ERRSRV,ERRaccess); - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) - return ERROR_DOS(ERRDOS,ERRunknownlevel); - - if (VALID_STAT(sbuf)) - unixmode = sbuf.st_mode; - DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n", tran_call,fname,info_level,total_data)); @@ -2305,36 +2048,29 @@ static int call_trans2setfilepathinfo(connection_struct *conn, SSVAL(params,0,0); - if (fsp) { - /* the pending modtime overrides the current modtime */ - sbuf.st_mtime = fsp->pending_modtime; - } - size = sbuf.st_size; tvs.modtime = sbuf.st_mtime; tvs.actime = sbuf.st_atime; - dosmode = dos_mode(conn,fname,&sbuf); - unixmode = sbuf.st_mode; + mode = dos_mode(conn,fname,&sbuf); - set_owner = VALID_STAT(sbuf) ? sbuf.st_uid : (uid_t)SMB_UID_NO_CHANGE; - set_grp = VALID_STAT(sbuf) ? sbuf.st_gid : (gid_t)SMB_GID_NO_CHANGE; + if (total_data > 4 && IVAL(pdata,0) == total_data) { + /* uggh, EAs for OS2 */ + DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); + return ERROR_DOS(ERRDOS,ERReasnotsupported); + } switch (info_level) { case SMB_INFO_STANDARD: case SMB_INFO_QUERY_EA_SIZE: { - if (total_data < l1_cbFile+4) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - /* access time */ tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess); /* write time */ tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite); - dosmode = SVAL(pdata,l1_attrFile); + mode = SVAL(pdata,l1_attrFile); size = IVAL(pdata,l1_cbFile); - break; } @@ -2342,24 +2078,18 @@ static int call_trans2setfilepathinfo(connection_struct *conn, it's also not in the cifs6.txt spec. */ case SMB_INFO_QUERY_EAS_FROM_LIST: - if (total_data < 28) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - tvs.actime = make_unix_date2(pdata+8); tvs.modtime = make_unix_date2(pdata+12); size = IVAL(pdata,16); - dosmode = IVAL(pdata,24); + mode = IVAL(pdata,24); break; /* XXXX nor this. not in cifs6.txt, either. */ case SMB_INFO_QUERY_ALL_EAS: - if (total_data < 28) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - tvs.actime = make_unix_date2(pdata+8); tvs.modtime = make_unix_date2(pdata+12); size = IVAL(pdata,16); - dosmode = IVAL(pdata,24); + mode = IVAL(pdata,24); break; case SMB_SET_FILE_BASIC_INFO: @@ -2369,9 +2099,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, time_t write_time; time_t changed_time; - if (total_data < 36) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - /* Ignore create time at offset pdata. */ /* access time */ @@ -2382,28 +2109,21 @@ static int call_trans2setfilepathinfo(connection_struct *conn, tvs.modtime = MIN(write_time, changed_time); - if (write_time > tvs.modtime && write_time != 0xffffffff) { - tvs.modtime = write_time; - } /* Prefer a defined time to an undefined one. */ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1) tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1 ? changed_time : write_time); /* attributes */ - dosmode = IVAL(pdata,32); + mode = IVAL(pdata,32); break; } - case SMB_FILE_ALLOCATION_INFORMATION: + case SMB_FILE_ALLOCATION_INFORMATION: case SMB_SET_FILE_ALLOCATION_INFO: { int ret = -1; SMB_OFF_T allocation_size = IVAL(pdata,0); - - if (total_data < 8) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - #ifdef LARGE_SMB_OFF_T allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ @@ -2443,16 +2163,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn, return(UNIXERROR(ERRDOS,ERRbadpath)); ret = vfs_allocate_file_space(new_fsp, allocation_size); if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", - new_fsp->fnum, strerror(errno))); + DEBUG(3,("fstat of fnum %d failed (%s)\n",new_fsp->fnum, strerror(errno))); ret = -1; } close_file(new_fsp,True); } else { ret = vfs_allocate_file_space(fsp, allocation_size); if (vfs_fstat(fsp,fd,&new_sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); + DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); ret = -1; } } @@ -2466,12 +2184,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } - case SMB_FILE_END_OF_FILE_INFORMATION: + case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_SET_FILE_END_OF_FILE_INFO: { - if (total_data < 8) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); @@ -2489,9 +2204,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, BOOL delete_on_close = (CVAL(pdata,0) ? True : False); NTSTATUS status; - if (total_data < 1) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - if (tran_call != TRANSACT2_SETFILEINFO) return ERROR_DOS(ERRDOS,ERRunknownlevel); @@ -2506,183 +2218,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } - /* - * CIFS UNIX extensions. - */ - - case SMB_SET_FILE_UNIX_BASIC: - { - uint32 raw_unixmode; - - if (total_data < 100) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO && - IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) { - size=IVAL(pdata,0); /* first 8 Bytes are size */ -#ifdef LARGE_SMB_OFF_T - size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); -#else /* LARGE_SMB_OFF_T */ - if (IVAL(pdata,4) != 0) /* more than 32 bits? */ - return ERROR_DOS(ERRDOS,ERRunknownlevel); -#endif /* LARGE_SMB_OFF_T */ - } - pdata+=24; /* ctime & st_blocks are not changed */ - tvs.actime = interpret_long_unix_date(pdata); /* access_time */ - tvs.modtime = interpret_long_unix_date(pdata+8); /* modification_time */ - pdata+=16; - set_owner = (uid_t)IVAL(pdata,0); - pdata += 8; - set_grp = (gid_t)IVAL(pdata,0); - pdata += 8; - raw_unixmode = IVAL(pdata,28); - unixmode = unix_perms_from_wire(conn, &sbuf, raw_unixmode); - dosmode = 0; /* Ensure dos mode change doesn't override this. */ - - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC: name = %s \ -size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", - fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode)); - - if (!VALID_STAT(sbuf)) { - - /* - * The only valid use of this is to create character and block - * devices, and named pipes. This is deprecated (IMHO) and - * a new info level should be used for mknod. JRA. - */ - -#if !defined(HAVE_MAKEDEV_FN) - return(ERROR_DOS(ERRDOS,ERRnoaccess)); -#else /* HAVE_MAKEDEV_FN */ - uint32 file_type = IVAL(pdata,0); - uint32 dev_major = IVAL(pdata,4); - uint32 dev_minor = IVAL(pdata,12); - - uid_t myuid = geteuid(); - gid_t mygid = getegid(); - SMB_DEV_T dev; - - if (tran_call == TRANSACT2_SETFILEINFO) - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - - if (raw_unixmode == SMB_MODE_NO_CHANGE) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - dev = makedev(dev_major, dev_minor); - - /* We can only create as the owner/group we are. */ - - if ((set_owner != myuid) && (set_owner != (uid_t)SMB_UID_NO_CHANGE)) - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - if ((set_grp != mygid) && (set_grp != (gid_t)SMB_GID_NO_CHANGE)) - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - - if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV && - file_type != UNIX_TYPE_FIFO) - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ -0%o for file %s\n", (double)dev, unixmode, fname )); - - /* Ok - do the mknod. */ - if (conn->vfs_ops.mknod(conn,dos_to_unix_static(fname), unixmode, dev) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); -#endif /* HAVE_MAKEDEV_FN */ - - } - - /* - * Deal with the UNIX specific mode set. - */ - - if (raw_unixmode != SMB_MODE_NO_CHANGE) { - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", - (unsigned int)unixmode, fname )); - if (vfs_chmod(conn,fname,unixmode) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* - * Deal with the UNIX specific uid set. - */ - - if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) { - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n", - (unsigned int)set_owner, fname )); - if (vfs_chown(conn,fname,set_owner, (gid_t)-1) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* - * Deal with the UNIX specific gid set. - */ - - if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) { - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n", - (unsigned int)set_owner, fname )); - if (vfs_chown(conn,fname,(uid_t)-1, set_grp) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - break; - } - - case SMB_SET_FILE_UNIX_LINK: - { - pstring link_dest; - /* Set a symbolic link. */ - /* Don't allow this if follow links is false. */ - - if (!lp_symlinks(SNUM(conn))) - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - - /* Disallow if already exists. */ - if (VALID_STAT(sbuf)) - return(ERROR_DOS(ERRDOS,ERRbadpath)); - - srvstr_pull(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE); - - if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", - fname, link_dest )); - - if (conn->vfs_ops.symlink(conn,link_dest,fname) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); - } - - case SMB_SET_FILE_UNIX_HLINK: - { - pstring link_dest; - - /* Set a hard link. */ - - /* Disallow if already exists. */ - if (VALID_STAT(sbuf)) - return(ERROR_DOS(ERRDOS,ERRbadpath)); - - srvstr_pull(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE); - - if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", - fname, link_dest )); - - if (conn->vfs_ops.link(conn,link_dest,fname) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); - } - default: return ERROR_DOS(ERRDOS,ERRunknownlevel); } @@ -2697,18 +2232,17 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", DEBUG(6,("actime: %s " , ctime(&tvs.actime))); DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); DEBUG(6,("size: %.0f ", (double)size)); + DEBUG(6,("mode: %x\n" , mode)); if (S_ISDIR(sbuf.st_mode)) - dosmode |= aDIR; + mode |= aDIR; else - dosmode &= ~aDIR; - - DEBUG(6,("dosmode: %x\n" , dosmode)); + mode &= ~aDIR; if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) || (info_level == SMB_SET_FILE_ALLOCATION_INFO) || (info_level == SMB_FILE_ALLOCATION_INFORMATION) || - (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) { + (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) { /* * Only do this test if we are not explicitly @@ -2729,7 +2263,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", * NT does this a lot. It's actually pointless * setting the time here, as it will be overwritten * on the next write, so we save the request - * away and will set it on file close. JRA. + * away and will set it on file code. JRA. */ if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { @@ -2747,11 +2281,11 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } /* check the mode isn't different, before changing it */ - if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) { + if ((mode != 0) && (mode != dos_mode(conn, fname, &sbuf))) { - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode )); + DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, mode )); - if(file_chmod(conn, fname, dosmode, NULL)) { + if(file_chmod(conn, fname, mode, NULL)) { DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno))); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -2797,6 +2331,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); return(-1); @@ -2808,45 +2343,48 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char **pparams, char **ppdata) { - char *params = *pparams; - pstring directory; - int ret = -1; - SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; + char *params = *pparams; + pstring directory; + int ret = -1; + SMB_STRUCT_STAT sbuf; + BOOL bad_path = False; - if (!CAN_WRITE(conn)) - return ERROR_DOS(ERRSRV,ERRaccess); + if (!CAN_WRITE(conn)) + return ERROR_DOS(ERRSRV,ERRaccess); - if (total_params < 4) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + srvstr_pull(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE); - srvstr_pull(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE); + DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (check_name(directory,conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + unix_convert(directory,conn,0,&bad_path,&sbuf); + if (check_name(directory,conn)) + ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); - if(ret < 0) { - DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,2); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - *pparams = params; - - SSVAL(params,0,0); - - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + if(ret < 0) + { + DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); + if((errno == ENOENT) && bad_path) + { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,2); + if(params == NULL) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *pparams = params; + + SSVAL(params,0,0); + + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** @@ -2855,45 +2393,44 @@ static int call_trans2mkdir(connection_struct *conn, ****************************************************************************/ static int call_trans2findnotifyfirst(connection_struct *conn, - char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char *inbuf, char *outbuf, + int length, int bufsize, + char **pparams, char **ppdata) { - static uint16 fnf_handle = 257; - char *params = *pparams; - uint16 info_level; - - if (total_params < 6) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - info_level = SVAL(params,4); - DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); - - switch (info_level) { - case 1: - case 2: - break; - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,6); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - *pparams = params; - - SSVAL(params,0,fnf_handle); - SSVAL(params,2,0); /* No changes */ - SSVAL(params,4,0); /* No EA errors */ - - fnf_handle++; - - if(fnf_handle == 0) - fnf_handle = 257; - - send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); + static uint16 fnf_handle = 257; + char *params = *pparams; + uint16 info_level = SVAL(params,4); + + DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); + + switch (info_level) + { + case 1: + case 2: + break; + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,6); + if(params == NULL) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *pparams = params; + + SSVAL(params,0,fnf_handle); + SSVAL(params,2,0); /* No changes */ + SSVAL(params,4,0); /* No EA errors */ + + fnf_handle++; + + if(fnf_handle == 0) + fnf_handle = 257; + + send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** @@ -2902,25 +2439,27 @@ static int call_trans2findnotifyfirst(connection_struct *conn, ****************************************************************************/ static int call_trans2findnotifynext(connection_struct *conn, - char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char *inbuf, char *outbuf, + int length, int bufsize, + char **pparams, char **ppdata) { - char *params = *pparams; + char *params = *pparams; - DEBUG(3,("call_trans2findnotifynext\n")); + DEBUG(3,("call_trans2findnotifynext\n")); - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,4); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - *pparams = params; + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,4); + if(params == NULL) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *pparams = params; - SSVAL(params,0,0); /* No changes */ - SSVAL(params,2,0); /* No EA errors */ + SSVAL(params,0,0); /* No changes */ + SSVAL(params,2,0); /* No EA errors */ - send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** @@ -2928,33 +2467,29 @@ static int call_trans2findnotifynext(connection_struct *conn, ****************************************************************************/ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, - char* outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char* outbuf, int length, int bufsize, + char** pparams, char** ppdata) { - char *params = *pparams; - pstring pathname; - int reply_size = 0; - int max_referral_level; + char *params = *pparams; + pstring pathname; + int reply_size = 0; + int max_referral_level = SVAL(params,0); - DEBUG(10,("call_trans2getdfsreferral\n")); - if (total_params < 2) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + DEBUG(10,("call_trans2getdfsreferral\n")); - max_referral_level = SVAL(params,0); + if(!lp_host_msdfs()) + return ERROR_DOS(ERRDOS,ERRbadfunc); - if(!lp_host_msdfs()) - return ERROR_DOS(ERRDOS,ERRbadfunc); + srvstr_pull(inbuf, pathname, ¶ms[2], sizeof(pathname), -1, STR_TERMINATE); - srvstr_pull(inbuf, pathname, ¶ms[2], sizeof(pathname), -1, STR_TERMINATE); - - if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0) - return ERROR_DOS(ERRDOS,ERRbadfile); + if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0) + return ERROR_DOS(ERRDOS,ERRbadfile); - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); - send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); + send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); - return(-1); + return(-1); } #define LMCAT_SPL 0x53 @@ -2965,31 +2500,32 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, ****************************************************************************/ static int call_trans2ioctl(connection_struct *conn, char* inbuf, - char* outbuf, int length, int bufsize, - char **pparams, int total_params, char **ppdata, int total_data) + char* outbuf, int length, int bufsize, + char** pparams, char** ppdata) { - char *pdata = *ppdata; - files_struct *fsp = file_fsp(inbuf,smb_vwv15); - - if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && - (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { - pdata = Realloc(*ppdata, 32); - if(pdata == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - *ppdata = pdata; - - /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2 - CAN ACCEPT THIS IN UNICODE. JRA. */ - - SSVAL(pdata,0,fsp->print_jobid); /* Job number */ - srvstr_push( outbuf, pdata + 2, global_myname, 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ - srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ - send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); - return(-1); - } else { - DEBUG(2,("Unknown TRANS2_IOCTL\n")); - return ERROR_DOS(ERRSRV,ERRerror); - } + char *pdata = *ppdata; + files_struct *fsp = file_fsp(inbuf,smb_vwv15); + + if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && + (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + pdata = Realloc(*ppdata, 32); + if(pdata == NULL) { + return ERROR_DOS(ERRDOS,ERRnomem); + } + *ppdata = pdata; + + /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2 + CAN ACCEPT THIS IN UNICODE. JRA. */ + + SSVAL(pdata,0,fsp->print_jobid); /* Job number */ + srvstr_push( outbuf, pdata + 2, global_myname, 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ + srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ + send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); + return(-1); + } else { + DEBUG(2,("Unknown TRANS2_IOCTL\n")); + return ERROR_DOS(ERRSRV,ERRerror); + } } /**************************************************************************** @@ -3200,84 +2736,93 @@ int reply_trans2(connection_struct *conn, switch(tran_call) { case TRANSACT2_OPEN: START_PROFILE_NESTED(Trans2_open); - outsize = call_trans2open(conn, inbuf, outbuf, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2open(conn, + inbuf, outbuf, bufsize, + ¶ms, &data); END_PROFILE_NESTED(Trans2_open); break; case TRANSACT2_FINDFIRST: START_PROFILE_NESTED(Trans2_findfirst); - outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2findfirst(conn, inbuf, outbuf, + bufsize, ¶ms, &data); END_PROFILE_NESTED(Trans2_findfirst); break; case TRANSACT2_FINDNEXT: START_PROFILE_NESTED(Trans2_findnext); - outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2findnext(conn, inbuf, outbuf, + length, bufsize, + ¶ms, &data); END_PROFILE_NESTED(Trans2_findnext); break; case TRANSACT2_QFSINFO: START_PROFILE_NESTED(Trans2_qfsinfo); - outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2qfsinfo(conn, inbuf, outbuf, + length, bufsize, ¶ms, + &data); END_PROFILE_NESTED(Trans2_qfsinfo); break; case TRANSACT2_SETFSINFO: START_PROFILE_NESTED(Trans2_setfsinfo); - outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2setfsinfo(conn, inbuf, outbuf, + length, bufsize, + ¶ms, &data); END_PROFILE_NESTED(Trans2_setfsinfo); break; case TRANSACT2_QPATHINFO: case TRANSACT2_QFILEINFO: START_PROFILE_NESTED(Trans2_qpathinfo); - outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, + length, bufsize, + ¶ms, &data, total_data); END_PROFILE_NESTED(Trans2_qpathinfo); break; case TRANSACT2_SETPATHINFO: case TRANSACT2_SETFILEINFO: START_PROFILE_NESTED(Trans2_setpathinfo); - outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, + length, bufsize, + ¶ms, &data, + total_data); END_PROFILE_NESTED(Trans2_setpathinfo); break; case TRANSACT2_FINDNOTIFYFIRST: START_PROFILE_NESTED(Trans2_findnotifyfirst); - outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, + length, bufsize, + ¶ms, &data); END_PROFILE_NESTED(Trans2_findnotifyfirst); break; case TRANSACT2_FINDNOTIFYNEXT: START_PROFILE_NESTED(Trans2_findnotifynext); - outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2findnotifynext(conn, inbuf, outbuf, + length, bufsize, + ¶ms, &data); END_PROFILE_NESTED(Trans2_findnotifynext); break; case TRANSACT2_MKDIR: START_PROFILE_NESTED(Trans2_mkdir); - outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2mkdir(conn, inbuf, outbuf, length, + bufsize, ¶ms, &data); END_PROFILE_NESTED(Trans2_mkdir); break; case TRANSACT2_GET_DFS_REFERRAL: START_PROFILE_NESTED(Trans2_get_dfs_referral); - outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, + bufsize, ¶ms, &data); END_PROFILE_NESTED(Trans2_get_dfs_referral); break; case TRANSACT2_IOCTL: START_PROFILE_NESTED(Trans2_ioctl); - outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize, - ¶ms, total_params, &data, total_data); + outsize = call_trans2ioctl(conn,inbuf,outbuf,length, + bufsize,¶ms,&data); END_PROFILE_NESTED(Trans2_ioctl); break; default: |