diff options
author | Andrew Tridgell <tridge@samba.org> | 1997-10-14 09:15:58 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1997-10-14 09:15:58 +0000 |
commit | 78348cb8f8afe6454bd0e3a9f0b93b8c9c0b85b9 (patch) | |
tree | c61d39a6683f6db0ae1e04516e8d17164bd15933 | |
parent | 0826e4b41b9fcbcdd8ff758c8b5b6da9ca28eb66 (diff) | |
download | samba-78348cb8f8afe6454bd0e3a9f0b93b8c9c0b85b9.tar.gz |
add become_root()/unbecome_root() calls. These should be used around
regions of the code that need root privilages but which normally don't
have them (ie. when processing most SMBs). These functions can
optionally save/restore the current working directory as well
updated several places in the code that previously used unbecome_user()
to achieve the same thing to now use become_root() and unbecome_root()
changed close_file() to take an additional argument which says whether
this is a normal SMBclose type call or a close that resulted from some
other action, such as the close of a connection. If it is a abnormal
close then don't use magic scripts or print files.
changed sys_utime() to ignore any attempt to set the modification time
to 0 or -1. We've had reports that files have had their time set to
0 so this should catch those.
-rw-r--r-- | source/include/proto.h | 4 | ||||
-rw-r--r-- | source/lib/system.c | 13 | ||||
-rw-r--r-- | source/locking/locking.c | 65 | ||||
-rw-r--r-- | source/smbd/ipc.c | 5 | ||||
-rw-r--r-- | source/smbd/pipes.c | 4 | ||||
-rw-r--r-- | source/smbd/reply.c | 24 | ||||
-rw-r--r-- | source/smbd/server.c | 23 | ||||
-rw-r--r-- | source/smbd/trans2.c | 4 | ||||
-rw-r--r-- | source/smbd/uid.c | 84 |
9 files changed, 152 insertions, 74 deletions
diff --git a/source/include/proto.h b/source/include/proto.h index ffa2f251cca..d7cbc4cc4c4 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -705,7 +705,7 @@ int fd_attempt_open(char *fname, int flags, int mode); void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr); int fd_attempt_close(file_fd_struct *fd_ptr); void sync_file(int fnum); -void close_file(int fnum); +void close_file(int fnum, int normal_close); 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); @@ -847,6 +847,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(int save_dir) ; +void unbecome_root(int restore_dir); /*The following definitions come from username.c */ diff --git a/source/lib/system.c b/source/lib/system.c index df24691512f..b149ccb4b98 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -194,14 +194,23 @@ now for utime() ********************************************************************/ int sys_utime(char *fname,struct utimbuf *times) { - return(utime(dos_to_unix(fname,False),times)); + /* if the modtime is 0 or -1 then ignore the call and + return success */ + if (times->modtime == (time_t)0 || times->modtime == (time_t)-1) + return 0; + + /* if the access time is 0 or -1 then set it to the modtime */ + if (times->actime == (time_t)0 || times->actime == (time_t)-1) + times->actime = times->modtime; + + return(utime(dos_to_unix(fname,False),times)); } + /********************************************************* for rename across filesystems Patch from Warren Birnbaum <warrenb@hpcvscdp.cv.hp.com> **********************************************************/ - static int copy_reg (const char *source, const char *dest) { diff --git a/source/locking/locking.c b/source/locking/locking.c index db4990a7263..461ad5aef0b 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -611,10 +611,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(0); + { int old_umask; BOOL gotlock = False; - unbecome_user(); old_umask = umask(0); /* @@ -675,31 +677,14 @@ BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok gotlock = True; } while(!gotlock); - /* - * We have to come here if any of the above calls fail - * as we don't want to return and leave ourselves running - * as root ! - */ - 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(0); + return ret; } @@ -727,31 +712,21 @@ BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token tok /******************************************************************* Force a share file to be deleted. ********************************************************************/ - static int delete_share_file( int cnum, char *fname ) { - unbecome_user(); - if(unlink(fname) != 0) - { - DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n", - fname, strerror(errno))); - } - - DEBUG(5,("delete_share_file: Deleted share file %s\n", fname)); - - 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; + /* the share file could be owned by anyone, so do this as root */ + become_root(0); + + 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)); + } + + unbecome_root(0); + + return 0; } /******************************************************************* diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c index a0a4ec8fc73..1d7ee375d3f 100644 --- a/source/smbd/ipc.c +++ b/source/smbd/ipc.c @@ -1601,13 +1601,14 @@ static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data, name[l] = 0; DEBUG(3,("Setting print name to %s\n",name)); + + become_root(1); for (i=0;i<MAX_OPEN_FILES;i++) if (Files[i].open && Files[i].print_file) { pstring wd; GetWd(wd); - unbecome_user(); if (!become_user(Files[i].cnum,vuid) || !become_service(Files[i].cnum,True)) @@ -1617,6 +1618,8 @@ static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data, string_set(&Files[i].name,name); break; } + + unbecome_root(1); } desc.errcode=NERR_Success; diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c index feb8d91a5b0..2cc6eea506f 100644 --- a/source/smbd/pipes.c +++ b/source/smbd/pipes.c @@ -141,7 +141,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, 0); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -149,7 +149,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, 0); return(ERROR(ERRDOS,ERRnoaccess)); } diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 7925add45f3..ffa80aac870 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1138,7 +1138,7 @@ int reply_open(char *inbuf,char *outbuf) } if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); + close_file(fnum, 0); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1148,7 +1148,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, 0); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1229,7 +1229,7 @@ int reply_open_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, 0); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1237,7 +1237,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, 0); return(ERROR(ERRDOS,ERRnoaccess)); } @@ -1277,7 +1277,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, 0); } } @@ -2190,7 +2190,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, 1); /* We have a cached error */ if(eclass || err) @@ -2237,7 +2237,7 @@ int reply_writeclose(char *inbuf,char *outbuf) set_filetime(Files[fnum].name,mtime); - close_file(fnum); + close_file(fnum, 1); DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n", timestring(),fnum,cnum,numtowrite,nwritten, @@ -2468,7 +2468,7 @@ int reply_printclose(char *inbuf,char *outbuf) if (!CAN_PRINT(cnum)) return(ERROR(ERRDOS,ERRnoaccess)); - close_file(fnum); + close_file(fnum, 1); DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum)); @@ -3040,14 +3040,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, 0); return(False); } open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1, ofun,st.st_mode,&Access,&action); if (!Files[fnum2].open) { - close_file(fnum1); + close_file(fnum1, 0); return(False); } @@ -3058,8 +3058,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, 0); + close_file(fnum2, 0); return(ret == st.st_size); } diff --git a/source/smbd/server.c b/source/smbd/server.c index 8e1bc152ffd..3bfd5bbbf40 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -1348,8 +1348,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, int normal_close) { files_struct *fs_p = &Files[fnum]; int cnum = fs_p->cnum; @@ -1386,11 +1391,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, @@ -1510,7 +1516,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, 0); /* Share mode no longer locked. */ *share_locked = False; errno = EACCES; @@ -3203,7 +3209,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, 0); } } @@ -3216,6 +3222,10 @@ void close_cnum(int cnum, uint16 vuid) { DirCacheFlush(SNUM(cnum)); + close_open_files(cnum); + dptr_closecnum(cnum); + + /* after this we are running as root, so be careful! */ unbecome_user(); if (!OPEN_CNUM(cnum)) @@ -3236,9 +3246,6 @@ void close_cnum(int cnum, uint16 vuid) if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS); - close_open_files(cnum); - dptr_closecnum(cnum); - /* execute any "postexec = " line */ if (*lp_postexec(SNUM(cnum)) && become_user(cnum,vuid)) { diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index ecc8f5dbec7..f7351b99e5a 100644 --- a/source/smbd/trans2.c +++ b/source/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, 0); 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, 0); return(ERROR(ERRDOS,ERRnoaccess)); } diff --git a/source/smbd/uid.c b/source/smbd/uid.c index cdc4e474c61..fe2cb5a652d 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -258,6 +258,8 @@ BOOL become_user(int cnum, uint16 vuid) if (current_user.ngroups > 0) if (setgroups(current_user.ngroups,current_user.groups)<0) DEBUG(0,("setgroups call failed!\n")); + } else { + current_user.ngroups = 0; } #endif @@ -318,7 +320,8 @@ BOOL unbecome_user(void ) current_user.uid = initial_uid; current_user.gid = initial_gid; - + current_user.ngroups = 0; + if (ChDir(OriginalDir) != 0) DEBUG(0,("%s chdir(%s) failed in unbecome_user\n", timestring(),OriginalDir)); @@ -476,3 +479,82 @@ 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(int 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(int 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; +} + + + |