}
/*
- * 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
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;
}
/*
- * 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
/* 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"));
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;
}
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;
}
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);
{
int i = 0;
BOOL ret = False;
- BOOL changed_user_id = False;
if (p->ntlmssp_auth_validated) {
prs_mem_free(&p->out_data.rdata);
return False;
}
-
- changed_user_id = True;
}
for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) {
}
}
- if(changed_user_id)
- unbecome_authenticated_pipe_user(p);
+ if(p->ntlmssp_auth_validated)
+ unbecome_authenticated_pipe_user();
return ret;
}
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));
psd->dacl->revision = (uint16) NT4_ACL_REVISION;
close_file(fsp, True);
-
+ unbecome_user();
close_cnum(conn, user.vuid);
return r_u->status;
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));
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 ));
/*
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.
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;
}
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.
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;
}
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;
}
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();
* 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" ) );
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);
/* 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;
/* 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) {
/* 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
}
/* 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));
}
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);
/* Set effective user id */
set_effective_uid(uid);
- current_user.uid = uid;
DO_PROFILE_INC(uid_changes);
-
return True;
}
/* Set effective group id */
set_effective_gid(gid);
- current_user.gid = gid;
-
return True;
}
/* 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;
reset_stat_cache();
/* this forces service parameters to be flushed */
- become_service(NULL,True);
+ set_current_service(NULL,True);
return(ret);
}
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();
/****************************************************************************
-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;
#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)
{
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);
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);
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)),
DEBUG(1,("too many connections - rejected\n"));
*status = NT_STATUS_INSUFFICIENT_RESOURCES;
conn_free(conn);
- unbecome_root();
- unbecome_user();
return NULL;
}
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 */
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;
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)));
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);
}
{
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,
/* 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;
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;
}
/****************************************************************************
- 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;
NT_USER_TOKEN *token = NULL;
if (!conn) {
- DEBUG(2,("Connection not open\n"));
+ DEBUG(2,("change_to_user: Connection not open\n"));
return(False);
}
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);
}
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;
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;
/****************************************************************************
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);
/****************************************************************************
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();
}
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;
}
/*****************************************************************