diff options
author | Jeremy Allison <jra@samba.org> | 1998-12-29 00:03:38 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 1998-12-29 00:03:38 +0000 |
commit | 18697e90d06518a9a5fd6cf47b59d2e3b7eca0ff (patch) | |
tree | 9397dde03ffbd7c57f1fedf38474e6e1afc2c232 | |
parent | 80dfe5dcbc6f327be4ba1f2871ac84e282c9de9d (diff) | |
download | samba-18697e90d06518a9a5fd6cf47b59d2e3b7eca0ff.tar.gz samba-18697e90d06518a9a5fd6cf47b59d2e3b7eca0ff.tar.xz samba-18697e90d06518a9a5fd6cf47b59d2e3b7eca0ff.zip |
lib/signal.c: Added CatchChildLeaveStatus() call needed in smbd/open.c and smbd/chgpasswd.c.
smbd/chgpasswd.c
smbd/open.c: Ensure that we replace SIGCLD handler with CatchChildLeaveStatus()
*before* we expect to reap a child status - and reset it to CatchChild()
after we've done the sys_waitpid(). The original CatchChild() code
would eat the status code from the zombie in the signal handler, meaning
that the sys_waitpid() calls in check_access_allowed_for_current_user()
and chgpasswd would never return a status.
smbd/open.c:
smbd/reply.c:
smbd/close.c: Check error return on close() calls - ensure a valid error return
is sent back to the client. This catches the "file truncated"
bug when a user has run out of quota (or space) and the ENOSPC
error is returned on the *close()* call, not the write() (eg. on
an nfs mounted drive).
smbd/fileio.c: Added check for ESPIPE on sys_lseek() in file_seek() to allow
people to use Windows clients to communicate with UNIX fifo's
(like they could in 1.9.18).
Jeremy.
-rw-r--r-- | source/include/proto.h | 6 | ||||
-rw-r--r-- | source/lib/signal.c | 40 | ||||
-rw-r--r-- | source/lib/util.c | 6 | ||||
-rw-r--r-- | source/smbd/chgpasswd.c | 14 | ||||
-rw-r--r-- | source/smbd/close.c | 17 | ||||
-rw-r--r-- | source/smbd/fileio.c | 12 | ||||
-rw-r--r-- | source/smbd/open.c | 57 | ||||
-rw-r--r-- | source/smbd/reply.c | 70 |
8 files changed, 172 insertions, 50 deletions
diff --git a/source/include/proto.h b/source/include/proto.h index dc5763198f0..1f4f522ac77 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -148,6 +148,7 @@ char *rep_inet_ntoa(struct in_addr ip); void BlockSignals(BOOL block,int signum); void CatchSignal(int signum,void (*handler)(int )); void CatchChild(void); +void CatchChildLeaveStatus(void); /*The following definitions come from lib/slprintf.c */ @@ -316,6 +317,7 @@ void gain_root_privilege(void); void gain_root_group_privilege(void); int set_effective_uid(uid_t uid); int set_effective_gid(gid_t gid); +int set_real_uid(uid_t uid); BOOL become_user_permanently(uid_t uid, gid_t gid); /*The following definitions come from lib/util_sid.c */ @@ -2280,7 +2282,7 @@ BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL overri /*The following definitions come from smbd/close.c */ -void close_file(files_struct *fsp, BOOL normal_close); +int close_file(files_struct *fsp, BOOL normal_close); void close_directory(files_struct *fsp); /*The following definitions come from smbd/conn.c */ @@ -2432,7 +2434,7 @@ int reply_nttrans(connection_struct *conn, /*The following definitions come from smbd/open.c */ void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u); -uint16 fd_attempt_close(file_fd_struct *fd_ptr); +uint16 fd_attempt_close(file_fd_struct *fd_ptr, int *err_ret); void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int share_mode,int ofun, mode_t mode,int oplock_request, int *Access,int *action); int open_directory(files_struct *fsp,connection_struct *conn, diff --git a/source/lib/signal.c b/source/lib/signal.c index bb1c6fe189b..1d2e1e8d166 100644 --- a/source/lib/signal.c +++ b/source/lib/signal.c @@ -22,22 +22,31 @@ #include "includes.h" - /**************************************************************************** -catch child exits + Catch child exits and reap the child zombie status. ****************************************************************************/ + static void sig_cld(int signum) { - while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0) ; + while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0) + ; CatchSignal(SIGCLD, sig_cld); } +/**************************************************************************** +catch child exits - leave status; +****************************************************************************/ +static void sig_cld_leave_status(int signum) +{ + CatchSignal(SIGCLD, sig_cld_leave_status); +} /******************************************************************* -block sigs + Block sigs. ********************************************************************/ + void BlockSignals(BOOL block,int signum) { #ifdef HAVE_SIGPROCMASK @@ -63,14 +72,13 @@ void BlockSignals(BOOL block,int signum) #endif } - - /******************************************************************* -catch a signal. This should implement the following semantics: + Catch a signal. This should implement the following semantics: -1) the handler remains installed after being called -2) the signal should be blocked during handler execution + 1) The handler remains installed after being called. + 2) The signal should be blocked during handler execution. ********************************************************************/ + void CatchSignal(int signum,void (*handler)(int )) { #ifdef HAVE_SIGACTION @@ -91,12 +99,20 @@ void CatchSignal(int signum,void (*handler)(int )) #endif } - - /******************************************************************* -ignore SIGCLD via whatever means is necessary for this OS + Ignore SIGCLD via whatever means is necessary for this OS. ********************************************************************/ + void CatchChild(void) { CatchSignal(SIGCLD, sig_cld); } + +/******************************************************************* + Catch SIGCLD but leave the child around so it's status can be reaped. +********************************************************************/ + +void CatchChildLeaveStatus(void) +{ + CatchSignal(SIGCLD, sig_cld_leave_status); +} diff --git a/source/lib/util.c b/source/lib/util.c index d760e61fd00..3813e7859d8 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -1572,12 +1572,11 @@ BOOL yesno(char *p) return(False); } - - /**************************************************************************** set the length of a file from a filedescriptor. Returns 0 on success, -1 on failure. ****************************************************************************/ + int set_filelen(int fd, SMB_OFF_T len) { /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot @@ -1601,7 +1600,8 @@ int set_filelen(int fd, SMB_OFF_T len) return -1; #ifdef S_ISFIFO - if (S_ISFIFO(st.st_mode)) return 0; + if (S_ISFIFO(st.st_mode)) + return 0; #endif if(st.st_size == len) diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c index 4a12da8fc7c..ebbc79c4a10 100644 --- a/source/smbd/chgpasswd.c +++ b/source/smbd/chgpasswd.c @@ -297,9 +297,17 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc return(False); } + /* + * We need to temporarily stop CatchChild from eating + * SIGCLD signals as it also eats the exit status code. JRA. + */ + + CatchChildLeaveStatus(); + if ((pid = fork()) < 0) { DEBUG(3,("Cannot fork() child for password change: %s\n",name)); close(master); + CatchChild(); return(False); } @@ -313,9 +321,15 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { DEBUG(3,("The process is no longer waiting!\n\n")); close(master); + CatchChild(); return(False); } + /* + * Go back to ignoring children. + */ + CatchChild(); + close(master); if (pid != wpid) { diff --git a/source/smbd/close.c b/source/smbd/close.c index 0d133f06667..708571bae6b 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -94,14 +94,16 @@ static void close_filestruct(files_struct *fsp) the closing of the connection. In the latter case printing and magic scripts are not run. ****************************************************************************/ -void close_file(files_struct *fsp, BOOL normal_close) + +int close_file(files_struct *fsp, BOOL normal_close) { SMB_DEV_T dev = fsp->fd_ptr->dev; SMB_INO_T inode = fsp->fd_ptr->inode; int token; - BOOL last_reference = False; - BOOL delete_on_close = fsp->fd_ptr->delete_on_close; + BOOL last_reference = False; + BOOL delete_on_close = fsp->fd_ptr->delete_on_close; connection_struct *conn = fsp->conn; + int err = 0; remove_pending_lock_requests_by_fid(fsp); @@ -119,7 +121,7 @@ void close_file(files_struct *fsp, BOOL normal_close) if(fsp->granted_oplock == True) release_file_oplock(fsp); - if(fd_attempt_close(fsp->fd_ptr) == 0) + if(fd_attempt_close(fsp->fd_ptr,&err) == 0) last_reference = True; fsp->fd_ptr = NULL; @@ -158,15 +160,17 @@ with error %s\n", fsp->fsp_name, strerror(errno) )); } } - DEBUG(2,("%s closed file %s (numopen=%d)\n", + DEBUG(2,("%s closed file %s (numopen=%d) %s\n", conn->user,fsp->fsp_name, - conn->num_files_open)); + conn->num_files_open, err ? strerror(err) : "")); if (fsp->fsp_name) { string_free(&fsp->fsp_name); } file_free(fsp); + + return err; } /**************************************************************************** @@ -187,4 +191,3 @@ void close_directory(files_struct *fsp) file_free(fsp); } - diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index c7ffb6412dd..d067db4fa47 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -38,6 +38,18 @@ SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos) seek_ret = sys_lseek(fsp->fd_ptr->fd,pos+offset,SEEK_SET); + /* + * We want to maintain the fiction that we can seek + * on a fifo for file system purposes. This allows + * people to set up UNIX fifo's that feed data to Windows + * applications. JRA. + */ + + if((seek_ret == -1) && (errno == ESPIPE)) { + seek_ret = pos+offset; + errno = 0; + } + if((seek_ret == -1) || (seek_ret != pos+offset)) { DEBUG(0,("seek_file: sys_lseek failed. Error was %s\n", strerror(errno) )); fsp->pos = -1; diff --git a/source/smbd/open.c b/source/smbd/open.c index 6658b8926f8..9e662e9f805 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -144,11 +144,14 @@ static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr) fd support routines - attempt to close the file referenced by this fd. Decrements the ref_count and returns it. ****************************************************************************/ -uint16 fd_attempt_close(file_fd_struct *fd_ptr) + +uint16 fd_attempt_close(file_fd_struct *fd_ptr, int *err_ret) { extern struct current_user current_user; uint16 ret_ref = fd_ptr->ref_count; + *err_ret = 0; + DEBUG(3,("fd_attempt_close fd = %d, dev = %x, inode = %.0f, open_flags = %d, ref_count = %d.\n", fd_ptr->fd, (unsigned int)fd_ptr->dev, (double)fd_ptr->inode, fd_ptr->real_open_flags, @@ -160,12 +163,26 @@ uint16 fd_attempt_close(file_fd_struct *fd_ptr) ret_ref = fd_ptr->ref_count; if(fd_ptr->ref_count == 0) { - if(fd_ptr->fd != -1) - close(fd_ptr->fd); - if(fd_ptr->fd_readonly != -1) - close(fd_ptr->fd_readonly); - if(fd_ptr->fd_writeonly != -1) - close(fd_ptr->fd_writeonly); + + if(fd_ptr->fd != -1) { + if(close(fd_ptr->fd) < 0) + *err_ret = errno; + } + + if(fd_ptr->fd_readonly != -1) { + if(close(fd_ptr->fd_readonly) < 0) { + if(*err_ret == 0) + *err_ret = errno; + } + } + + if(fd_ptr->fd_writeonly != -1) { + if( close(fd_ptr->fd_writeonly) < 0) { + if(*err_ret == 0) + *err_ret = errno; + } + } + /* * Delete this fd_ptr. */ @@ -174,7 +191,7 @@ uint16 fd_attempt_close(file_fd_struct *fd_ptr) fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid); } - return ret_ref; + return ret_ref; } /**************************************************************************** @@ -184,12 +201,21 @@ This is really ugly code, as due to POSIX locking braindamage we must fork and then attempt to open the file, and return success or failure via an exit code. ****************************************************************************/ + static BOOL check_access_allowed_for_current_user( char *fname, int accmode ) { pid_t child_pid; + /* + * We need to temporarily stop CatchChild from eating + * SIGCLD signals as it also eats the exit status code. JRA. + */ + + CatchChildLeaveStatus(); + if((child_pid = fork()) < 0) { DEBUG(0,("check_access_allowed_for_current_user: fork failed.\n")); + CatchChild(); return False; } @@ -201,9 +227,15 @@ static BOOL check_access_allowed_for_current_user( char *fname, int accmode ) int status_code; if ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) { DEBUG(0,("check_access_allowed_for_current_user: The process is no longer waiting!\n")); + CatchChild(); return(False); } + /* + * Go back to ignoring children. + */ + CatchChild(); + if (child_pid != wpid) { DEBUG(0,("check_access_allowed_for_current_user: We were waiting for the wrong process ID\n")); return(False); @@ -449,7 +481,8 @@ static void open_file(files_struct *fsp,connection_struct *conn, p = strrchr(dname,'/'); if (p) *p = 0; if (sys_disk_free(dname,&dum1,&dum2,&dum3) < (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) { - if(fd_attempt_close(fd_ptr) == 0) + int err; + if(fd_attempt_close(fd_ptr, &err) == 0) dos_unlink(fname); fsp->fd_ptr = 0; errno = ENOSPC; @@ -459,10 +492,11 @@ static void open_file(files_struct *fsp,connection_struct *conn, if (fd_ptr->fd < 0) { + int err; DEBUG(3,("Error opening file %s (%s) (flags=%d)\n", fname,strerror(errno),flags)); /* Ensure the ref_count is decremented. */ - fd_attempt_close(fd_ptr); + fd_attempt_close(fd_ptr,&err); check_for_pipe(fname); return; } @@ -472,11 +506,12 @@ static void open_file(files_struct *fsp,connection_struct *conn, if(sbuf == 0) { /* Do the fstat */ if(sys_fstat(fd_ptr->fd, &statbuf) == -1) { + int err; /* Error - backout !! */ DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n", fd_ptr->fd, fname,strerror(errno))); /* Ensure the ref_count is decremented. */ - fd_attempt_close(fd_ptr); + fd_attempt_close(fd_ptr,&err); return; } sbuf = &statbuf; diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 38c4afa06fe..49982badedd 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -2610,6 +2610,7 @@ int reply_close(connection_struct *conn, /* * Close ordinary file. */ + int close_err; /* * If there was a modify time outstanding, @@ -2629,8 +2630,17 @@ int reply_close(connection_struct *conn, DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n", fsp->fd_ptr->fd, fsp->fnum, conn->num_files_open)); - - close_file(fsp,True); + + /* + * close_file() returns the unix errno if an error + * was detected on close - normally this is due to + * a disk full error. If not then it was probably an I/O error. + */ + + if((close_err = close_file(fsp,True)) != 0) { + errno = close_err; + return (UNIXERROR(ERRHRD,ERRgeneral)); + } } /* We have a cached error */ @@ -2650,6 +2660,7 @@ int reply_writeclose(connection_struct *conn, size_t numtowrite; ssize_t nwritten = -1; int outsize = 0; + int close_err = 0; SMB_OFF_T startpos; char *data; time_t mtime; @@ -2674,7 +2685,7 @@ int reply_writeclose(connection_struct *conn, set_filetime(conn, fsp->fsp_name,mtime); - close_file(fsp,True); + close_err = close_file(fsp,True); DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n", fsp->fnum, numtowrite, nwritten, @@ -2682,7 +2693,12 @@ int reply_writeclose(connection_struct *conn, if (nwritten <= 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); - + + if(close_err != 0) { + errno = close_err; + return(UNIXERROR(ERRHRD,ERRgeneral)); + } + outsize = set_message(outbuf,1,0,True); SSVAL(outbuf,smb_vwv0,nwritten); @@ -2887,6 +2903,7 @@ int reply_printclose(connection_struct *conn, { int outsize = set_message(outbuf,0,0,True); files_struct *fsp = file_fsp(inbuf,smb_vwv0); + int close_err = 0; CHECK_FSP(fsp,conn); CHECK_ERROR(fsp); @@ -2897,7 +2914,12 @@ int reply_printclose(connection_struct *conn, DEBUG(3,("printclose fd=%d fnum=%d\n", fsp->fd_ptr->fd,fsp->fnum)); - close_file(fsp,True); + close_err = close_file(fsp,True); + + if(close_err != 0) { + errno = close_err; + return(UNIXERROR(ERRHRD,ERRgeneral)); + } return(outsize); } @@ -3507,7 +3529,7 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, in ******************************************************************/ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, - int count,BOOL target_is_directory) + int count,BOOL target_is_directory, int *err_ret) { int Access,action; SMB_STRUCT_STAT st; @@ -3515,6 +3537,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, files_struct *fsp1,*fsp2; pstring dest; + *err_ret = 0; + pstrcpy(dest,dest1); if (target_is_directory) { char *p = strrchr(src,'/'); @@ -3575,7 +3599,13 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, fsp2->fd_ptr->fd,st.st_size,NULL,0,0); close_file(fsp1,False); - close_file(fsp2,False); + /* + * As we are opening fsp1 read-only we only expect + * an error on close on fsp2 if we are out of space. + * Thus we don't look at the error return from the + * close of fsp1. + */ + *err_ret = close_file(fsp2,False); return(ret == st.st_size); } @@ -3594,6 +3624,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, char *p; int count=0; int error = ERRnoaccess; + int err = 0; BOOL has_wild; BOOL exists=False; int tid2 = SVAL(inbuf,smb_vwv0); @@ -3655,7 +3686,11 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstrcat(directory,mask); if (resolve_wildcards(directory,newname) && copy_file(directory,newname,conn,ofun, - count,target_is_directory)) count++; + count,target_is_directory,&err)) count++; + if(!count && err) { + errno = err; + return(UNIXERROR(ERRHRD,ERRgeneral)); + } if (!count) exists = dos_file_exist(directory,NULL); } else { void *dirptr = NULL; @@ -3665,33 +3700,38 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (check_name(directory,conn)) dirptr = OpenDir(conn, directory, True); - if (dirptr) - { + if (dirptr) { error = ERRbadfile; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); - while ((dname = ReadDirName(dirptr))) - { + while ((dname = ReadDirName(dirptr))) { pstring fname; pstrcpy(fname,dname); - if(!mask_match(fname, mask, case_sensitive, False)) continue; + if(!mask_match(fname, mask, case_sensitive, False)) + continue; error = ERRnoaccess; slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); pstrcpy(destname,newname); if (resolve_wildcards(fname,destname) && copy_file(directory,newname,conn,ofun, - count,target_is_directory)) count++; + count,target_is_directory,&err)) count++; DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname)); } CloseDir(dirptr); - } + } } if (count == 0) { + if(err) { + /* Error on close... */ + errno = err; + return(UNIXERROR(ERRHRD,ERRgeneral)); + } + if (exists) return(ERROR(ERRDOS,error)); else |