summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h4
-rw-r--r--source3/locking/locking.c45
-rw-r--r--source3/smbd/ipc.c4
-rw-r--r--source3/smbd/pipes.c4
-rw-r--r--source3/smbd/reply.c26
-rw-r--r--source3/smbd/server.c16
-rw-r--r--source3/smbd/trans2.c4
-rw-r--r--source3/smbd/uid.c74
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;
+}