2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* what user is current? */
25 extern struct current_user current_user;
27 /****************************************************************************
28 Become the guest user without changing the security context stack.
29 ****************************************************************************/
31 BOOL change_to_guest(void)
33 static struct passwd *pass=NULL;
36 /* Don't need to free() this as its stored in a static */
37 pass = getpwnam_alloc(lp_guestaccount());
43 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
45 initgroups(pass->pw_name, pass->pw_gid);
48 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
50 current_user.conn = NULL;
51 current_user.vuid = UID_FIELD_INVALID;
56 /*******************************************************************
57 Check if a username is OK.
58 ********************************************************************/
60 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
63 for (i=0;i<conn->uid_cache.entries;i++)
64 if (conn->uid_cache.list[i] == vuser->uid)
67 if (!user_ok(vuser->user.unix_name,snum))
70 i = conn->uid_cache.entries % UID_CACHE_SIZE;
71 conn->uid_cache.list[i] = vuser->uid;
73 if (conn->uid_cache.entries < UID_CACHE_SIZE)
74 conn->uid_cache.entries++;
79 /****************************************************************************
80 Become the user of a connection number without changing the security context
81 stack, but modify the currnet_user entries.
82 ****************************************************************************/
84 BOOL change_to_user(connection_struct *conn, uint16 vuid)
86 user_struct *vuser = get_valid_user_struct(vuid);
91 BOOL must_free_token = False;
92 NT_USER_TOKEN *token = NULL;
95 DEBUG(2,("change_to_user: Connection not open\n"));
100 * We need a separate check in security=share mode due to vuid
101 * always being UID_FIELD_INVALID. If we don't do this then
102 * in share mode security we are *always* changing uid's between
103 * SMB's - this hurts performance - Badly.
106 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
107 (current_user.uid == conn->uid)) {
108 DEBUG(4,("change_to_user: Skipping user change - already user\n"));
110 } else if ((current_user.conn == conn) &&
111 (vuser != 0) && (current_user.vuid == vuid) &&
112 (current_user.uid == vuser->uid)) {
113 DEBUG(4,("change_to_user: Skipping user change - already user\n"));
119 if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
122 if (conn->force_user ||
124 (lp_security() == SEC_SHARE)) {
127 current_user.groups = conn->groups;
128 current_user.ngroups = conn->ngroups;
129 token = conn->nt_user_token;
132 DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid));
137 current_user.ngroups = vuser->n_groups;
138 current_user.groups = vuser->groups;
139 token = vuser->nt_user_token;
143 * See if we should force group for this service.
144 * If so this overrides any group set in the force
148 if((group_c = *lp_force_group(snum))) {
149 BOOL is_guest = False;
154 * Only force group if the user is a member of
155 * the service group. Check the group memberships for
156 * this user (we already have this) to
157 * see if we should force the group.
161 for (i = 0; i < current_user.ngroups; i++) {
162 if (current_user.groups[i] == conn->gid) {
172 * We've changed the group list in the token - we must
176 if (vuser && vuser->guest)
179 token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL);
180 must_free_token = True;
183 set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
186 * Free the new token (as set_sec_ctx copies it).
190 delete_nt_token(&token);
192 current_user.conn = conn;
193 current_user.vuid = vuid;
195 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
196 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
201 /****************************************************************************
202 Go back to being root without changing the security context stack,
203 but modify the current_user entries.
204 ****************************************************************************/
206 BOOL change_to_root_user(void)
210 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
211 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
213 current_user.conn = NULL;
214 current_user.vuid = UID_FIELD_INVALID;
219 /****************************************************************************
220 Become the user of an authenticated connected named pipe.
221 When this is called we are currently running as the connection
222 user. Doesn't modify current_user.
223 ****************************************************************************/
225 BOOL become_authenticated_pipe_user(pipes_struct *p)
230 set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid,
231 p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
236 /****************************************************************************
237 Unbecome the user of an authenticated connected named pipe.
238 When this is called we are running as the authenticated pipe
239 user and need to go back to being the connection user. Doesn't modify
241 ****************************************************************************/
243 BOOL unbecome_authenticated_pipe_user(void)
245 return pop_sec_ctx();
248 /****************************************************************************
249 Utility functions used by become_xxx/unbecome_xxx.
250 ****************************************************************************/
253 connection_struct *conn;
257 /* A stack of current_user connection contexts. */
259 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
260 static int conn_ctx_stack_ndx;
262 static void push_conn_ctx(void)
264 struct conn_ctx *ctx_p;
266 /* Check we don't overflow our stack */
268 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
269 DEBUG(0, ("Connection context stack overflow!\n"));
270 smb_panic("Connection context stack overflow!\n");
273 /* Store previous user context */
274 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
276 ctx_p->conn = current_user.conn;
277 ctx_p->vuid = current_user.vuid;
279 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
280 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
282 conn_ctx_stack_ndx++;
285 static void pop_conn_ctx(void)
287 struct conn_ctx *ctx_p;
289 /* Check for stack underflow. */
291 if (conn_ctx_stack_ndx == 0) {
292 DEBUG(0, ("Connection context stack underflow!\n"));
293 smb_panic("Connection context stack underflow!\n");
296 conn_ctx_stack_ndx--;
297 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
299 current_user.conn = ctx_p->conn;
300 current_user.vuid = ctx_p->vuid;
303 ctx_p->vuid = UID_FIELD_INVALID;
306 void init_conn_ctx(void)
310 /* Initialise connection context stack */
311 for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
312 conn_ctx_stack[i].conn = NULL;
313 conn_ctx_stack[i].vuid = UID_FIELD_INVALID;
317 /****************************************************************************
318 Temporarily become a root user. Must match with unbecome_root(). Saves and
319 restores the connection context.
320 ****************************************************************************/
322 void become_root(void)
329 /* Unbecome the root user */
331 void unbecome_root(void)
337 /****************************************************************************
338 Push the current security context then force a change via change_to_user().
339 Saves and restores the connection context.
340 ****************************************************************************/
342 BOOL become_user(connection_struct *conn, uint16 vuid)
349 if (!change_to_user(conn, vuid)) {
358 BOOL unbecome_user(void)
365 /*****************************************************************
366 Convert the suplimentary SIDs returned in a netlogon into UNIX
367 group gid_t's. Add to the total group array.
368 *****************************************************************/
370 void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok)
373 int current_n_groups = *n_groups;
374 gid_t *final_groups = NULL;
376 NT_USER_TOKEN *ptok = *pptok;
377 NT_USER_TOKEN *new_tok = NULL;
379 if (!ptok || (ptok->num_sids == 0))
382 new_tok = dup_nt_token(ptok);
384 DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n"));
387 /* Leave the allocated space but empty the number of SIDs. */
388 new_tok->num_sids = 0;
390 total_groups = current_n_groups + ptok->num_sids;
392 final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t));
394 DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n"));
395 delete_nt_token(&new_tok);
399 memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t));
400 for (i = 0; i < ptok->num_sids; i++) {
401 enum SID_NAME_USE sid_type;
404 if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) {
406 * Don't add the gid_t if it is already in the current group
407 * list. Some UNIXen don't like the same group more than once.
411 for (j = 0; j < current_n_groups; j++)
412 if (final_groups[j] == new_grp)
415 if ( j == current_n_groups) {
416 /* Group not already present. */
417 final_groups[current_n_groups++] = new_grp;
420 /* SID didn't map. Copy to the new token to be saved. */
421 sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
425 SAFE_FREE(*pp_groups);
426 *pp_groups = final_groups;
427 *n_groups = current_n_groups;
429 /* Replace the old token with the truncated one. */
430 delete_nt_token(&ptok);
434 /*****************************************************************
435 *THE CANONICAL* convert name to SID function.
436 Tries local lookup first - for local domains - then uses winbind.
437 *****************************************************************/
439 BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
441 extern pstring global_myname;
442 extern fstring global_myworkgroup;
446 *name_type = SID_NAME_UNKNOWN;
448 /* If we are looking up a domain user, make sure it is
449 for the local machine only */
451 switch (lp_server_role()) {
452 case ROLE_DOMAIN_PDC:
453 case ROLE_DOMAIN_BDC:
454 if (strequal(domain, global_myworkgroup)) {
455 ret = local_lookup_name(name, psid, name_type);
457 /* No break is deliberate here. JRA. */
460 } else if (strequal(global_myname, domain)) {
461 ret = local_lookup_name(name, psid, name_type);
463 DEBUG(5, ("lookup_name: domain %s is not local\n", domain));
469 ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %u)\n",
470 domain, name, sid_to_string(sid,psid),
471 (unsigned int)*name_type ));
473 } else if (winbind_lookup_name(domain, name, psid, name_type) || (*name_type != SID_NAME_USER) ) {
475 DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
476 domain, name, sid_to_string(sid, psid),
477 (unsigned int)*name_type));
481 DEBUG(10, ("lookup_name: winbind and local lookups for [%s]\\[%s] failed\n", domain, name));
486 /*****************************************************************
487 *THE CANONICAL* convert SID to name function.
488 Tries local lookup first - for local sids, then tries winbind.
489 *****************************************************************/
491 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
496 *name_type = SID_NAME_UNKNOWN;
498 /* Check if this is our own sid. This should perhaps be done by
499 winbind? For the moment handle it here. */
501 if (sid->num_auths == 5) {
505 sid_copy(&tmp_sid, sid);
506 sid_split_rid(&tmp_sid, &rid);
508 if (sid_equal(&global_sam_sid, &tmp_sid)) {
510 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
511 local_lookup_sid(sid, name, name_type);
515 if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
520 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
522 sid_copy(&tmp_sid, sid);
523 sid_split_rid(&tmp_sid, &rid);
524 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
525 lookup_known_rid(&tmp_sid, rid, name, name_type);
530 /*****************************************************************
531 *THE CANONICAL* convert uid_t to SID function.
532 Tries winbind first - then uses local lookup.
534 *****************************************************************/
536 DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
541 if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
542 if (winbind_uid_to_sid(psid, uid)) {
544 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
545 (unsigned int)uid, sid_to_string(sid, psid)));
551 local_uid_to_sid(psid, uid);
553 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
558 /*****************************************************************
559 *THE CANONICAL* convert gid_t to SID function.
560 Tries winbind first - then uses local lookup.
562 *****************************************************************/
564 DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
569 if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
570 if (winbind_gid_to_sid(psid, gid)) {
572 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
573 (unsigned int)gid, sid_to_string(sid, psid)));
579 local_gid_to_sid(psid, gid);
581 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
586 /*****************************************************************
587 *THE CANONICAL* convert SID to uid function.
588 Tries winbind first - then uses local lookup.
589 Returns True if this name is a user sid and the conversion
590 was done correctly, False if not. sidtype is set by this function.
591 *****************************************************************/
593 BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
595 fstring dom_name, name, sid_str;
596 enum SID_NAME_USE name_type;
598 *sidtype = SID_NAME_UNKNOWN;
601 * First we must look up the name and decide if this is a user sid.
604 if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
605 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
606 sid_to_string(sid_str, psid) ));
608 return local_sid_to_uid(puid, psid, sidtype);
612 * Ensure this is a user sid.
615 if (name_type != SID_NAME_USER) {
616 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
617 (unsigned int)name_type ));
621 *sidtype = SID_NAME_USER;
624 * Get the uid for this SID.
627 if (!winbind_sid_to_uid(puid, psid)) {
628 DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
629 sid_to_string(sid_str, psid) ));
633 DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
634 sid_to_string(sid_str, psid),
635 (unsigned int)*puid ));
640 /*****************************************************************
641 *THE CANONICAL* convert SID to gid function.
642 Tries winbind first - then uses local lookup.
643 Returns True if this name is a user sid and the conversion
644 was done correctly, False if not.
645 *****************************************************************/
647 BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
649 fstring dom_name, name, sid_str;
650 enum SID_NAME_USE name_type;
652 *sidtype = SID_NAME_UNKNOWN;
655 * First we must look up the name and decide if this is a group sid.
658 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
659 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
660 sid_to_string(sid_str, psid) ));
662 return local_sid_to_gid(pgid, psid, sidtype);
666 * Ensure this is a group sid.
669 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
670 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
671 (unsigned int)name_type ));
673 return local_sid_to_gid(pgid, psid, sidtype);
676 *sidtype = name_type;
679 * Get the gid for this SID.
682 if (!winbind_sid_to_gid(pgid, psid)) {
683 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
684 sid_to_string(sid_str, psid) ));
688 DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",
689 sid_to_string(sid_str, psid),
690 (unsigned int)*pgid ));