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);
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)));

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,
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);

View File

@ -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

View File

@ -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; )
{
FD_ZERO(&fds);
FD_SET(fd,&fds);
selrtn = sys_select(&fds,&timeout);
/* Check if error */
if(selrtn == -1) {
/* something is wrong. Maybe the socket is dead? */
smb_read_error = READ_ERROR;
return -1;
}
/* Did we timeout ? */
if (selrtn == 0) {
if (nread < mincnt) return -1;
break; /* Yes */
smb_read_error = READ_TIMEOUT;
return -1;
}
readret = read(fd, buf+nread, maxcnt-nread);
if (readret == 0 && nread < mincnt) {
/* error_limit should not really be needed, but some systems
do strange things ... I don't want to just continue
indefinately in case we get an infinite loop */
if (error_limit--) continue;
return(-1);
if (readret == 0) {
/* we got EOF on the file descriptor */
smb_read_error = READ_EOF;
return -1;
}
if (readret < 0) {
/* force a particular error number for
portability */
DEBUG(5,("read gave error %s\n",strerror(errno)));
if (readret == -1) {
/* the descriptor is probably dead */
smb_read_error = READ_ERROR;
return -1;
}
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 */
@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}