diff options
-rw-r--r-- | source3/include/proto.h | 4 | ||||
-rw-r--r-- | source3/locking/locking.c | 45 | ||||
-rw-r--r-- | source3/smbd/ipc.c | 4 | ||||
-rw-r--r-- | source3/smbd/pipes.c | 4 | ||||
-rw-r--r-- | source3/smbd/reply.c | 26 | ||||
-rw-r--r-- | source3/smbd/server.c | 16 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 4 | ||||
-rw-r--r-- | source3/smbd/uid.c | 74 |
8 files changed, 125 insertions, 52 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 70a9873d34..85ef094340 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -776,7 +776,7 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize); int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize); BOOL check_name(char *name,int cnum); void sync_file(int fnum); -void close_file(int fnum); +void close_file(int fnum, BOOL normal_close); BOOL check_file_sharing(int cnum,char *fname); int check_share_mode( min_share_mode_entry *share, int deny_mode, char *fname, BOOL fcbopen, int *flags); @@ -957,6 +957,8 @@ BOOL become_guest(void); BOOL become_user(int cnum, uint16 vuid); BOOL unbecome_user(void ); int smbrun(char *cmd,char *outfile,BOOL shared); +void become_root(BOOL save_dir) ; +void unbecome_root(BOOL restore_dir); /*The following definitions come from username.c */ diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 04c198afea..5071121bed 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -729,10 +729,12 @@ BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok if(!share_name(cnum, dev, inode, fname)) return False; + /* we need to do this as root */ + become_root(False); + { int old_umask; BOOL gotlock = False; - unbecome_user(); old_umask = umask(0); /* @@ -801,23 +803,13 @@ BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok */ umask(old_umask); - if(!become_user(cnum,Connections[cnum].vuid)) - { - DEBUG(0,("lock_share_entry: Can't become connected user!\n")); - close(fd); - ret = False; - } - /* We need to change directory back to the connection root. */ - if (ChDir(Connections[cnum].connectpath) != 0) - { - DEBUG(0,("lock_share_entry: Can't change directory to %s (%s)\n", - Connections[cnum].connectpath, strerror(errno))); - close(fd); - ret = False; - } } *ptok = (share_lock_token)fd; + + /* return to our previous privilage level */ + unbecome_root(False); + return ret; } @@ -848,27 +840,22 @@ Force a share file to be deleted. static int delete_share_file( int cnum, char *fname ) { - unbecome_user(); + /* the share file could be owned by anyone, so do this as root */ + become_root(False); + if(unlink(fname) != 0) { DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n", fname, strerror(errno))); + } + else + { + DEBUG(5,("delete_share_file: Deleted share file %s\n", fname)); } - DEBUG(5,("delete_share_file: Deleted share file %s\n", fname)); + /* return to our previous privilage level */ + unbecome_root(False); - if(!become_user(cnum,Connections[cnum].vuid)) - { - DEBUG(0,("delete_share_file: Can't become connected user!\n")); - return -1; - } - /* We need to change directory back to the connection root. */ - if (ChDir(Connections[cnum].connectpath) != 0) - { - DEBUG(0,("delete_share_file: Can't change directory to %s (%s)\n", - Connections[cnum].connectpath, strerror(errno))); - return -1; - } return 0; } diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index c29e8656b1..142f139d26 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -1602,6 +1602,8 @@ static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data, DEBUG(3,("Setting print name to %s\n",name)); + become_root(True); + for (i=0;i<MAX_OPEN_FILES;i++) if (Files[i].open && Files[i].print_file) { @@ -1617,6 +1619,8 @@ static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data, string_set(&Files[i].name,name); break; } + + unbecome_root(True); } desc.errcode=NERR_Success; diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index bf53fa84bc..8c7e6c69c5 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -147,7 +147,7 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize) } if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -155,7 +155,7 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize) fmode = dos_mode(cnum,fname,&sbuf); mtime = sbuf.st_mtime; if (fmode & aDIR) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index dffb6f05bd..56288df073 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -479,8 +479,8 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) /* computer with that name (minus the $) has access. For now */ /* say yes to everything ending in $. */ if (user[strlen(user) - 1] == '$') { - struct smb_passwd *smb_pass; /* To check if machine account exists */ #ifdef NTDOMAIN + struct smb_passwd *smb_pass; /* To check if machine account exists */ /* PAXX: Ack. We don't want to do this. The workstation trust account with a $ on the end should exist in the local password database @@ -1178,7 +1178,7 @@ int reply_open(char *inbuf,char *outbuf) } if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1188,7 +1188,7 @@ int reply_open(char *inbuf,char *outbuf) if (fmode & aDIR) { DEBUG(3,("attempt to open a directory %s\n",fname)); - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1274,7 +1274,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize) } if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1282,7 +1282,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize) fmode = dos_mode(cnum,fname,&sbuf); mtime = sbuf.st_mtime; if (fmode & aDIR) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1328,7 +1328,7 @@ int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize) int i; for (i=0;i<MAX_OPEN_FILES;i++) if (Files[i].uid == vuser->uid && Files[i].open) { - close_file(i); + close_file(i,False); } } @@ -2271,7 +2271,7 @@ int reply_close(char *inbuf,char *outbuf) /* try and set the date */ set_filetime(Files[fnum].name,mtime); - close_file(fnum); + close_file(fnum,True); /* We have a cached error */ if(eclass || err) @@ -2318,7 +2318,7 @@ int reply_writeclose(char *inbuf,char *outbuf) set_filetime(Files[fnum].name,mtime); - close_file(fnum); + close_file(fnum,True); DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n", timestring(),fnum,cnum,numtowrite,nwritten, @@ -2550,7 +2550,7 @@ int reply_printclose(char *inbuf,char *outbuf) if (!CAN_PRINT(cnum)) return(ERROR(ERRDOS,ERRnoaccess)); - close_file(fnum); + close_file(fnum,True); DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum)); @@ -3187,14 +3187,14 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun, fnum2 = find_free_file(); if (fnum2<0) { - close_file(fnum1); + close_file(fnum1,False); return(False); } open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1, ofun,st.st_mode,0,&Access,&action); if (!Files[fnum2].open) { - close_file(fnum1); + close_file(fnum1,False); return(False); } @@ -3205,8 +3205,8 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun, if (st.st_size) ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0); - close_file(fnum1); - close_file(fnum2); + close_file(fnum1,False); + close_file(fnum2,False); return(ret == st.st_size); } diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 1c31f69389..be24ad7781 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -1361,8 +1361,13 @@ static void check_magic(int fnum,int cnum) /**************************************************************************** close a file - possibly invalidating the read prediction + +If normal_close is 1 then this came from a normal SMBclose (or equivalent) +operation otherwise it came as the result of some other operation such as +the closing of the connection. In the latter case printing and +magic scripts are not run ****************************************************************************/ -void close_file(int fnum) +void close_file(int fnum, BOOL normal_close) { files_struct *fs_p = &Files[fnum]; int cnum = fs_p->cnum; @@ -1399,11 +1404,12 @@ void close_file(int fnum) unlock_share_entry( cnum, dev, inode, token); /* NT uses smbclose to start a print - weird */ - if (fs_p->print_file) + if (normal_close && fs_p->print_file) print_file(fnum); /* check for magic scripts */ - check_magic(fnum,cnum); + if (normal_close) + check_magic(fnum,cnum); DEBUG(2,("%s %s closed file %s (numopen=%d)\n", timestring(),Connections[cnum].user,fs_p->name, @@ -1575,7 +1581,7 @@ static void truncate_unless_locked(int fnum, int cnum, share_lock_token token, if (*share_locked && lp_share_modes(SNUM(cnum))) unlock_share_entry( cnum, Files[fnum].fd_ptr->dev, Files[fnum].fd_ptr->inode, token); - close_file(fnum); + close_file(fnum,False); /* Share mode no longer locked. */ *share_locked = False; errno = EACCES; @@ -3847,7 +3853,7 @@ static void close_open_files(int cnum) int i; for (i=0;i<MAX_OPEN_FILES;i++) if( Files[i].cnum == cnum && Files[i].open) { - close_file(i); + close_file(i,False); } } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index a56df9cb9c..e484b3b2e1 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -226,7 +226,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum, } if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -235,7 +235,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum, mtime = sbuf.st_mtime; inode = sbuf.st_ino; if (fmode & aDIR) { - close_file(fnum); + close_file(fnum,False); return(ERROR(ERRDOS,ERRnoaccess)); } diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 78614a5b5c..42ade7e4da 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -481,3 +481,77 @@ int smbrun(char *cmd,char *outfile,BOOL shared) #endif return 1; } + +static struct current_user current_user_saved; +static int become_root_depth; +static pstring become_root_dir; + +/**************************************************************************** +This is used when we need to do a privilaged operation (such as mucking +with share mode files) and temporarily need root access to do it. This +call should always be paired with an unbecome_root() call immediately +after the operation + +Set save_dir if you also need to save/restore the CWD +****************************************************************************/ +void become_root(BOOL save_dir) +{ + if (become_root_depth) { + DEBUG(0,("ERROR: become root depth is non zero\n")); + } + if (save_dir) + GetWd(become_root_dir); + + current_user_saved = current_user; + become_root_depth = 1; + + become_gid(0); + become_uid(0); +} + +/**************************************************************************** +When the privilaged operation is over call this + +Set save_dir if you also need to save/restore the CWD +****************************************************************************/ +void unbecome_root(BOOL restore_dir) +{ + if (become_root_depth != 1) { + DEBUG(0,("ERROR: unbecome root depth is %d\n", + become_root_depth)); + } + + /* we might have done a become_user() while running as root, + if we have then become root again in order to become + non root! */ + if (current_user.uid != 0) { + become_uid(0); + } + + /* restore our gid first */ + if (!become_gid(current_user_saved.gid)) { + DEBUG(0,("ERROR: Failed to restore gid\n")); + exit_server("Failed to restore gid"); + } + +#ifndef NO_SETGROUPS + if (current_user_saved.ngroups > 0) { + if (setgroups(current_user_saved.ngroups, + current_user_saved.groups)<0) + DEBUG(0,("ERROR: setgroups call failed!\n")); + } +#endif + + /* now restore our uid */ + if (!become_uid(current_user_saved.uid)) { + DEBUG(0,("ERROR: Failed to restore uid\n")); + exit_server("Failed to restore uid"); + } + + if (restore_dir) + ChDir(become_root_dir); + + current_user = current_user_saved; + + become_root_depth = 0; +} |