Merge the become_XXX -> change_to_XXX fixes from 2.2.2 to HEAD.
authorJeremy Allison <jra@samba.org>
Thu, 18 Oct 2001 20:15:12 +0000 (20:15 +0000)
committerJeremy Allison <jra@samba.org>
Thu, 18 Oct 2001 20:15:12 +0000 (20:15 +0000)
Ensure make_conection() can only be called as root.
Jeremy.

16 files changed:
source/auth/pass_check.c
source/passdb/nispass.c
source/passdb/pass_check.c
source/printing/nt_printing.c
source/rpc_server/srv_netlog_nt.c
source/rpc_server/srv_pipe.c
source/rpc_server/srv_srvsvc_nt.c
source/smbd/blocking.c
source/smbd/notify_hash.c
source/smbd/oplock.c
source/smbd/password.c
source/smbd/process.c
source/smbd/sec_ctx.c
source/smbd/server.c
source/smbd/service.c
source/smbd/uid.c

index a57cb2ff06beede78e6bd519940e2384a27223b4..44b3b9a2375ba2882662839a3869aa1f33b4e772 100644 (file)
@@ -233,7 +233,7 @@ static BOOL dfs_auth(char *user, char *password)
        }
 
        /*
-        * NB. I'd like to change these to call something like become_user()
+        * NB. I'd like to change these to call something like change_to_user()
         * instead but currently we don't have a connection
         * context to become the correct user. This is already
         * fairly platform specific code however, so I think
index 04b3765d59270c909e6455d807cefe16cc4c87e3..a595cabb37bc9a27f7d64f663a17a7453269e9a1 100644 (file)
@@ -297,7 +297,7 @@ static BOOL make_sam_from_nisp_object(struct sam_passwd *pw_buf, nis_object *obj
        if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$') {
          
          /* XXXX hack to get standard_sub_basic() to use sam logon username */
-         /* possibly a better way would be to do a become_user() call */
+         /* possibly a better way would be to do a change_to_user() call */
          pstrcpy(samlogon_user, pw_buf->smb_name);
          sam_logon_in_ssb = True;
          
index a57cb2ff06beede78e6bd519940e2384a27223b4..44b3b9a2375ba2882662839a3869aa1f33b4e772 100644 (file)
@@ -233,7 +233,7 @@ static BOOL dfs_auth(char *user, char *password)
        }
 
        /*
-        * NB. I'd like to change these to call something like become_user()
+        * NB. I'd like to change these to call something like change_to_user()
         * instead but currently we don't have a connection
         * context to become the correct user. This is already
         * fairly platform specific code however, so I think
index c61893e0feb2c83a3e6a90a78f53bdf821e4f901..9b5f7379f541f4bf4cc2b3087b46fc00b2093a96 100644 (file)
@@ -944,7 +944,10 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        /* connect to the print$ share under the same account as the user connected to the rpc pipe */  
        /* Null password is ok - we are already an authenticated user... */
        *null_pw = '\0';
+
+       become_root();
        conn = make_connection("print$", null_pw, 0, "A:", user->vuid, &nt_status);
+       unbecome_root();
 
        if (conn == NULL) {
                DEBUG(0,("get_correct_cversion: Unable to connect\n"));
@@ -952,13 +955,9 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
                return -1;
        }
 
-       /* Save who we are - we are temporarily becoming the connection user. */
-       push_sec_ctx();
-
        if (!become_user(conn, conn->vuid)) {
                DEBUG(0,("get_correct_cversion: Can't become user!\n"));
                *perr = WERR_ACCESS_DENIED;
-               pop_sec_ctx();
                return -1;
        }
 
@@ -1017,16 +1016,16 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
 
        close_file(fsp, True);
        close_cnum(conn, user->vuid);
-       pop_sec_ctx();
+       unbecome_user();
        return cversion;
 
+  error_exit:
 
-       error_exit:
        if(fsp)
                close_file(fsp, True);
        
        close_cnum(conn, user->vuid);
-       pop_sec_ctx();
+       unbecome_user();
        return -1;
 }
 
index 678c48ff71019f46acd503a19d003c049d1f8757..7a7ff09d711c7af4474f05da01fd4b4fb74adf2e 100644 (file)
@@ -708,7 +708,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                usr_info->ptr_user_info = 0;
         
                /* XXXX hack to get standard_sub_basic() to use sam logon username */
