s3: libsmb: In cli_qpathinfo_send() (SMBtrans2:TRANSACT2_QPATHINFO) check for DFS...
[Samba.git] / source3 / smbd / uid.c
blob52918c4f1819cc371df971cb35e8c24687c1e538
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/passwd.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../librpc/gen_ndr/netlogon.h"
25 #include "libcli/security/security.h"
26 #include "passdb/lookup_sid.h"
27 #include "auth.h"
28 #include "../auth/auth_util.h"
29 #include "source3/lib/substitute.h"
31 /* what user is current? */
32 extern struct current_user current_user;
34 /****************************************************************************
35 Become the guest user without changing the security context stack.
36 ****************************************************************************/
38 bool change_to_guest(void)
40 struct passwd *pass;
42 pass = Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
43 if (!pass) {
44 return false;
47 #ifdef AIX
48 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
49 setting IDs */
50 initgroups(pass->pw_name, pass->pw_gid);
51 #endif
53 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
55 current_user.conn = NULL;
56 current_user.vuid = UID_FIELD_INVALID;
58 TALLOC_FREE(pass);
60 return true;
63 /****************************************************************************
64 talloc free the conn->session_info if not used in the vuid cache.
65 ****************************************************************************/
67 static void free_conn_session_info_if_unused(connection_struct *conn)
69 unsigned int i;
71 for (i = 0; i < VUID_CACHE_SIZE; i++) {
72 struct vuid_cache_entry *ent;
73 ent = &conn->vuid_cache->array[i];
74 if (ent->vuid != UID_FIELD_INVALID &&
75 conn->session_info == ent->session_info) {
76 return;
79 /* Not used, safe to free. */
80 TALLOC_FREE(conn->session_info);
83 /****************************************************************************
84 Setup the share access mask for a connection.
85 ****************************************************************************/
87 static uint32_t create_share_access_mask(int snum,
88 bool readonly_share,
89 const struct security_token *token)
91 uint32_t share_access = 0;
93 share_access_check(token,
94 lp_const_servicename(snum),
95 MAXIMUM_ALLOWED_ACCESS,
96 &share_access);
98 if (readonly_share) {
99 share_access &=
100 ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
101 SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
102 SEC_DIR_DELETE_CHILD );
105 if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
106 share_access |= SEC_FLAG_SYSTEM_SECURITY;
108 if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
109 share_access |= SEC_RIGHTS_PRIV_RESTORE;
111 if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
112 share_access |= SEC_RIGHTS_PRIV_BACKUP;
114 if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
115 share_access |= SEC_STD_WRITE_OWNER;
118 return share_access;
121 /*******************************************************************
122 Calculate access mask and if this user can access this share.
123 ********************************************************************/
125 NTSTATUS check_user_share_access(connection_struct *conn,
126 const struct auth_session_info *session_info,
127 uint32_t *p_share_access,
128 bool *p_readonly_share)
130 int snum = SNUM(conn);
131 uint32_t share_access = 0;
132 bool readonly_share = false;
134 if (!user_ok_token(session_info->unix_info->unix_name,
135 session_info->info->domain_name,
136 session_info->security_token, snum)) {
137 return NT_STATUS_ACCESS_DENIED;
140 readonly_share = is_share_read_only_for_token(
141 session_info->unix_info->unix_name,
142 session_info->info->domain_name,
143 session_info->security_token,
144 conn);
146 share_access = create_share_access_mask(snum,
147 readonly_share,
148 session_info->security_token);
150 if ((share_access & (FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
151 /* No access, read or write. */
152 DBG_NOTICE("user %s connection to %s denied due to share "
153 "security descriptor.\n",
154 session_info->unix_info->unix_name,
155 lp_const_servicename(snum));
156 return NT_STATUS_ACCESS_DENIED;
159 if (!readonly_share &&
160 !(share_access & FILE_WRITE_DATA)) {
161 /* smb.conf allows r/w, but the security descriptor denies
162 * write. Fall back to looking at readonly. */
163 readonly_share = true;
164 DBG_INFO("falling back to read-only access-evaluation due to "
165 "security descriptor\n");
168 *p_share_access = share_access;
169 *p_readonly_share = readonly_share;
171 return NT_STATUS_OK;
174 /*******************************************************************
175 Check if a username is OK.
177 This sets up conn->session_info with a copy related to this vuser that
178 later code can then mess with.
179 ********************************************************************/
181 static bool check_user_ok(connection_struct *conn,
182 uint64_t vuid,
183 const struct auth_session_info *session_info,
184 int snum)
186 unsigned int i;
187 bool readonly_share = false;
188 bool admin_user = false;
189 struct vuid_cache_entry *ent = NULL;
190 uint32_t share_access = 0;
191 NTSTATUS status;
193 for (i=0; i<VUID_CACHE_SIZE; i++) {
194 ent = &conn->vuid_cache->array[i];
195 if (ent->vuid == vuid) {
196 if (vuid == UID_FIELD_INVALID) {
198 * Slow path, we don't care
199 * about the array traversal.
201 continue;
203 free_conn_session_info_if_unused(conn);
204 conn->session_info = ent->session_info;
205 conn->read_only = ent->read_only;
206 conn->share_access = ent->share_access;
207 conn->vuid = ent->vuid;
208 return(True);
212 status = check_user_share_access(conn,
213 session_info,
214 &share_access,
215 &readonly_share);
216 if (!NT_STATUS_IS_OK(status)) {
217 return false;
220 admin_user = token_contains_name_in_list(
221 session_info->unix_info->unix_name,
222 session_info->info->domain_name,
223 NULL, session_info->security_token, lp_admin_users(snum));
225 ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry];
227 conn->vuid_cache->next_entry =
228 (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE;
230 TALLOC_FREE(ent->session_info);
233 * If force_user was set, all session_info's are based on the same
234 * username-based faked one.
237 ent->session_info = copy_session_info(
238 conn, conn->force_user ? conn->session_info : session_info);
240 if (ent->session_info == NULL) {
241 ent->vuid = UID_FIELD_INVALID;
242 return false;
245 if (admin_user) {
246 DEBUG(2,("check_user_ok: user %s is an admin user. "
247 "Setting uid as %d\n",
248 ent->session_info->unix_info->unix_name,
249 sec_initial_uid() ));
250 ent->session_info->unix_token->uid = sec_initial_uid();
254 * It's actually OK to call check_user_ok() with
255 * vuid == UID_FIELD_INVALID as called from become_user_by_session().
256 * All this will do is throw away one entry in the cache.
259 ent->vuid = vuid;
260 ent->read_only = readonly_share;
261 ent->share_access = share_access;
262 free_conn_session_info_if_unused(conn);
263 conn->session_info = ent->session_info;
264 conn->vuid = ent->vuid;
265 if (vuid == UID_FIELD_INVALID) {
267 * Not strictly needed, just make it really
268 * clear this entry is actually an unused one.
270 ent->read_only = false;
271 ent->share_access = 0;
272 ent->session_info = NULL;
275 conn->read_only = readonly_share;
276 conn->share_access = share_access;
278 return(True);
281 static void print_impersonation_info(connection_struct *conn)
283 struct smb_filename *cwdfname = NULL;
285 if (!CHECK_DEBUGLVL(DBGLVL_INFO)) {
286 return;
289 cwdfname = vfs_GetWd(talloc_tos(), conn);
290 if (cwdfname == NULL) {
291 return;
294 DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
295 (int)getuid(),
296 (int)geteuid(),
297 (int)getgid(),
298 (int)getegid(),
299 cwdfname->base_name);
300 TALLOC_FREE(cwdfname);
303 /****************************************************************************
304 Become the user of a connection number without changing the security context
305 stack, but modify the current_user entries.
306 ****************************************************************************/
308 static bool change_to_user_impersonate(connection_struct *conn,
309 const struct auth_session_info *session_info,
310 uint64_t vuid)
312 const struct loadparm_substitution *lp_sub =
313 loadparm_s3_global_substitution();
314 int snum;
315 gid_t gid;
316 uid_t uid;
317 const char *force_group_name;
318 char group_c;
319 int num_groups = 0;
320 gid_t *group_list = NULL;
321 bool ok;
323 if ((current_user.conn == conn) &&
324 (current_user.vuid == vuid) &&
325 (current_user.ut.uid == session_info->unix_token->uid))
327 DBG_INFO("Skipping user change - already user\n");
328 return true;
331 set_current_user_info(session_info->unix_info->sanitized_username,
332 session_info->unix_info->unix_name,
333 session_info->info->domain_name);
335 snum = SNUM(conn);
337 ok = check_user_ok(conn, vuid, session_info, snum);
338 if (!ok) {
339 DBG_WARNING("SMB user %s (unix user %s) "
340 "not permitted access to share %s.\n",
341 session_info->unix_info->sanitized_username,
342 session_info->unix_info->unix_name,
343 lp_const_servicename(snum));
344 return false;
347 uid = conn->session_info->unix_token->uid;
348 gid = conn->session_info->unix_token->gid;
349 num_groups = conn->session_info->unix_token->ngroups;
350 group_list = conn->session_info->unix_token->groups;
353 * See if we should force group for this service. If so this overrides
354 * any group set in the force user code.
356 force_group_name = lp_force_group(talloc_tos(), lp_sub, snum);
357 group_c = *force_group_name;
359 if ((group_c != '\0') && (conn->force_group_gid == (gid_t)-1)) {
361 * This can happen if "force group" is added to a
362 * share definition whilst an existing connection
363 * to that share exists. In that case, don't change
364 * the existing credentials for force group, only
365 * do so for new connections.
367 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
369 DBG_INFO("Not forcing group %s on existing connection to "
370 "share %s for SMB user %s (unix user %s)\n",
371 force_group_name,
372 lp_const_servicename(snum),
373 session_info->unix_info->sanitized_username,
374 session_info->unix_info->unix_name);
377 if((group_c != '\0') && (conn->force_group_gid != (gid_t)-1)) {
379 * Only force group for connections where
380 * conn->force_group_gid has already been set
381 * to the correct value (i.e. the connection
382 * happened after the 'force group' definition
383 * was added to the share definition. Connections
384 * that were made before force group was added
385 * should stay with their existing credentials.
387 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
390 if (group_c == '+') {
391 int i;
394 * Only force group if the user is a member of the
395 * service group. Check the group memberships for this
396 * user (we already have this) to see if we should force
397 * the group.
399 for (i = 0; i < num_groups; i++) {
400 if (group_list[i] == conn->force_group_gid) {
401 conn->session_info->unix_token->gid =
402 conn->force_group_gid;
403 gid = conn->force_group_gid;
404 gid_to_sid(&conn->session_info->security_token
405 ->sids[1], gid);
406 break;
409 } else {
410 conn->session_info->unix_token->gid = conn->force_group_gid;
411 gid = conn->force_group_gid;
412 gid_to_sid(&conn->session_info->security_token->sids[1],
413 gid);
417 set_sec_ctx(uid,
418 gid,
419 num_groups,
420 group_list,
421 conn->session_info->security_token);
423 current_user.conn = conn;
424 current_user.vuid = vuid;
425 return true;
429 * Impersonate user and change directory to service
431 * change_to_user_and_service() is used to impersonate the user associated with
432 * the given vuid and to change the working directory of the process to the
433 * service base directory.
435 bool change_to_user_and_service(connection_struct *conn, uint64_t vuid)
437 int snum = SNUM(conn);
438 struct auth_session_info *si = NULL;
439 NTSTATUS status;
440 bool ok;
442 if (conn == NULL) {
443 DBG_WARNING("Connection not open\n");
444 return false;
447 status = smbXsrv_session_info_lookup(conn->sconn->client,
448 vuid,
449 &si);
450 if (!NT_STATUS_IS_OK(status)) {
451 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
452 (unsigned long long)vuid,
453 lp_const_servicename(snum));
454 return false;
457 ok = change_to_user_impersonate(conn, si, vuid);
458 if (!ok) {
459 return false;
462 if (conn->tcon_done) {
463 ok = chdir_current_service(conn);
464 if (!ok) {
465 return false;
469 print_impersonation_info(conn);
470 return true;
474 * Impersonate user and change directory to service
476 * change_to_user_and_service_by_fsp() is used to impersonate the user
477 * associated with the given vuid and to change the working directory of the
478 * process to the service base directory.
480 bool change_to_user_and_service_by_fsp(struct files_struct *fsp)
482 return change_to_user_and_service(fsp->conn, fsp->vuid);
485 /****************************************************************************
486 Go back to being root without changing the security context stack,
487 but modify the current_user entries.
488 ****************************************************************************/
490 bool smbd_change_to_root_user(void)
492 set_root_sec_ctx();
494 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
495 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
497 current_user.conn = NULL;
498 current_user.vuid = UID_FIELD_INVALID;
500 return(True);
503 /****************************************************************************
504 Become the user of an authenticated connected named pipe.
505 When this is called we are currently running as the connection
506 user. Doesn't modify current_user.
507 ****************************************************************************/
509 bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
511 if (!push_sec_ctx())
512 return False;
514 set_current_user_info(session_info->unix_info->sanitized_username,
515 session_info->unix_info->unix_name,
516 session_info->info->domain_name);
518 set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
519 session_info->unix_token->ngroups, session_info->unix_token->groups,
520 session_info->security_token);
522 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
523 (int)getuid(),
524 (int)geteuid(),
525 (int)getgid(),
526 (int)getegid()));
528 return True;
531 /****************************************************************************
532 Unbecome the user of an authenticated connected named pipe.
533 When this is called we are running as the authenticated pipe
534 user and need to go back to being the connection user. Doesn't modify
535 current_user.
536 ****************************************************************************/
538 bool smbd_unbecome_authenticated_pipe_user(void)
540 return pop_sec_ctx();
543 /****************************************************************************
544 Utility functions used by become_xxx/unbecome_xxx.
545 ****************************************************************************/
547 static void push_conn_ctx(void)
549 struct conn_ctx *ctx_p;
550 extern userdom_struct current_user_info;
552 /* Check we don't overflow our stack */
554 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
555 DEBUG(0, ("Connection context stack overflow!\n"));
556 smb_panic("Connection context stack overflow!\n");
559 /* Store previous user context */
560 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
562 ctx_p->conn = current_user.conn;
563 ctx_p->vuid = current_user.vuid;
564 ctx_p->user_info = current_user_info;
566 DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
567 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
569 conn_ctx_stack_ndx++;
572 static void pop_conn_ctx(void)
574 struct conn_ctx *ctx_p;
576 /* Check for stack underflow. */
578 if (conn_ctx_stack_ndx == 0) {
579 DEBUG(0, ("Connection context stack underflow!\n"));
580 smb_panic("Connection context stack underflow!\n");
583 conn_ctx_stack_ndx--;
584 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
586 set_current_user_info(ctx_p->user_info.smb_name,
587 ctx_p->user_info.unix_name,
588 ctx_p->user_info.domain);
590 current_user.conn = ctx_p->conn;
591 current_user.vuid = ctx_p->vuid;
593 *ctx_p = (struct conn_ctx) {
594 .vuid = UID_FIELD_INVALID,
598 /****************************************************************************
599 Temporarily become a root user. Must match with unbecome_root(). Saves and
600 restores the connection context.
601 ****************************************************************************/
603 void smbd_become_root(void)
606 * no good way to handle push_sec_ctx() failing without changing
607 * the prototype of become_root()
609 if (!push_sec_ctx()) {
610 smb_panic("become_root: push_sec_ctx failed");
612 push_conn_ctx();
613 set_root_sec_ctx();
616 /* Unbecome the root user */
618 void smbd_unbecome_root(void)
620 pop_sec_ctx();
621 pop_conn_ctx();
624 /****************************************************************************
625 Push the current security context then force a change via change_to_user().
626 Saves and restores the connection context.
627 ****************************************************************************/
629 bool become_user_without_service(connection_struct *conn, uint64_t vuid)
631 struct auth_session_info *session_info = NULL;
632 int snum = SNUM(conn);
633 NTSTATUS status;
634 bool ok;
636 if (conn == NULL) {
637 DBG_WARNING("Connection not open\n");
638 return false;
641 status = smbXsrv_session_info_lookup(conn->sconn->client,
642 vuid,
643 &session_info);
644 if (!NT_STATUS_IS_OK(status)) {
645 /* Invalid vuid sent */
646 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
647 (unsigned long long)vuid,
648 lp_const_servicename(snum));
649 return false;
652 ok = push_sec_ctx();
653 if (!ok) {
654 return false;
657 push_conn_ctx();
659 ok = change_to_user_impersonate(conn, session_info, vuid);
660 if (!ok) {
661 pop_sec_ctx();
662 pop_conn_ctx();
663 return false;
666 return true;
669 bool become_user_without_service_by_fsp(struct files_struct *fsp)
671 return become_user_without_service(fsp->conn, fsp->vuid);
674 bool become_user_without_service_by_session(connection_struct *conn,
675 const struct auth_session_info *session_info)
677 bool ok;
679 SMB_ASSERT(conn != NULL);
680 SMB_ASSERT(session_info != NULL);
682 ok = push_sec_ctx();
683 if (!ok) {
684 return false;
687 push_conn_ctx();
689 ok = change_to_user_impersonate(conn, session_info, UID_FIELD_INVALID);
690 if (!ok) {
691 pop_sec_ctx();
692 pop_conn_ctx();
693 return false;
696 return true;
699 bool unbecome_user_without_service(void)
701 pop_sec_ctx();
702 pop_conn_ctx();
703 return True;
706 /****************************************************************************
707 Return the current user we are running effectively as on this connection.
708 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
709 doesn't alter this value.
710 ****************************************************************************/
712 uid_t get_current_uid(connection_struct *conn)
714 return current_user.ut.uid;
717 /****************************************************************************
718 Return the current group we are running effectively as on this connection.
719 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
720 doesn't alter this value.
721 ****************************************************************************/
723 gid_t get_current_gid(connection_struct *conn)
725 return current_user.ut.gid;
728 /****************************************************************************
729 Return the UNIX token we are running effectively as on this connection.
730 I'd like to make this return &conn->session_info->unix_token-> but become_root()
731 doesn't alter this value.
732 ****************************************************************************/
734 const struct security_unix_token *get_current_utok(connection_struct *conn)
736 return &current_user.ut;
739 /****************************************************************************
740 Return the Windows token we are running effectively as on this connection.
741 If this is currently a NULL token as we're inside become_root() - a temporary
742 UNIX security override, then we search up the stack for the previous active
743 token.
744 ****************************************************************************/
746 const struct security_token *get_current_nttok(connection_struct *conn)
748 if (current_user.nt_user_token) {
749 return current_user.nt_user_token;
751 return sec_ctx_active_token();