1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-08 21:18:16 +03:00

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 a7c7d7afe2)
This commit is contained in:
Andrew Tridgell 1996-07-30 15:47:30 +00:00
parent a7ed8cd8ac
commit 2b4b7b4e1a
7 changed files with 81 additions and 173 deletions

View File

@ -768,7 +768,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
memcpy(p,status,21); memcpy(p,status,21);
send_smb(Client,outbuf); send_smb(Client,outbuf);
receive_smb(Client,inbuf,CLIENT_TIMEOUT,False); receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0) if (CVAL(inbuf,smb_rcls) != 0)
DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf))); DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));

View File

@ -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, void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
int mode,int *Access,int *action); int mode,int *Access,int *action);
int seek_file(int fnum,int pos); 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); int write_file(int fnum,char *data,int n);
BOOL become_service(int cnum,BOOL do_chdir); BOOL become_service(int cnum,BOOL do_chdir);
int find_service(char *service); 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); void close_low_fds(void);
int write_socket(int fd,char *buf,int len); int write_socket(int fd,char *buf,int len);
int read_udp_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);
int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact);
int read_max_udp(int fd,char *buffer,int bufsize,int maxtime); int read_max_udp(int fd,char *buffer,int bufsize,int maxtime);
int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew); int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew);
BOOL send_keepalive(int client); BOOL send_keepalive(int client);

View File

@ -111,11 +111,10 @@ EXTERN int syslog_level;
#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? (syslog_level = (level), Debug1 body):0) #define DEBUG(level,body) ((DEBUGLEVEL>=(level))? (syslog_level = (level), Debug1 body):0)
#endif #endif
/* this defines the error codes that receive_smb can put in smberrcode */ /* this defines the error codes that receive_smb can put in smb_read_error */
#define SMBERR_OK 0 #define READ_TIMEOUT 1
#define SMBERR_TIMEOUT 1 #define READ_EOF 2
#define SMBERR_EOF 2 #define READ_ERROR 3
#define SMBERR_ERROR 3
#define DIR_STRUCT_SIZE 43 #define DIR_STRUCT_SIZE 43

View File