-               /* possibly a better way would be to do a become_user() call */
+               /* possibly a better way would be to do a change_to_user() call */
                sam_logon_in_ssb = True;
                pstrcpy(samlogon_user, nt_username);
 
index 2957d7cc95dd9f82f3d9fdf4d4d3f55a211afc82..7079cc2ca189487f065f09c6838a574272171328 100644 (file)
@@ -1135,7 +1135,6 @@ BOOL api_pipe_request(pipes_struct *p)
 {
        int i = 0;
        BOOL ret = False;
-       BOOL changed_user_id = False;
 
        if (p->ntlmssp_auth_validated) {
 
@@ -1143,8 +1142,6 @@ BOOL api_pipe_request(pipes_struct *p)
                        prs_mem_free(&p->out_data.rdata);
                        return False;
                }
-
-               changed_user_id = True;
        }
 
        for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) {
@@ -1157,8 +1154,8 @@ BOOL api_pipe_request(pipes_struct *p)
                }
        }
 
-       if(changed_user_id)
-               unbecome_authenticated_pipe_user(p);
+       if(p->ntlmssp_auth_validated)
+               unbecome_authenticated_pipe_user();
 
        return ret;
 }
index 2ae4a738740344c421df680659a72d85749ec7dc..44e44cfa3ae1f873593c21bd2749510638f30b9d 100644 (file)
@@ -1598,7 +1598,9 @@ NTSTATUS _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDE
 
        get_current_user(&user, p);     
        
+       become_root();
        conn = make_connection(qualname, null_pw, 0, "A:", user.vuid, &nt_status);
