From 2b4b7b4e1adbd2aac9aab89b28df82fc145a6d87 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 30 Jul 1996 15:47:30 +0000 Subject: fix a bug that we've had for a long time where we don't handle EOF properly from clients, and end up looping like mad. At least I _hope_ this is fixed. (This used to be commit a7c7d7afe2ef81f4a74584ce9b71e54442f7e484) --- source3/client/client.c | 2 +- source3/include/proto.h | 5 +- source3/include/smb.h | 9 ++- source3/lib/util.c | 182 ++++++++++++----------------------------------- source3/smbd/chgpasswd.c | 2 +- source3/smbd/reply.c | 10 +-- source3/smbd/server.c | 44 ++++++------ 7 files changed, 81 insertions(+), 173 deletions(-) (limited to 'source3') diff --git a/source3/client/client.c b/source3/client/client.c index fde79c6e1b..7c4795a8c3 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -768,7 +768,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void ( memcpy(p,status,21); send_smb(Client,outbuf); - receive_smb(Client,inbuf,CLIENT_TIMEOUT,False); + receive_smb(Client,inbuf,CLIENT_TIMEOUT); if (CVAL(inbuf,smb_rcls) != 0) DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf))); diff --git a/source3/include/proto.h b/source3/include/proto.h index faddbc6a49..60b8eed59a 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -636,7 +636,7 @@ BOOL check_file_sharing(int cnum,char *fname); void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, int mode,int *Access,int *action); int seek_file(int fnum,int pos); -int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact); +int read_file(int fnum,char *data,int pos,int n); int write_file(int fnum,char *data,int n); BOOL become_service(int cnum,BOOL do_chdir); int find_service(char *service); @@ -819,8 +819,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode void close_low_fds(void); int write_socket(int fd,char *buf,int len); int read_udp_socket(int fd,char *buf,int len); -int set_blocking(int fd, BOOL set); -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact); +int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out); int read_max_udp(int fd,char *buffer,int bufsize,int maxtime); int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew); BOOL send_keepalive(int client); diff --git a/source3/include/smb.h b/source3/include/smb.h index 05924de35e..317f31b19e 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -111,11 +111,10 @@ EXTERN int syslog_level; #define DEBUG(level,body) ((DEBUGLEVEL>=(level))? (syslog_level = (level), Debug1 body):0) #endif -/* this defines the error codes that receive_smb can put in smberrcode */ -#define SMBERR_OK 0 -#define SMBERR_TIMEOUT 1 -#define SMBERR_EOF 2 -#define SMBERR_ERROR 3 +/* this defines the error codes that receive_smb can put in smb_read_error */ +#define READ_TIMEOUT 1 +#define READ_EOF 2 +#define READ_ERROR 3 #define DIR_STRUCT_SIZE 43 diff --git a/source3/lib/util.c b/source3/lib/util.c index ee4fca3ed3..8c221a23b6 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -75,6 +75,8 @@ pstring user_socket_options=""; pstring sesssetup_user=""; +int smb_read_error = 0; + static char *filename_dos(char *path,char *buf); static BOOL stdout_logging = False; @@ -1691,103 +1693,44 @@ int read_udp_socket(int fd,char *buf,int len) return(ret); } -/**************************************************************************** -Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, -else -if SYSV use O_NDELAY -if BSD use FNDELAY -****************************************************************************/ -int set_blocking(int fd, BOOL set) -{ -int val; -#ifdef O_NONBLOCK -#define FLAG_TO_SET O_NONBLOCK -#else -#ifdef SYSV -#define FLAG_TO_SET O_NDELAY -#else /* BSD */ -#define FLAG_TO_SET FNDELAY -#endif -#endif - - if((val = fcntl(fd, F_GETFL, 0))==-1) - return -1; - if(set) /* Turn blocking on - ie. clear nonblock flag */ - val &= ~FLAG_TO_SET; - else - val |= FLAG_TO_SET; - return fcntl( fd, F_SETFL, val); -#undef FLAG_TO_SET -} - - -/**************************************************************************** -Calculate the difference in timeout values. Return 1 if val1 > val2, -0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval -may be == val1 or val2 -****************************************************************************/ -static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) -{ - int usecdiff = val1->tv_usec - val2->tv_usec; - int secdiff = val1->tv_sec - val2->tv_sec; - if(usecdiff < 0) { - usecdiff = 1000000 + usecdiff; - secdiff--; - } - retval->tv_sec = secdiff; - retval->tv_usec = usecdiff; - if(secdiff < 0) - return -1; - if(secdiff > 0) - return 1; - return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0); -} - /**************************************************************************** read data from a device with a timout in msec. mincount = if timeout, minimum to read before returning maxcount = number to be read. ****************************************************************************/ -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) +int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out) { fd_set fds; int selrtn; int readret; int nread = 0; - struct timeval timeout, tval1, tval2, tvaldiff; - int error_limit = 5; + struct timeval timeout; /* just checking .... */ if (maxcnt <= 0) return(0); - if(time_out == -2) - time_out = DEFAULT_PIPE_TIMEOUT; + smb_read_error = 0; /* Blocking read */ - if(time_out < 0) { + if (time_out <= 0) { if (mincnt == 0) mincnt = maxcnt; - while (nread < mincnt) - { - readret = read(fd, buf + nread, maxcnt - nread); - if (readret <= 0) return(nread); - nread += readret; + while (nread < mincnt) { + readret = read(fd, buf + nread, maxcnt - nread); + if (readret == 0) { + smb_read_error = READ_EOF; + return -1; + } + + if (readret == -1) { + smb_read_error = READ_ERROR; + return -1; } + nread += readret; + } return(nread); } - /* Non blocking read */ - if(time_out == 0) { - set_blocking(fd, False); - nread = read_data(fd, buf, mincnt); - if (nread < maxcnt) - nread += read(fd,buf+nread,maxcnt-nread); - if(nread == -1 && errno == EWOULDBLOCK) - nread = 0; - set_blocking(fd,True); - return nread; - } - /* Most difficult - timeout read */ /* If this is ever called on a disk file and mincnt is greater then the filesize then @@ -1798,69 +1741,40 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL timeout.tv_sec = time_out / 1000; timeout.tv_usec = 1000 * (time_out % 1000); - /* As most UNIXes don't modify the value of timeout - when they return from select we need to get the timeofday (in usec) - now, and also after the select returns so we know - how much time has elapsed */ - - if (exact) - GetTimeOfDay( &tval1); - nread = 0; /* Number of bytes we have read */ - - for(;;) + for (nread=0; nread= mincnt) - break; - - /* We need to do another select - but first reduce the - time_out by the amount of time already elapsed - if - this is less than zero then return */ - if (exact) { - GetTimeOfDay(&tval2); - (void)tval_sub( &tvaldiff, &tval2, &tval1); - - if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) - break; /* We timed out */ - } - - /* Save the time of day as we need to do the select - again (saves a system call) */ - tval1 = tval2; } /* Return the number we got */ @@ -1927,12 +1841,19 @@ int read_data(int fd,char *buffer,int N) int ret; int total=0; + smb_read_error = 0; + while (total < N) { ret = read(fd,buffer + total,N - total); - - if (ret <= 0) - return total; + if (ret == 0) { + smb_read_error = READ_EOF; + return 0; + } + if (ret == -1) { + smb_read_error = READ_ERROR; + return -1; + } total += ret; } return total; @@ -2056,23 +1977,12 @@ int read_smb_length(int fd,char *inbuf,int timeout) while (!ok) { if (timeout > 0) - ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); - else + ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4); + else ok = (read_data(fd,buffer,4) == 4); if (!ok) - { - if (timeout>0) - { - DEBUG(10,("select timeout (%d)\n", timeout)); - return(-1); - } - else - { - DEBUG(6,("couldn't read from client\n")); - exit(1); - } - } + return(-1); len = smb_len(buffer); msg_type = CVAL(buffer,0); @@ -2099,6 +2009,8 @@ BOOL receive_smb(int fd,char *buffer,int timeout) { int len,ret; + smb_read_error = 0; + bzero(buffer,smb_size + 100); len = read_smb_length(fd,buffer,timeout); @@ -2113,7 +2025,7 @@ BOOL receive_smb(int fd,char *buffer,int timeout) ret = read_data(fd,buffer+4,len); if (ret != len) { - DEBUG(0,("ERROR: Invalid SMB length. Expected %d got %d\n",len,ret)); + smb_read_error = READ_ERROR; return False; } diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 809ac4d224..54b49edf13 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -178,7 +178,7 @@ static int expect(int master,char *expected,char *buf) } /* allow 4 seconds for some output to appear */ - m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000, True); + m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000); if (m < 0) return False; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 13cc8efe5d..d463b305c9 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1363,7 +1363,7 @@ int reply_readbraw(char *inbuf, char *outbuf) fname,startpos,nread,ret)); #else - ret = read_file(fnum,header+4,startpos,nread,nread,-1,False); + ret = read_file(fnum,header+4,startpos,nread); if (ret < mincount) ret = 0; _smb_setlen(header,ret); @@ -1405,7 +1405,7 @@ int reply_lockread(char *inbuf,char *outbuf) if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode)) return (ERROR(eclass,ecode)); - nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False); + nread = read_file(fnum,data,startpos,numtoread); if (nread < 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); @@ -1450,7 +1450,7 @@ int reply_read(char *inbuf,char *outbuf) return(ERROR(ERRDOS,ERRlock)); if (numtoread > 0) - nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False); + nread = read_file(fnum,data,startpos,numtoread); if (nread < 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); @@ -1495,7 +1495,7 @@ int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) if (is_locked(fnum,cnum,smb_maxcnt,smb_offs)) return(ERROR(ERRDOS,ERRlock)); - nread = read_file(fnum,data,smb_offs,smb_maxcnt,smb_maxcnt,-1,False); + nread = read_file(fnum,data,smb_offs,smb_maxcnt); ok = True; if (nread < 0) @@ -2934,7 +2934,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize) { int N = MIN(max_per_packet,tcount-total_read); - nread = read_file(fnum,data,startpos,N,N,-1,False); + nread = read_file(fnum,data,startpos,N); if (nread <= 0) nread = 0; diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 3ececed393..e582ea735a 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -48,6 +48,8 @@ extern BOOL short_case_preserve; extern BOOL case_mangle; extern time_t smb_last_time; +extern int smb_read_error; + extern pstring user_socket_options; connection_struct Connections[MAX_CONNECTIONS]; @@ -1263,41 +1265,35 @@ int seek_file(int fnum,int pos) /**************************************************************************** read from a file ****************************************************************************/ -int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact) +int read_file(int fnum,char *data,int pos,int n) { - int ret=0; + int ret=0,readret; if (!Files[fnum].can_write) { - ret = read_predict(Files[fnum].fd, - pos, - data, - NULL, - maxcnt); + ret = read_predict(Files[fnum].fd,pos,data,NULL,n); data += ret; - maxcnt -= ret; - mincnt = MAX(mincnt-ret,0); + n -= ret; pos += ret; } #if USE_MMAP if (Files[fnum].mmap_ptr) { - int num = MIN(maxcnt,Files[fnum].mmap_size-pos); + int num = MIN(n,Files[fnum].mmap_size-pos); if (num > 0) { memcpy(data,Files[fnum].mmap_ptr+pos,num); data += num; pos += num; - maxcnt -= num; - mincnt = MAX(mincnt-num,0); + n -= num; ret += num; } } #endif - if (maxcnt <= 0) + if (n <= 0) return(ret); if (seek_file(fnum,pos) != pos) @@ -1306,13 +1302,10 @@ int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL return(ret); } - if (maxcnt > 0) - ret += read_with_timeout(Files[fnum].fd, - data, - mincnt, - maxcnt, - timeout, - exact); + if (n > 0) { + readret = read(Files[fnum].fd,data,n); + if (readret > 0) ret += readret; + } return(ret); } @@ -3437,9 +3430,14 @@ static void process(void) BOOL allidle = True; extern int keepalive; - /* check for socket failure */ - if (errno) { - DEBUG(3,("receive_smb error (%s) exiting\n",strerror(errno))); + if (smb_read_error == READ_EOF) { + DEBUG(3,("end of file from client\n")); + return; + } + + if (smb_read_error == READ_ERROR) { + DEBUG(3,("receive_smb error (%s) exiting\n", + strerror(errno))); return; } -- cgit