@ -75,6 +75,8 @@ pstring user_socket_options="";
pstring sesssetup_user=""; pstring sesssetup_user="";
int smb_read_error = 0;
static char *filename_dos(char *path,char *buf); static char *filename_dos(char *path,char *buf);
static BOOL stdout_logging = False; static BOOL stdout_logging = False;
@ -1691,103 +1693,44 @@ int read_udp_socket(int fd,char *buf,int len)
return(ret); 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. read data from a device with a timout in msec.
mincount = if timeout, minimum to read before returning mincount = if timeout, minimum to read before returning
maxcount = number to be read. 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; fd_set fds;
int selrtn; int selrtn;
int readret; int readret;
int nread = 0; int nread = 0;
struct timeval timeout, tval1, tval2, tvaldiff; struct timeval timeout;
int error_limit = 5;
/* just checking .... */ /* just checking .... */
if (maxcnt <= 0) return(0); if (maxcnt <= 0) return(0);
if(time_out == -2) smb_read_error = 0;
time_out = DEFAULT_PIPE_TIMEOUT;
/* Blocking read */ /* Blocking read */
if(time_out < 0) { if (time_out <= 0) {
if (mincnt == 0) mincnt = maxcnt; if (mincnt == 0) mincnt = maxcnt;
while (nread < mincnt) while (nread < mincnt) {
{ readret = read(fd, buf + nread, maxcnt - nread);
readret = read(fd, buf + nread, maxcnt - nread); if (readret == 0) {
if (readret <= 0) return(nread); smb_read_error = READ_EOF;
nread += readret; return -1;
} }
if (readret == -1) {
smb_read_error = READ_ERROR;
return -1;
}
nread += readret;
}
return(nread); 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 */ /* Most difficult - timeout read */
/* If this is ever called on a disk file and /* If this is ever called on a disk file and
mincnt is greater then the filesize then 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_sec = time_out / 1000;
timeout.tv_usec = 1000 * (time_out % 1000); timeout.tv_usec = 1000 * (time_out % 1000);
/* As most UNIXes don't modify the value of timeout for (nread=0; nread<mincnt; )
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(;;)
{ {
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(fd,&fds); FD_SET(fd,&fds);
selrtn = sys_select(&fds,&timeout); selrtn = sys_select(&fds,&timeout);
/* Check if error */ /* Check if error */
if(selrtn == -1) { if(selrtn == -1) {
/* something is wrong. Maybe the socket is dead? */
smb_read_error = READ_ERROR;
return -1; return -1;
} }
/* Did we timeout ? */ /* Did we timeout ? */
if (selrtn == 0) { if (selrtn == 0) {
if (nread < mincnt) return -1; smb_read_error = READ_TIMEOUT;
break; /* Yes */ return -1;
} }
readret = read(fd, buf+nread, maxcnt-nread); readret = read(fd, buf+nread, maxcnt-nread);
if (readret == 0 && nread < mincnt) { if (readret == 0) {
/* error_limit should not really be needed, but some systems /* we got EOF on the file descriptor */
do strange things ... I don't want to just continue smb_read_error = READ_EOF;
indefinately in case we get an infinite loop */ return -1;
if (error_limit--) continue;
return(-1);
} }
if (readret < 0) { if (readret == -1) {
/* force a particular error number for /* the descriptor is probably dead */
portability */ smb_read_error = READ_ERROR;
DEBUG(5,("read gave error %s\n",strerror(errno)));
return -1; return -1;
} }
nread += readret; nread += readret;
/* If we have read more than mincnt then return */
if (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 */ /* Return the number we got */
@ -1927,12 +1841,19 @@ int read_data(int fd,char *buffer,int N)
int ret; int ret;
int total=0; int total=0;
smb_read_error = 0;
while (total < N) while (total < N)
{ {
ret = read(fd,buffer + total,N - total); ret = read(fd,buffer + total,N - total);
if (ret == 0) {
if (ret <= 0) smb_read_error = READ_EOF;
return total; return 0;
}
if (ret == -1) {
smb_read_error = READ_ERROR;
return -1;
}
total += ret; total += ret;
} }
return total; return total;
@ -2056,23 +1977,12 @@ int read_smb_length(int fd,char *inbuf,int timeout)
while (!ok) while (!ok)
{ {
if (timeout > 0) if (timeout > 0)
ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4);
else else
ok = (read_data(fd,buffer,4) == 4); ok = (read_data(fd,buffer,4) == 4);
if (!ok) if (!ok)
{ return(-1);
if (timeout>0)
{
DEBUG(10,("select timeout (%d)\n", timeout));
return(-1);
}
else
{
DEBUG(6,("couldn't read from client\n"));
exit(1);
}
}
len = smb_len(buffer); len = smb_len(buffer);
msg_type = CVAL(buffer,0); msg_type = CVAL(buffer,0);
@ -2099,6 +2009,8 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
{ {
int len,ret; int len,ret;
smb_read_error = 0;
bzero(buffer,smb_size + 100); bzero(buffer,smb_size + 100);
len = read_smb_length(fd,buffer,timeout); 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); ret = read_data(fd,buffer+4,len);
if (ret != len) { if (ret != len) {
DEBUG(0,("ERROR: Invalid SMB length. Expected %d got %d\n",len,ret)); smb_read_error = READ_ERROR;
return False; return False;
} }

View File

@ -178,7 +178,7 @@ static int expect(int master,char *expected,char *buf)
} }
/* allow 4 seconds for some output to appear */ /* 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) if (m < 0)
return False; return False;

View File

@ -1363,7 +1363,7 @@ int reply_readbraw(char *inbuf, char *outbuf)
fname,startpos,nread,ret)); fname,startpos,nread,ret));
#else #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; if (ret < mincount) ret = 0;
_smb_setlen(header,ret); _smb_setlen(header,ret);
@ -1405,7 +1405,7 @@ int reply_lockread(char *inbuf,char *outbuf)
if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode)) if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
return (ERROR(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) if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess)); return(UNIXERROR(ERRDOS,ERRnoaccess));
@ -1450,7 +1450,7 @@ int reply_read(char *inbuf,char *outbuf)
return(ERROR(ERRDOS,ERRlock)); return(ERROR(ERRDOS,ERRlock));
if (numtoread > 0) if (numtoread > 0)
nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False); nread = read_file(fnum,data,startpos,numtoread);
if (nread < 0) if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess)); 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)) if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
return(ERROR(ERRDOS,ERRlock)); 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; ok = True;
if (nread < 0) 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); 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; if (nread <= 0) nread = 0;

View File

@ -48,6 +48,8 @@ extern BOOL short_case_preserve;
extern BOOL case_mangle; extern BOOL case_mangle;
extern time_t smb_last_time; extern time_t smb_last_time;
extern int smb_read_error;
extern pstring user_socket_options; extern pstring user_socket_options;
connection_struct Connections[MAX_CONNECTIONS]; connection_struct Connections[MAX_CONNECTIONS];
@ -1263,41 +1265,35 @@ int seek_file(int fnum,int pos)
/**************************************************************************** /****************************************************************************
read from a file 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) if (!Files[fnum].can_write)
{ {
ret = read_predict(Files[fnum].fd, ret = read_predict(Files[fnum].fd,pos,data,NULL,n);
pos,
data,
NULL,
maxcnt);
data += ret; data += ret;
maxcnt -= ret; n -= ret;
mincnt = MAX(mincnt-ret,0);
pos += ret; pos += ret;
} }
#if USE_MMAP #if USE_MMAP
if (Files[fnum].mmap_ptr) 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) if (num > 0)
{ {
memcpy(data,Files[fnum].mmap_ptr+pos,num); memcpy(data,Files[fnum].mmap_ptr+pos,num);
data += num; data += num;
pos += num; pos += num;
maxcnt -= num; n -= num;
mincnt = MAX(mincnt-num,0);
ret += num; ret += num;
} }
} }
#endif #endif
if (maxcnt <= 0) if (n <= 0)
return(ret); return(ret);
if (seek_file(fnum,pos) != pos) 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); return(ret);
} }
if (maxcnt > 0) if (n > 0) {
ret += read_with_timeout(Files[fnum].fd, readret = read(Files[fnum].fd,data,n);
data, if (readret > 0) ret += readret;
mincnt, }
maxcnt,
timeout,
exact);
return(ret); return(ret);
} }
@ -3437,9 +3430,14 @@ static void process(void)
BOOL allidle = True; BOOL allidle = True;
extern int keepalive; extern int keepalive;
/* check for socket failure */ if (smb_read_error == READ_EOF) {
if (errno) { DEBUG(3,("end of file from client\n"));
DEBUG(3,("receive_smb error (%s) exiting\n",strerror(errno))); return;
}
if (smb_read_error == READ_ERROR) {
DEBUG(3,("receive_smb error (%s) exiting\n",
strerror(errno)));
return; return;
} }