+       unbecome_root();
 
        if (conn == NULL) {
                DEBUG(3,("_srv_net_file_query_secdesc: Unable to connect to %s\n", qualname));
@@ -1649,7 +1651,7 @@ NTSTATUS _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDE
        psd->dacl->revision = (uint16) NT4_ACL_REVISION;
 
        close_file(fsp, True);
-
+       unbecome_user();
        close_cnum(conn, user.vuid);
        return r_u->status;
 
@@ -1700,7 +1702,9 @@ NTSTATUS _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *
 
        get_current_user(&user, p);     
        
+       become_root();
        conn = make_connection(qualname, null_pw, 0, "A:", user.vuid, &nt_status);
+       unbecome_root();
 
        if (conn == NULL) {
                DEBUG(3,("_srv_net_file_set_secdesc: Unable to connect to %s\n", qualname));
index a398a4c2a1beedec88a2e74001b0f89ce1af2aec..252ae6e0ea4c2efc98a8f7acfb0150ac7d668266 100644 (file)
@@ -582,7 +582,7 @@ void process_blocking_lock_queue(time_t t)
       continue;
     }
 
-    if(!become_user(conn,vuid)) {
+    if(!change_to_user(conn,vuid)) {
       DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
             vuid ));
       /*
@@ -594,7 +594,7 @@ void process_blocking_lock_queue(time_t t)
       continue;
     }
 
-    if(!become_service(conn,True)) {
+    if(!set_current_service(conn,True)) {
       DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
       /*
        * Remove the entry and return an error to the client.
@@ -602,7 +602,7 @@ void process_blocking_lock_queue(time_t t)
       blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
-      unbecome_user();
+      change_to_root_user();
       continue;
     }
 
@@ -615,11 +615,11 @@ void process_blocking_lock_queue(time_t t)
     if(blocking_lock_record_process(blr)) {
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
-      unbecome_user();
+      change_to_root_user();
       continue;
     }
 
-    unbecome_user();
+    change_to_root_user();
 
     /*
      * Move to the next in the list.
index 0c69dc78769d30cf26e425723157a2707d8e4844..d398fac214fee73fb8149507d21194e5ce6b60cd 100644 (file)
@@ -126,16 +126,19 @@ static void *hash_register_notify(connection_struct *conn, char *path, uint32 fl
  Check if a change notify should be issued.
  A time of zero means instantaneous check - don't modify the last check time.
 *****************************************************************************/
+
 static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
 {
        struct change_data *data = (struct change_data *)datap;
        struct change_data data2;
 
-       if (t && t < data->last_check_time + lp_change_notify_timeout()) return False;
+       if (t && t < data->last_check_time + lp_change_notify_timeout())
+               return False;
 
-       if (!become_user(conn,vuid)) return True;
-       if (!become_service(conn,True)) {
-               unbecome_user();
+       if (!change_to_user(conn,vuid))
+               return True;
+       if (!set_current_service(conn,True)) {
+               change_to_root_user();
                return True;
        }
 
@@ -144,14 +147,14 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path,
            data2.status_time != data->status_time ||
            data2.total_time != data->total_time ||
            data2.num_entries != data->num_entries) {
-               unbecome_user();
+               change_to_root_user();
                return True;
        }
 
        if (t)
                data->last_check_time = t;
 
-       unbecome_user();
+       change_to_root_user();
 
        return False;
 }
index 4e8e36b3aa64b93d81b146b8f67066a4862f0f0a..927719ac1a7a21dc75303c2125f86f5129c4204b 100644 (file)
@@ -750,7 +750,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
   saved_vuid = current_user.vuid;
   saved_fsp_conn = fsp->conn;
   vfs_GetWd(saved_fsp_conn,saved_dir);
-  unbecome_user();
+  change_to_root_user();
   /* Save the chain fnum. */
   file_chain_save();
 
@@ -823,7 +823,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
    * Go back to being the user who requested the oplock
    * break.
    */
-  if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !become_user(saved_user_conn, saved_vuid))
+  if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !change_to_user(saved_user_conn, saved_vuid))
   {
     DEBUG( 0, ( "oplock_break: unable to re-become user!" ) );
     DEBUGADD( 0, ( "Shutting down server\n" ) );
index b074552567dbbf4d5c37b6888132d2da5d67cf6b..b1739d9bb6fff4405a63a77f3ade93a546e98f0c 100644 (file)
@@ -244,7 +244,7 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
        vuser->groups  = NULL;
 
        /* Find all the groups this uid is in and store them. 
-               Used by become_user() */
+               Used by change_to_user() */
        initialise_groups(vuser->user.unix_name, vuser->uid, vuser->gid);
        get_current_groups( &vuser->n_groups, &vuser->groups);
 
index cf691ce9f3539b2517094474436ef8ce9be748b2..edcb6b345fb090f3a5b3af87da03837e29c11406 100644 (file)
@@ -120,7 +120,7 @@ static void async_processing(fd_set *fds, char *buffer, int buffer_len)
 
        /* check for sighup processing */
        if (reload_after_sighup) {
-               unbecome_user();
+               change_to_root_user();
                DEBUG(1,("Reloading services after SIGHUP\n"));
                reload_services(False);
                reload_after_sighup = False;
@@ -702,7 +702,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
 
     /* does this protocol need to be run as root? */
     if (!(flags & AS_USER))
-      unbecome_user();
+      change_to_root_user();
 
     /* does this protocol need a valid tree connection? */
     if ((flags & AS_USER) && !conn) {
@@ -711,7 +711,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
 
 
     /* does this protocol need to be run as the connected user? */
-    if ((flags & AS_USER) && !become_user(conn,session_tag)) {
+    if ((flags & AS_USER) && !change_to_user(conn,session_tag)) {
       if (flags & AS_GUEST) 
         flags &= ~AS_USER;
       else
@@ -734,13 +734,13 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
     }
 
     /* load service specific parameters */
-    if (conn && !become_service(conn,(flags & AS_USER)?True:False)) {
+    if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) {
       return(ERROR_DOS(ERRSRV,ERRaccess));
     }
 
     /* does this protocol need to be run as guest? */
     if ((flags & AS_GUEST) && 
-                (!become_guest() || 
+                (!change_to_guest() || 
                !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) {
       return(ERROR_DOS(ERRSRV,ERRaccess));
     }
@@ -1096,7 +1096,7 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t
     last_idle_closed_check = t;
 
   /* become root again if waiting */
-  unbecome_user();
+  change_to_root_user();
 
   /* check if we need to reload services */
   check_reload(t);
index c053a611c2cc4094e172fa599dc77a5c37d7d7a7..cea39b82cb8e89a70d6dce5386f8b1959c750acb 100644 (file)
@@ -59,10 +59,8 @@ static BOOL become_uid(uid_t uid)
        /* Set effective user id */
 
        set_effective_uid(uid);
-       current_user.uid = uid;
 
        DO_PROFILE_INC(uid_changes);
-
        return True;
 }
 
@@ -88,8 +86,6 @@ static BOOL become_gid(gid_t gid)
        /* Set effective group id */
 
        set_effective_gid(gid);
-       current_user.gid = gid;
-       
        return True;
 }
 
index 579649cf0c430d9946dfd437f9bf0d198e04d3aa..2e0fb1868d444eea86a007b14c504988f3cc3a23 100644 (file)
@@ -247,7 +247,7 @@ max can be %d\n",
 
                        /* check for sighup processing */
                        if (reload_after_sighup) {
-                               unbecome_user();
+                               change_to_root_user();
                                DEBUG(1,("Reloading services after SIGHUP\n"));
                                reload_services(False);
                                reload_after_sighup = False;
@@ -393,7 +393,7 @@ BOOL reload_services(BOOL test)
        reset_stat_cache();
 
        /* this forces service parameters to be flushed */
-       become_service(NULL,True);
+       set_current_service(NULL,True);
 
        return(ret);
 }
@@ -479,10 +479,11 @@ void exit_server(char *reason)
        extern char *last_inbuf;
 
 
-       if (!firsttime) exit(0);
+       if (!firsttime)
+               exit(0);
        firsttime = 0;
 
-       unbecome_user();
+       change_to_root_user();
        DEBUG(2,("Closing connections\n"));
 
        conn_close_all();
index 6f2c28d19c173eb64e10de9a8844f96297c3de48..9e3f3c9f1106e5cfe020042d5aa61197ee0e79a4 100644 (file)
@@ -34,9 +34,10 @@ extern fstring remote_machine;
 
 
 /****************************************************************************
-load parameters specific to a connection/service
+ Load parameters specific to a connection/service.
 ****************************************************************************/
-BOOL become_service(connection_struct *conn,BOOL do_chdir)
+
+BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
 {
        extern char magic_char;
        static connection_struct *last_conn;
@@ -315,10 +316,10 @@ static void set_admin_user(connection_struct *conn)
 #endif
 }
 
-
 /****************************************************************************
-  make a connection to a service
+ Make a connection to a service.
 ****************************************************************************/
+
 connection_struct *make_connection(char *service,char *password, 
                                   int pwlen, char *dev,uint16 vuid, NTSTATUS *status)
 {
@@ -327,10 +328,17 @@ connection_struct *make_connection(char *service,char *password,
        BOOL guest = False;
        BOOL force = False;
        connection_struct *conn;
+       uid_t euid;
 
        fstring user;
        ZERO_STRUCT(user);
 
+       /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
+       if ((euid = geteuid()) != 0) {
+               DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
+               smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
+       }
+
        strlower(service);
 
        snum = find_service(service);
@@ -519,7 +527,7 @@ connection_struct *make_connection(char *service,char *password,
        conn->groups = NULL;
        
        /* Find all the groups this uid is in and
-          store them. Used by become_user() */
+          store them. Used by change_to_user() */
        initialise_groups(conn->user, conn->uid, conn->gid); 
        get_current_groups(&conn->ngroups,&conn->groups);
                
@@ -557,16 +565,7 @@ connection_struct *make_connection(char *service,char *password,
                return NULL;
        }
 
-       if (!become_user(conn, conn->vuid)) {
-               /* No point continuing if they fail the basic checks */
-               DEBUG(0,("Can't become connected user!\n"));
-               conn_free(conn);
-               *status = NT_STATUS_LOGON_FAILURE;
-               return NULL;
-       }
-
 /* ROOT Activities: */ 
-       become_root();
        /* check number of connections */
        if (!claim_connection(conn,
                              lp_servicename(SNUM(conn)),
@@ -575,8 +574,6 @@ connection_struct *make_connection(char *service,char *password,
                DEBUG(1,("too many connections - rejected\n"));
                *status = NT_STATUS_INSUFFICIENT_RESOURCES;
                conn_free(conn);
-               unbecome_root();
-               unbecome_user();
                return NULL;
        }  
 
@@ -596,14 +593,19 @@ connection_struct *make_connection(char *service,char *password,
                                         lp_max_connections(SNUM(conn)));
                        conn_free(conn);
                        *status = NT_STATUS_UNSUCCESSFUL;
-                       unbecome_root();
-                       unbecome_user();
                        return NULL;
                }
        }
-       unbecome_root();
 
 /* USER Activites: */
+       if (!change_to_user(conn, conn->vuid)) {
+               /* No point continuing if they fail the basic checks */
+               DEBUG(0,("Can't become connected user!\n"));
+               conn_free(conn);
+               *status = NT_STATUS_LOGON_FAILURE;
+               return NULL;
+       }
+
        /* Remember that a different vuid can connect later without these checks... */
 
        /* Preexecs are done here as they might make the dir we are to ChDir to below */
@@ -616,7 +618,7 @@ connection_struct *make_connection(char *service,char *password,
                ret = smbrun(cmd,NULL);
                if (ret != 0 && lp_preexec_close(SNUM(conn))) {
                        DEBUG(1,("preexec gave %d - failing connection\n", ret));
-                       unbecome_user();
+                       change_to_root_user();
                        yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
                        conn_free(conn);
                        *status = NT_STATUS_UNSUCCESSFUL;
@@ -628,7 +630,7 @@ connection_struct *make_connection(char *service,char *password,
                DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
                         remote_machine, conn->client_address,
                         conn->connectpath,strerror(errno)));
-               unbecome_user();
+               change_to_root_user();
                yield_connection(conn,
                                 lp_servicename(SNUM(conn)),
                                 lp_max_connections(SNUM(conn)));
@@ -677,14 +679,14 @@ connection_struct *make_connection(char *service,char *password,
                if (conn->vfs_ops.connect(conn, service, user) < 0) {
                        DEBUG(0,("make_connection: VFS make connection failed!\n"));
                        *status = NT_STATUS_UNSUCCESSFUL;
-                       unbecome_user();
+                       change_to_root_user();
                        conn_free(conn);
                        return NULL;
                }
        }
 
-       /* we've finished with the sensitive stuff */
-       unbecome_user();
+       /* we've finished with the user stuff - go back to root */
+       change_to_root_user();
             
        return(conn);
 }
@@ -697,7 +699,7 @@ void close_cnum(connection_struct *conn, uint16 vuid)
 {
        DirCacheFlush(SNUM(conn));
 
-       unbecome_user();
+       change_to_root_user();
 
        DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
                                 remote_machine,conn->client_address,
@@ -720,15 +722,15 @@ void close_cnum(connection_struct *conn, uint16 vuid)
 
        /* execute any "postexec = " line */
        if (*lp_postexec(SNUM(conn)) && 
-           become_user(conn, vuid))  {
+           change_to_user(conn, vuid))  {
                pstring cmd;
                pstrcpy(cmd,lp_postexec(SNUM(conn)));
                standard_sub_conn(conn,cmd);
                smbrun(cmd,NULL);
-               unbecome_user();
+               change_to_root_user();
        }
 
-       unbecome_user();
+       change_to_root_user();
        /* execute any "root postexec = " line */
        if (*lp_rootpostexec(SNUM(conn)))  {
                pstring cmd;
index 39bdaaa5960c80c91eca2fef61fe1a616ca20bb4..b1012c3c912ff8be2a1e8789ee60e8cdb089b737 100644 (file)
 extern struct current_user current_user;
 
 /****************************************************************************
- Become the guest user.
+ Become the guest user without changing the security context stack.
 ****************************************************************************/
 
-BOOL become_guest(void)
+BOOL change_to_guest(void)
 {
        static struct passwd *pass=NULL;
        static uid_t guest_uid = (uid_t)-1;
@@ -82,10 +82,11 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
 }
 
 /****************************************************************************
- Become the user of a connection number.
+ Become the user of a connection number without changing the security context
+ stack, but modify the currnet_user entries.
 ****************************************************************************/
 
-BOOL become_user(connection_struct *conn, uint16 vuid)
+BOOL change_to_user(connection_struct *conn, uint16 vuid)
 {
        user_struct *vuser = get_valid_user_struct(vuid);
        int snum;
@@ -96,7 +97,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
        NT_USER_TOKEN *token = NULL;
 
        if (!conn) {
-               DEBUG(2,("Connection not open\n"));
+               DEBUG(2,("change_to_user: Connection not open\n"));
                return(False);
        }
 
@@ -109,12 +110,12 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
 
        if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
           (current_user.uid == conn->uid)) {
-               DEBUG(4,("Skipping become_user - already user\n"));
+               DEBUG(4,("change_to_user: Skipping user change - already user\n"));
                return(True);
        } else if ((current_user.conn == conn) && 
                   (vuser != 0) && (current_user.vuid == vuid) && 
                   (current_user.uid == vuser->uid)) {
-               DEBUG(4,("Skipping become_user - already user\n"));
+               DEBUG(4,("change_to_user: Skipping user change - already user\n"));
                return(True);
        }
 
@@ -133,7 +134,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
                token = conn->nt_user_token;
        } else {
                if (!vuser) {
-                       DEBUG(2,("Invalid vuid used %d\n",vuid));
+                       DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid));
                        return(False);
                }
                uid = vuser->uid;
@@ -196,21 +197,22 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
        current_user.conn = conn;
        current_user.vuid = vuid;
 
-       DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
+       DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
   
        return(True);
 }
 
 /****************************************************************************
- Unbecome the user of a connection number.
+ Go back to being root without changing the security context stack,
+ but modify the current_user entries.
 ****************************************************************************/
 
-BOOL unbecome_user(void )
+BOOL change_to_root_user(void)
 {
        set_root_sec_ctx();
 
-       DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
+       DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
                (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
 
        current_user.conn = NULL;
@@ -222,16 +224,13 @@ BOOL unbecome_user(void )
 /****************************************************************************
  Become the user of an authenticated connected named pipe.
  When this is called we are currently running as the connection
- user.
+ user. Doesn't modify current_user.
 ****************************************************************************/
 
 BOOL become_authenticated_pipe_user(pipes_struct *p)
 {
-       BOOL res = push_sec_ctx();
-
-       if (!res) {
+       if (!push_sec_ctx())
                return False;
-       }
 
        set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid, 
                    p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
@@ -242,19 +241,93 @@ BOOL become_authenticated_pipe_user(pipes_struct *p)
 /****************************************************************************
  Unbecome the user of an authenticated connected named pipe.
  When this is called we are running as the authenticated pipe
- user and need to go back to being the connection user.
+ user and need to go back to being the connection user. Doesn't modify
+ current_user.
 ****************************************************************************/
 
-BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
+BOOL unbecome_authenticated_pipe_user(void)
 {
        return pop_sec_ctx();
 }
 
-/* Temporarily become a root user.  Must match with unbecome_root(). */
+/****************************************************************************
+ Utility functions used by become_xxx/unbecome_xxx.
+****************************************************************************/
+
+struct conn_ctx {
+       connection_struct *conn;
+       uint16 vuid;
+};
+/* A stack of current_user connection contexts. */
+static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
+static int conn_ctx_stack_ndx;
+
+static void push_conn_ctx(void)
+{
+       struct conn_ctx *ctx_p;
+       /* Check we don't overflow our stack */
+       if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
+               DEBUG(0, ("Connection context stack overflow!\n"));
+               smb_panic("Connection context stack overflow!\n");
+       }
+       /* Store previous user context */
+       ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+       ctx_p->conn = current_user.conn;
+       ctx_p->vuid = current_user.vuid;
+       DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
+               (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
+
+       conn_ctx_stack_ndx++;
+}
+
+static void pop_conn_ctx(void)
+{
+       struct conn_ctx *ctx_p;
+       /* Check for stack underflow. */
+
+       if (conn_ctx_stack_ndx == 0) {
+               DEBUG(0, ("Connection context stack underflow!\n"));
+               smb_panic("Connection context stack underflow!\n");
+       }
+
+       conn_ctx_stack_ndx--;
+       ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+       current_user.conn = ctx_p->conn;
+       current_user.vuid = ctx_p->vuid;
+
+       ctx_p->conn = NULL;
+       ctx_p->vuid = UID_FIELD_INVALID;
+}
+
+void init_conn_ctx(void)
+{
+    int i;
+    /* Initialise connection context stack */
+       for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
+               conn_ctx_stack[i].conn = NULL;
+               conn_ctx_stack[i].vuid = UID_FIELD_INVALID;
+    }
+}
+
+/****************************************************************************
+ Temporarily become a root user.  Must match with unbecome_root(). Saves and
+ restores the connection context.
+****************************************************************************/
 
 void become_root(void)
 {
        push_sec_ctx();
+       push_conn_ctx();
        set_root_sec_ctx();
 }
 
@@ -263,6 +336,35 @@ void become_root(void)
 void unbecome_root(void)
 {
        pop_sec_ctx();
+       pop_conn_ctx();
+}
+
+/****************************************************************************
+ Push the current security context then force a change via change_to_user().
+ Saves and restores the connection context.
+****************************************************************************/
+
+BOOL become_user(connection_struct *conn, uint16 vuid)
+{
+       if (!push_sec_ctx())
+               return False;
+
+       push_conn_ctx();
+
+       if (!change_to_user(conn, vuid)) {
+               pop_sec_ctx();
+               pop_conn_ctx();
+               return False;
+       }
+
+       return True;
+}
+
+BOOL unbecome_user()
+{
+       pop_sec_ctx();
+       pop_conn_ctx();
+       return True;
 }
 
 /*****************************************************************