summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>1998-12-29 00:03:38 +0000
committerJeremy Allison <jra@samba.org>1998-12-29 00:03:38 +0000
commit18697e90d06518a9a5fd6cf47b59d2e3b7eca0ff (patch)
tree9397dde03ffbd7c57f1fedf38474e6e1afc2c232
parent80dfe5dcbc6f327be4ba1f2871ac84e282c9de9d (diff)
downloadsamba-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.h6
-rw-r--r--source/lib/signal.c40
-rw-r--r--source/lib/util.c6
-rw-r--r--source/smbd/chgpasswd.c14
-rw-r--r--source/smbd/close.c17
-rw-r--r--source/smbd/fileio.c12
-rw-r--r--source/smbd/open.c57
-rw-r--r--source/smbd/reply.c70
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