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:
parent
a7ed8cd8ac
commit
2b4b7b4e1a
@ -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)));
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user