/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
uid/user handling
Copyright (C) Andrew Tridgell 1992-1998
#include "includes.h"
-extern int DEBUGLEVEL;
-
/* what user is current? */
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;
- static gid_t guest_gid = (gid_t)-1;
- static fstring guest_name;
if (!pass) {
- pass = Get_Pwnam(lp_guestaccount(-1),True);
+ /* Don't need to free() this as its stored in a static */
+ pass = getpwnam_alloc(lp_guestaccount());
if (!pass)
return(False);
- guest_uid = pass->pw_uid;
- guest_gid = pass->pw_gid;
- fstrcpy(guest_name, pass->pw_name);
}
#ifdef AIX
/* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
setting IDs */
- initgroups(guest_name, guest_gid);
+ initgroups(pass->pw_name, pass->pw_gid);
#endif
- set_sec_ctx(guest_uid, guest_gid, 0, NULL, NULL);
+ set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
current_user.conn = NULL;
current_user.vuid = UID_FIELD_INVALID;
}
/****************************************************************************
- 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);
}
if (conn->force_user ||
conn->admin_user ||
- lp_security() == SEC_SHARE ||
- !(vuser) || (vuser->guest)) {
+ (lp_security() == SEC_SHARE)) {
uid = conn->uid;
gid = conn->gid;
current_user.groups = conn->groups;
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;
if (vuser && vuser->guest)
is_guest = True;
- token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
+ token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL);
must_free_token = True;
}
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();
}
-/*****************************************************************
- *THE CANONICAL* convert name to SID function.
- Tries winbind first - then uses local lookup.
-*****************************************************************/
+/****************************************************************************
+ Push the current security context then force a change via change_to_user().
+ Saves and restores the connection context.
+****************************************************************************/
-BOOL lookup_name(const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
+BOOL become_user(connection_struct *conn, uint16 vuid)
{
- extern pstring global_myname;
- extern fstring global_myworkgroup;
- fstring sid;
- char *sep = lp_winbind_separator();
+ if (!push_sec_ctx())
+ return False;
- if (!winbind_lookup_name(name, psid, name_type)) {
- BOOL ret;
+ push_conn_ctx();
- DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name));
+ if (!change_to_user(conn, vuid)) {
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return False;
+ }
- /* If we are looking up a domain user, make sure it is
- for the local machine only */
+ return True;
+}
- if (strchr(name, sep[0]) || strchr(name, '\\')) {
- fstring domain, username;
+BOOL unbecome_user(void)
+{
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return True;
+}
- split_domain_name(name, domain, username);
+/*****************************************************************
+ Convert the suplimentary SIDs returned in a netlogon into UNIX
+ group gid_t's. Add to the total group array.
+*****************************************************************/
+
+void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok)
+{
+ int total_groups;
+ int current_n_groups = *n_groups;
+ gid_t *final_groups = NULL;
+ size_t i;
+ NT_USER_TOKEN *ptok = *pptok;
+ NT_USER_TOKEN *new_tok = NULL;
+
+ if (!ptok || (ptok->num_sids == 0))
+ return;
+
+ new_tok = dup_nt_token(ptok);
+ if (!new_tok) {
+ DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n"));
+ return;
+ }
+ /* Leave the allocated space but empty the number of SIDs. */
+ new_tok->num_sids = 0;
+
+ total_groups = current_n_groups + ptok->num_sids;
+
+ final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t));
+ if (!final_groups) {
+ DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n"));
+ delete_nt_token(&new_tok);
+ return;
+ }
+
+ memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t));
+ for (i = 0; i < ptok->num_sids; i++) {
+ enum SID_NAME_USE sid_type;
+ gid_t new_grp;
+
+ if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) {
+ /*
+ * Don't add the gid_t if it is already in the current group
+ * list. Some UNIXen don't like the same group more than once.
+ */
+ int j;
- switch (lp_server_role()) {
- case ROLE_DOMAIN_PDC:
- case ROLE_DOMAIN_BDC:
- if (strequal(domain, global_myworkgroup))
- fstrcpy(domain, global_myname);
- /* No break is deliberate here. JRA. */
- default:
- if (strcasecmp(global_myname, domain) != 0) {
- DEBUG(5, ("domain %s is not local\n", domain));
- return False;
- }
+ for (j = 0; j < current_n_groups; j++)
+ if (final_groups[j] == new_grp)
+ break;
+
+ if ( j == current_n_groups) {
+ /* Group not already present. */
+ final_groups[current_n_groups++] = new_grp;
}
-
- ret = local_lookup_name(domain, username, psid,
- name_type);
} else {
- ret = local_lookup_name(global_myname, name, psid,
- name_type);
+ /* SID didn't map. Copy to the new token to be saved. */
+ sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
}
+ }
+
+ SAFE_FREE(*pp_groups);
+ *pp_groups = final_groups;
+ *n_groups = current_n_groups;
+
+ /* Replace the old token with the truncated one. */
+ delete_nt_token(&ptok);
+ *pptok = new_tok;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert name to SID function.
+ Tries local lookup first - for local domains - then uses winbind.
+*****************************************************************/
+
+BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
+{
+ extern pstring global_myname;
+ extern fstring global_myworkgroup;
+ fstring sid;
+ BOOL ret = False;
+
+ *name_type = SID_NAME_UNKNOWN;
+ /* If we are looking up a domain user, make sure it is
+ for the local machine only */
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ if (strequal(domain, global_myworkgroup)) {
+ ret = local_lookup_name(name, psid, name_type);
+ }
+ /* No break is deliberate here. JRA. */
+ default:
if (ret) {
- DEBUG(10,
- ("lookup_name: (local) %s -> SID %s (type %u)\n",
- name, sid_to_string(sid,psid),
- (unsigned int)*name_type ));
+ } else if (strequal(global_myname, domain)) {
+ ret = local_lookup_name(name, psid, name_type);
} else {
- DEBUG(10,("lookup name: (local) %s failed.\n", name));
+ DEBUG(5, ("lookup_name: domain %s is not local\n", domain));
}
-
- return ret;
}
-
- DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
- name, sid_to_string(sid, psid),
+
+ if (ret) {
+ DEBUG(10,
+ ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %u)\n",
+ domain, name, sid_to_string(sid,psid),
+ (unsigned int)*name_type ));
+ return True;
+ } else if (winbind_lookup_name(domain, name, psid, name_type) || (*name_type != SID_NAME_USER) ) {
+
+ DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
+ domain, name, sid_to_string(sid, psid),
(unsigned int)*name_type));
- return True;
+ return True;
+ }
+
+ DEBUG(10, ("lookup_name: winbind and local lookups for [%s]\\[%s] failed\n", domain, name));
+
+ return False;
}
/*****************************************************************
*THE CANONICAL* convert SID to name function.
- Tries winbind first - then uses local lookup.
+ Tries local lookup first - for local sids, then tries winbind.
*****************************************************************/
BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
if (!name_type)
return False;
+ *name_type = SID_NAME_UNKNOWN;
+
/* Check if this is our own sid. This should perhaps be done by
winbind? For the moment handle it here. */
sid_copy(&tmp_sid, sid);
sid_split_rid(&tmp_sid, &rid);
- if (sid_equal(&global_sam_sid, &tmp_sid)) {
+ if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
- local_lookup_rid(rid, name, name_type);
+ local_lookup_sid(sid, name, name_type);
}
}
sid_copy(&tmp_sid, sid);
sid_split_rid(&tmp_sid, &rid);
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
- lookup_known_rid(&tmp_sid, rid, name, name_type);
+ lookup_known_rid(&tmp_sid, rid, name, name_type);
}
return True;
}
DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
{
+ uid_t low, high;
fstring sid;
- if (!winbind_uid_to_sid(psid, uid)) {
- DEBUG(10,("uid_to_sid: winbind lookup for uid %u failed - trying local.\n", (unsigned int)uid ));
+ if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
+ if (winbind_uid_to_sid(psid, uid)) {
+
+ DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
+ (unsigned int)uid, sid_to_string(sid, psid)));
- return local_uid_to_sid(psid, uid);
+ return psid;
+ }
}
+
+ /* Make sure we report failure, (when psid == NULL) */
+ become_root();
+ psid = local_uid_to_sid(psid, uid);
+ unbecome_root();
- DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
- (unsigned int)uid, sid_to_string(sid, psid) ));
+ DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
return psid;
}
DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
{
+ gid_t low, high;
fstring sid;
- if (!winbind_gid_to_sid(psid, gid)) {
- DEBUG(10,("gid_to_sid: winbind lookup for gid %u failed - trying local.\n", (unsigned int)gid ));
+ if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
+ if (winbind_gid_to_sid(psid, gid)) {
- return local_gid_to_sid(psid, gid);
+ DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
+ (unsigned int)gid, sid_to_string(sid, psid)));
+
+ return psid;
+ }
}
- DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
- (unsigned int)gid, sid_to_string(sid,psid) ));
+ /* Make sure we report failure, (when psid == NULL) */
+ psid = local_gid_to_sid(psid, gid);
+
+ DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
return psid;
}
*THE CANONICAL* convert SID to uid function.
Tries winbind first - then uses local lookup.
Returns True if this name is a user sid and the conversion
- was done correctly, False if not.
+ was done correctly, False if not. sidtype is set by this function.
*****************************************************************/
BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
{
- fstring dom_name, name, sid_str;
+ fstring sid_str;
+
+ /* if we know its local then don't try winbindd */
+ if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
+ return local_sid_to_uid(puid, psid, sidtype);
+ }
+
+/* (tridge) I commented out the slab of code below in order to support foreign SIDs
+ Do we really need to validate the type of SID we have in this case?
+*/
+#if 0
+ fstring dom_name, name;
enum SID_NAME_USE name_type;
*sidtype = SID_NAME_UNKNOWN;
-
/*
* First we must look up the name and decide if this is a user sid.
*/
- if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
+ if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
+ BOOL result;
DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
sid_to_string(sid_str, psid) ));
- return local_sid_to_uid(puid, psid, sidtype);
+ become_root();
+ result = local_sid_to_uid(puid, psid, sidtype);
+ unbecome_root();
+ return result;
}
/*
(unsigned int)name_type ));
return False;
}
-
+#endif
*sidtype = SID_NAME_USER;
/*
*/
if (!winbind_sid_to_uid(puid, psid)) {
+ BOOL result;
DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
sid_to_string(sid_str, psid) ));
- return False;
+ become_root();
+ result = local_sid_to_uid(puid, psid, sidtype);
+ unbecome_root();
+ return result;
}
DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
sid_to_string(sid_str, psid) ));
-
- return local_sid_to_gid(pgid, psid, sidtype);
+ if (!local_sid_to_gid(pgid, psid, sidtype)) {
+ /* this was probably a foreign sid - assume its a group rid
+ and continue */
+ name_type = SID_NAME_DOM_GRP;
+ } else {
+ return True;
+ }
}
/*
return False;
}
- DEBUG(10,("gid_to_uid: winbindd %s -> %u\n",
+ DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",
sid_to_string(sid_str, psid),
(unsigned int)*pgid ));
return True;
}
+