summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1997-10-14 09:15:58 +0000
committerAndrew Tridgell <tridge@samba.org>1997-10-14 09:15:58 +0000
commit78348cb8f8afe6454bd0e3a9f0b93b8c9c0b85b9 (patch)
treec61d39a6683f6db0ae1e04516e8d17164bd15933
parent0826e4b41b9fcbcdd8ff758c8b5b6da9ca28eb66 (diff)
downloadsamba-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.h4
-rw-r--r--source/lib/system.c13
-rw-r--r--source/locking/locking.c65
-rw-r--r--source/smbd/ipc.c5
-rw-r--r--source/smbd/pipes.c4
-rw-r--r--source/smbd/reply.c24
-rw-r--r--source/smbd/server.c23
-rw-r--r--source/smbd/trans2.c4
-rw-r--r--source/smbd/uid.c84
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;
+}
+
+
+