From 50e78a9ac8cf0949c2471fafde844c674f97d73d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 13 Apr 2001 00:37:00 +0000 Subject: As Andrew suggested, make smbrun return a fd for a deleted file which can then be read. Jeremy. (This used to be commit e7d59d6de89a5fdd201e4b5c6072dab08b1519db) --- source3/lib/smbrun.c | 116 ++++++++++++++++++++++-------------------------- source3/lib/util.c | 5 ++- source3/lib/util_file.c | 52 +++++++++++++++++----- 3 files changed, 96 insertions(+), 77 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c index e039f222fc..a543ff5eee 100644 --- a/source3/lib/smbrun.c +++ b/source3/lib/smbrun.c @@ -27,54 +27,41 @@ struct current_user current_user; extern int DEBUGLEVEL; /**************************************************************************** -This is a utility function of smbrun(). It must be called only from -the child as it may leave the caller in a privileged state. +This is a utility function of smbrun(). ****************************************************************************/ -static BOOL setup_stdout_file(char *outfile,BOOL shared) -{ - int fd; - mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH; - int flags = O_RDWR|O_CREAT|O_EXCL; - close(1); +static BOOL setup_out_fd(char *template) +{ + int fd; + pstring path; - if (shared) { - /* become root - unprivileged users can't delete these files */ - gain_root_privilege(); - gain_root_group_privilege(); - } + pstrcpy( path, template); + pstrcat( path, generate_random_str(17)); + pstrcat( path, ".XXXXXX"); - unlink(outfile); + /* now create the file */ + fd = smb_mkstemp(path); - /* now create the file */ - fd = sys_open(outfile,flags,mode); + if (fd == -1) { + DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n", + path, strerror(errno) )); + return -1; + } - if (fd == -1) return False; + DEBUG(10,("setup_out_fd: Created tmp file %s\n", path )); - if (fd != 1) { - if (dup2(fd,1) != 1) { - DEBUG(2,("Failed to create stdout file descriptor\n")); - close(fd); - return False; - } - close(fd); - } - return True; + /* Ensure file only kept around by open fd. */ + unlink(path); + return fd; } - /**************************************************************************** run a command being careful about uid/gid handling and putting the output in -outfile (or discard it if outfile is NULL). - -if shared is True then ensure the file will be writeable by all users -but created such that its owned by root. This overcomes a security hole. - -if shared is not set then open the file with O_EXCL set +outfd (or discard it if outfd is NULL). ****************************************************************************/ -int smbrun(char *cmd,char *outfile,BOOL shared) + +int smbrun(char *cmd, int *outfd, char *template) { - int fd; pid_t pid; uid_t uid = current_user.uid; gid_t gid = current_user.gid; @@ -84,32 +71,13 @@ int smbrun(char *cmd,char *outfile,BOOL shared) */ oplock_set_capability(False, False); -#ifndef HAVE_EXECL - { - int ret; - pstring syscmd; - char *path = lp_smbrun(); - - /* in the old method we use system() to execute smbrun which then - executes the command (using system() again!). This involves lots - of shell launches and is very slow. It also suffers from a - potential security hole */ - if (!file_exist(path,NULL)) { - DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path)); - return(1); - } + /* point our stdout at the file we want output to go into */ - slprintf(syscmd,sizeof(syscmd)-1,"%s %d %d \"(%s 2>&1) > %s\"", - path,(int)uid,(int)gid,cmd, - outfile?outfile:"/dev/null"); - - DEBUG(5,("smbrun - running %s ",syscmd)); - ret = system(syscmd); - DEBUG(5,("gave %d\n",ret)); - return(ret); + if (outfd && ((*outfd = setup_out_fd(template)) == -1)) { + return -1; } -#else - /* in this newer method we will exec /bin/sh with the correct + + /* in this method we will exec /bin/sh with the correct arguments, after first setting stdout to point at the file */ /* @@ -122,6 +90,10 @@ int smbrun(char *cmd,char *outfile,BOOL shared) if ((pid=sys_fork()) < 0) { DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) )); CatchChild(); + if (outfd) { + close(*outfd); + *outfd = -1; + } return errno; } @@ -146,13 +118,24 @@ int smbrun(char *cmd,char *outfile,BOOL shared) if (wpid != pid) { DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno))); + if (outfd) { + close(*outfd); + *outfd = -1; + } return -1; } + + /* Reset the seek pointer. */ + if (outfd) { + sys_lseek(*outfd, 0, SEEK_SET); + } + #if defined(WIFEXITED) && defined(WEXITSTATUS) if (WIFEXITED(status)) { return WEXITSTATUS(status); } #endif + return status; } @@ -163,10 +146,15 @@ int smbrun(char *cmd,char *outfile,BOOL shared) pipeline or anything else the config file specifies */ /* point our stdout at the file we want output to go into */ - if (outfile && !setup_stdout_file(outfile,shared)) { - exit(80); + if (outfd) { + close(1); + if (dup2(*outfd,1) != 1) { + DEBUG(2,("Failed to create stdout file descriptor\n")); + close(*outfd); + exit(80); + } } - + /* now completely lose our privileges. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ @@ -183,13 +171,15 @@ int smbrun(char *cmd,char *outfile,BOOL shared) #ifndef __INSURE__ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and 2 point to /dev/null from the startup code */ + { + int fd; for (fd=3;fd<256;fd++) close(fd); + } #endif execl("/bin/sh","sh","-c",cmd,NULL); /* not reached */ exit(82); -#endif return 1; } diff --git a/source3/lib/util.c b/source3/lib/util.c index 42a9617077..506a0334d1 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -1752,8 +1752,9 @@ int smb_mkstemp(char *template) #else /* have a reasonable go at emulating it. Hope that the system mktemp() isn't completly hopeless */ - if (!mktemp(template)) return -1; - return open(template, O_CREAT|O_EXCL|O_RDWR, 0600); + char *p = smbd_mktemp(template); + if (!p) return -1; + return open(p, O_CREAT|O_EXCL|O_RDWR, 0600); #endif } diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c index 023f3e131c..4e2adc97bc 100644 --- a/source3/lib/util_file.c +++ b/source3/lib/util_file.c @@ -368,21 +368,15 @@ char *file_pload(char *syscmd, size_t *size) return p; } - /**************************************************************************** -load a file into memory -****************************************************************************/ -char *file_load(char *fname, size_t *size) +load a file into memory from a fd. +****************************************************************************/ + +char *fd_load(int fd, size_t *size) { - int fd; SMB_STRUCT_STAT sbuf; char *p; - if (!fname || !*fname) return NULL; - - fd = open(fname,O_RDONLY); - if (fd == -1) return NULL; - if (sys_fstat(fd, &sbuf) != 0) return NULL; p = (char *)malloc(sbuf.st_size+1); @@ -394,13 +388,31 @@ char *file_load(char *fname, size_t *size) } p[sbuf.st_size] = 0; - close(fd); - if (size) *size = sbuf.st_size; return p; } +/**************************************************************************** +load a file into memory +****************************************************************************/ +char *file_load(char *fname, size_t *size) +{ + int fd; + char *p; + + if (!fname || !*fname) return NULL; + + fd = open(fname,O_RDONLY); + if (fd == -1) return NULL; + + p = fd_load(fd, size); + + close(fd); + + return p; +} + /**************************************************************************** parse a buffer into lines @@ -459,6 +471,22 @@ char **file_lines_load(char *fname, int *numlines, BOOL convert) return file_lines_parse(p, size, numlines, convert); } +/**************************************************************************** +load a fd into memory and return an array of pointers to lines in the file +must be freed with file_lines_free(). If convert is true calls unix_to_dos on +the list. +****************************************************************************/ +char **fd_lines_load(int fd, int *numlines, BOOL convert) +{ + char *p; + size_t size; + + p = fd_load(fd, &size); + if (!p) return NULL; + + return file_lines_parse(p, size, numlines, convert); +} + /**************************************************************************** load a pipe into memory and return an array of pointers to lines in the data -- cgit