s4/selftest: Enable samba.tests.samba_tool.join for py3
[Samba.git] / source3 / smbd / uid.c
blob41bb66e2df1d3e42e350fa2f5559285d485be5dd
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/filesys.h"
22 #include "system/passwd.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../librpc/gen_ndr/netlogon.h"
26 #include "libcli/security/security.h"
27 #include "passdb/lookup_sid.h"
28 #include "auth.h"
29 #include "lib/util/time_basic.h"
30 #include "lib/pthreadpool/pthreadpool_tevent.h"
32 static struct smb_vfs_ev_glue *smbd_impersonate_user_ev_glue_create(
33 struct connection_struct *conn,
34 uint64_t vuid,
35 struct auth_session_info *session_info);
37 struct smbd_impersonate_debug_state {
38 int dbg_lvl;
39 const char *name;
42 static bool smbd_impersonate_debug_before_use(struct tevent_context *wrap_ev,
43 void *private_data,
44 struct tevent_context *main_ev,
45 const char *location)
47 struct smbd_impersonate_debug_state *state =
48 (struct smbd_impersonate_debug_state *)private_data;
50 DEBUG(state->dbg_lvl, (
51 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
52 __func__, state->name, wrap_ev, state, main_ev, location));
54 return true;
57 static void smbd_impersonate_debug_after_use(struct tevent_context *wrap_ev,
58 void *private_data,
59 struct tevent_context *main_ev,
60 const char *location)
62 struct smbd_impersonate_debug_state *state =
63 (struct smbd_impersonate_debug_state *)private_data;
65 DEBUG(state->dbg_lvl, (
66 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
67 __func__, state->name, wrap_ev, state, main_ev, location));
70 static void smbd_impersonate_debug_before_fd_handler(struct tevent_context *wrap_ev,
71 void *private_data,
72 struct tevent_context *main_ev,
73 struct tevent_fd *fde,
74 uint16_t flags,
75 const char *handler_name,
76 const char *location)
78 struct smbd_impersonate_debug_state *state =
79 (struct smbd_impersonate_debug_state *)private_data;
81 DEBUG(state->dbg_lvl, (
82 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
83 "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
84 __func__, state->name, wrap_ev, state, main_ev,
85 fde, flags, handler_name, location));
88 static void smbd_impersonate_debug_after_fd_handler(struct tevent_context *wrap_ev,
89 void *private_data,
90 struct tevent_context *main_ev,
91 struct tevent_fd *fde,
92 uint16_t flags,
93 const char *handler_name,
94 const char *location)
96 struct smbd_impersonate_debug_state *state =
97 (struct smbd_impersonate_debug_state *)private_data;
99 DEBUG(state->dbg_lvl, (
100 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
101 "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
102 __func__, state->name, wrap_ev, state, main_ev,
103 fde, flags, handler_name, location));
106 static void smbd_impersonate_debug_before_timer_handler(struct tevent_context *wrap_ev,
107 void *private_data,
108 struct tevent_context *main_ev,
109 struct tevent_timer *te,
110 struct timeval requested_time,
111 struct timeval trigger_time,
112 const char *handler_name,
113 const char *location)
115 struct smbd_impersonate_debug_state *state =
116 (struct smbd_impersonate_debug_state *)private_data;
117 struct timeval_buf requested_buf;
118 struct timeval_buf trigger_buf;
120 DEBUG(state->dbg_lvl, (
121 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
122 "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
123 __func__, state->name, wrap_ev, state, main_ev, te,
124 timeval_str_buf(&requested_time, true, true, &requested_buf),
125 timeval_str_buf(&trigger_time, true, true, &trigger_buf),
126 handler_name, location));
129 static void smbd_impersonate_debug_after_timer_handler(struct tevent_context *wrap_ev,
130 void *private_data,
131 struct tevent_context *main_ev,
132 struct tevent_timer *te,
133 struct timeval requested_time,
134 struct timeval trigger_time,
135 const char *handler_name,
136 const char *location)
138 struct smbd_impersonate_debug_state *state =
139 (struct smbd_impersonate_debug_state *)private_data;
140 struct timeval_buf requested_buf;
141 struct timeval_buf trigger_buf;
143 DEBUG(state->dbg_lvl, (
144 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
145 "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
146 __func__, state->name, wrap_ev, state, main_ev, te,
147 timeval_str_buf(&requested_time, true, true, &requested_buf),
148 timeval_str_buf(&trigger_time, true, true, &trigger_buf),
149 handler_name, location));
152 static void smbd_impersonate_debug_before_immediate_handler(struct tevent_context *wrap_ev,
153 void *private_data,
154 struct tevent_context *main_ev,
155 struct tevent_immediate *im,
156 const char *handler_name,
157 const char *location)
159 struct smbd_impersonate_debug_state *state =
160 (struct smbd_impersonate_debug_state *)private_data;
162 DEBUG(state->dbg_lvl, (
163 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
164 "im[%p] handler_name[%s] location[%s]\n",
165 __func__, state->name, wrap_ev, state, main_ev,
166 im, handler_name, location));
169 static void smbd_impersonate_debug_after_immediate_handler(struct tevent_context *wrap_ev,
170 void *private_data,
171 struct tevent_context *main_ev,
172 struct tevent_immediate *im,
173 const char *handler_name,
174 const char *location)
176 struct smbd_impersonate_debug_state *state =
177 (struct smbd_impersonate_debug_state *)private_data;
179 DEBUG(state->dbg_lvl, (
180 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
181 "im[%p] handler_name[%s] location[%s]\n",
182 __func__, state->name, wrap_ev, state, main_ev,
183 im, handler_name, location));
186 static void smbd_impersonate_debug_before_signal_handler(struct tevent_context *wrap_ev,
187 void *private_data,
188 struct tevent_context *main_ev,
189 struct tevent_signal *se,
190 int signum,
191 int count,
192 void *siginfo,
193 const char *handler_name,
194 const char *location)
196 struct smbd_impersonate_debug_state *state =
197 (struct smbd_impersonate_debug_state *)private_data;
199 DEBUG(state->dbg_lvl, (
200 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
201 "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
202 __func__, state->name, wrap_ev, state, main_ev,
203 se, signum, count, siginfo, handler_name, location));
206 static void smbd_impersonate_debug_after_signal_handler(struct tevent_context *wrap_ev,
207 void *private_data,
208 struct tevent_context *main_ev,
209 struct tevent_signal *se,
210 int signum,
211 int count,
212 void *siginfo,
213 const char *handler_name,
214 const char *location)
216 struct smbd_impersonate_debug_state *state =
217 (struct smbd_impersonate_debug_state *)private_data;
219 DEBUG(state->dbg_lvl, (
220 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
221 "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
222 __func__, state->name, wrap_ev, state, main_ev,
223 se, signum, count, siginfo, handler_name, location));
226 static const struct tevent_wrapper_ops smbd_impersonate_debug_ops = {
227 .name = "smbd_impersonate_debug",
228 .before_use = smbd_impersonate_debug_before_use,
229 .after_use = smbd_impersonate_debug_after_use,
230 .before_fd_handler = smbd_impersonate_debug_before_fd_handler,
231 .after_fd_handler = smbd_impersonate_debug_after_fd_handler,
232 .before_timer_handler = smbd_impersonate_debug_before_timer_handler,
233 .after_timer_handler = smbd_impersonate_debug_after_timer_handler,
234 .before_immediate_handler = smbd_impersonate_debug_before_immediate_handler,
235 .after_immediate_handler = smbd_impersonate_debug_after_immediate_handler,
236 .before_signal_handler = smbd_impersonate_debug_before_signal_handler,
237 .after_signal_handler = smbd_impersonate_debug_after_signal_handler,
240 struct tevent_context *_smbd_impersonate_debug_create(struct tevent_context *main_ev,
241 const char *name,
242 int dbg_lvl,
243 const char *location)
245 struct tevent_context *wrap_ev = NULL;
246 struct smbd_impersonate_debug_state *state = NULL;
248 wrap_ev = tevent_context_wrapper_create(main_ev,
249 main_ev,
250 &smbd_impersonate_debug_ops,
251 &state,
252 struct smbd_impersonate_debug_state);
253 if (wrap_ev == NULL) {
254 return NULL;
256 state->name = name;
257 state->dbg_lvl = dbg_lvl;
258 DEBUG(state->dbg_lvl, (
259 "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
260 __func__, state->name, wrap_ev, state, main_ev, location));
262 return wrap_ev;
265 /* what user is current? */
266 extern struct current_user current_user;
268 /****************************************************************************
269 Become the guest user without changing the security context stack.
270 ****************************************************************************/
272 bool change_to_guest(void)
274 struct passwd *pass;
276 pass = Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
277 if (!pass) {
278 return false;
281 #ifdef AIX
282 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
283 setting IDs */
284 initgroups(pass->pw_name, pass->pw_gid);
285 #endif
287 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
289 current_user.conn = NULL;
290 current_user.vuid = UID_FIELD_INVALID;
291 current_user.need_chdir = false;
292 current_user.done_chdir = false;
294 TALLOC_FREE(pass);
296 return true;
299 /****************************************************************************
300 talloc free the conn->session_info if not used in the vuid cache.
301 ****************************************************************************/
303 static void free_conn_session_info_if_unused(connection_struct *conn)
305 unsigned int i;
307 for (i = 0; i < VUID_CACHE_SIZE; i++) {
308 struct vuid_cache_entry *ent;
309 ent = &conn->vuid_cache->array[i];
310 if (ent->vuid != UID_FIELD_INVALID &&
311 conn->session_info == ent->session_info) {
312 return;
315 /* Not used, safe to free. */
316 conn->user_ev_ctx = NULL;
317 TALLOC_FREE(conn->user_vfs_evg);
318 TALLOC_FREE(conn->session_info);
321 /****************************************************************************
322 Setup the share access mask for a connection.
323 ****************************************************************************/
325 static uint32_t create_share_access_mask(int snum,
326 bool readonly_share,
327 const struct security_token *token)
329 uint32_t share_access = 0;
331 share_access_check(token,
332 lp_const_servicename(snum),
333 MAXIMUM_ALLOWED_ACCESS,
334 &share_access);
336 if (readonly_share) {
337 share_access &=
338 ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
339 SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
340 SEC_DIR_DELETE_CHILD );
343 if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
344 share_access |= SEC_FLAG_SYSTEM_SECURITY;
346 if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
347 share_access |= SEC_RIGHTS_PRIV_RESTORE;
349 if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
350 share_access |= SEC_RIGHTS_PRIV_BACKUP;
352 if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
353 share_access |= SEC_STD_WRITE_OWNER;
356 return share_access;
359 /*******************************************************************
360 Calculate access mask and if this user can access this share.
361 ********************************************************************/
363 NTSTATUS check_user_share_access(connection_struct *conn,
364 const struct auth_session_info *session_info,
365 uint32_t *p_share_access,
366 bool *p_readonly_share)
368 int snum = SNUM(conn);
369 uint32_t share_access = 0;
370 bool readonly_share = false;
372 if (!user_ok_token(session_info->unix_info->unix_name,
373 session_info->info->domain_name,
374 session_info->security_token, snum)) {
375 return NT_STATUS_ACCESS_DENIED;
378 readonly_share = is_share_read_only_for_token(
379 session_info->unix_info->unix_name,
380 session_info->info->domain_name,
381 session_info->security_token,
382 conn);
384 share_access = create_share_access_mask(snum,
385 readonly_share,
386 session_info->security_token);
388 if ((share_access & (FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
389 /* No access, read or write. */
390 DBG_NOTICE("user %s connection to %s denied due to share "
391 "security descriptor.\n",
392 session_info->unix_info->unix_name,
393 lp_const_servicename(snum));
394 return NT_STATUS_ACCESS_DENIED;
397 if (!readonly_share &&
398 !(share_access & FILE_WRITE_DATA)) {
399 /* smb.conf allows r/w, but the security descriptor denies
400 * write. Fall back to looking at readonly. */
401 readonly_share = true;
402 DBG_INFO("falling back to read-only access-evaluation due to "
403 "security descriptor\n");
406 *p_share_access = share_access;
407 *p_readonly_share = readonly_share;
409 return NT_STATUS_OK;
412 /*******************************************************************
413 Check if a username is OK.
415 This sets up conn->session_info with a copy related to this vuser that
416 later code can then mess with.
417 ********************************************************************/
419 static bool check_user_ok(connection_struct *conn,
420 uint64_t vuid,
421 const struct auth_session_info *session_info,
422 int snum)
424 unsigned int i;
425 bool readonly_share = false;
426 bool admin_user = false;
427 struct vuid_cache_entry *ent = NULL;
428 uint32_t share_access = 0;
429 NTSTATUS status;
431 for (i=0; i<VUID_CACHE_SIZE; i++) {
432 ent = &conn->vuid_cache->array[i];
433 if (ent->vuid == vuid) {
434 if (vuid == UID_FIELD_INVALID) {
436 * Slow path, we don't care
437 * about the array traversal.
439 continue;
441 free_conn_session_info_if_unused(conn);
442 conn->session_info = ent->session_info;
443 conn->user_vfs_evg = ent->user_vfs_evg;
444 conn->read_only = ent->read_only;
445 conn->share_access = ent->share_access;
446 conn->vuid = ent->vuid;
447 conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(
448 conn->user_vfs_evg);
449 SMB_ASSERT(conn->user_ev_ctx != NULL);
450 return(True);
454 status = check_user_share_access(conn,
455 session_info,
456 &share_access,
457 &readonly_share);
458 if (!NT_STATUS_IS_OK(status)) {
459 return false;
462 admin_user = token_contains_name_in_list(
463 session_info->unix_info->unix_name,
464 session_info->info->domain_name,
465 NULL, session_info->security_token, lp_admin_users(snum));
467 ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry];
469 conn->vuid_cache->next_entry =
470 (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE;
472 TALLOC_FREE(ent->session_info);
475 * If force_user was set, all session_info's are based on the same
476 * username-based faked one.
479 ent->session_info = copy_session_info(
480 conn, conn->force_user ? conn->session_info : session_info);
482 if (ent->session_info == NULL) {
483 ent->vuid = UID_FIELD_INVALID;
484 return false;
487 if (admin_user) {
488 DEBUG(2,("check_user_ok: user %s is an admin user. "
489 "Setting uid as %d\n",
490 ent->session_info->unix_info->unix_name,
491 sec_initial_uid() ));
492 ent->session_info->unix_token->uid = sec_initial_uid();
495 ent->user_vfs_evg = smbd_impersonate_user_ev_glue_create(conn,
496 vuid, ent->session_info);
497 if (ent->user_vfs_evg == NULL) {
498 TALLOC_FREE(ent->session_info);
499 ent->vuid = UID_FIELD_INVALID;
500 return false;
504 * It's actually OK to call check_user_ok() with
505 * vuid == UID_FIELD_INVALID as called from change_to_user_by_session().
506 * All this will do is throw away one entry in the cache.
509 ent->vuid = vuid;
510 ent->read_only = readonly_share;
511 ent->share_access = share_access;
512 free_conn_session_info_if_unused(conn);
513 conn->session_info = ent->session_info;
514 conn->vuid = ent->vuid;
515 conn->user_vfs_evg = ent->user_vfs_evg;
516 conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(conn->user_vfs_evg);
517 SMB_ASSERT(conn->user_ev_ctx != NULL);
519 if (vuid == UID_FIELD_INVALID) {
521 * Not strictly needed, just make it really
522 * clear this entry is actually an unused one.
524 ent->read_only = false;
525 ent->share_access = 0;
526 ent->session_info = NULL;
527 ent->user_vfs_evg = NULL;
530 conn->read_only = readonly_share;
531 conn->share_access = share_access;
533 return(True);
536 /****************************************************************************
537 Become the user of a connection number without changing the security context
538 stack, but modify the current_user entries.
539 ****************************************************************************/
541 static bool change_to_user_internal(connection_struct *conn,
542 const struct auth_session_info *session_info,
543 uint64_t vuid)
545 int snum;
546 gid_t gid;
547 uid_t uid;
548 char group_c;
549 int num_groups = 0;
550 gid_t *group_list = NULL;
551 bool ok;
553 if ((current_user.conn == conn) &&
554 (current_user.vuid == vuid) &&
555 (current_user.need_chdir == conn->tcon_done) &&
556 (current_user.ut.uid == session_info->unix_token->uid))
558 DBG_INFO("Skipping user change - already user\n");
559 return true;
562 set_current_user_info(session_info->unix_info->sanitized_username,
563 session_info->unix_info->unix_name,
564 session_info->info->domain_name);
566 snum = SNUM(conn);
568 ok = check_user_ok(conn, vuid, session_info, snum);
569 if (!ok) {
570 DBG_WARNING("SMB user %s (unix user %s) "
571 "not permitted access to share %s.\n",
572 session_info->unix_info->sanitized_username,
573 session_info->unix_info->unix_name,
574 lp_const_servicename(snum));
575 return false;
578 uid = conn->session_info->unix_token->uid;
579 gid = conn->session_info->unix_token->gid;
580 num_groups = conn->session_info->unix_token->ngroups;
581 group_list = conn->session_info->unix_token->groups;
584 * See if we should force group for this service. If so this overrides
585 * any group set in the force user code.
587 if((group_c = *lp_force_group(talloc_tos(), snum))) {
589 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
591 if (group_c == '+') {
592 int i;
595 * Only force group if the user is a member of the
596 * service group. Check the group memberships for this
597 * user (we already have this) to see if we should force
598 * the group.
600 for (i = 0; i < num_groups; i++) {
601 if (group_list[i] == conn->force_group_gid) {
602 conn->session_info->unix_token->gid =
603 conn->force_group_gid;
604 gid = conn->force_group_gid;
605 gid_to_sid(&conn->session_info->security_token
606 ->sids[1], gid);
607 break;
610 } else {
611 conn->session_info->unix_token->gid = conn->force_group_gid;
612 gid = conn->force_group_gid;
613 gid_to_sid(&conn->session_info->security_token->sids[1],
614 gid);
618 /*Set current_user since we will immediately also call set_sec_ctx() */
619 current_user.ut.ngroups = num_groups;
620 current_user.ut.groups = group_list;
622 set_sec_ctx(uid,
623 gid,
624 current_user.ut.ngroups,
625 current_user.ut.groups,
626 conn->session_info->security_token);
628 current_user.conn = conn;
629 current_user.vuid = vuid;
630 current_user.need_chdir = conn->tcon_done;
632 if (current_user.need_chdir) {
633 ok = chdir_current_service(conn);
634 if (!ok) {
635 DBG_ERR("chdir_current_service() failed!\n");
636 return false;
638 current_user.done_chdir = true;
641 if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
642 struct smb_filename *cwdfname = vfs_GetWd(talloc_tos(), conn);
643 if (cwdfname == NULL) {
644 return false;
646 DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
647 (int)getuid(),
648 (int)geteuid(),
649 (int)getgid(),
650 (int)getegid(),
651 cwdfname->base_name);
652 TALLOC_FREE(cwdfname);
655 return true;
658 bool change_to_user(connection_struct *conn, uint64_t vuid)
660 struct user_struct *vuser;
661 int snum = SNUM(conn);
663 if (!conn) {
664 DEBUG(2,("Connection not open\n"));
665 return(False);
668 vuser = get_valid_user_struct(conn->sconn, vuid);
669 if (vuser == NULL) {
670 /* Invalid vuid sent */
671 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
672 (unsigned long long)vuid,
673 lp_const_servicename(snum));
674 return false;
677 return change_to_user_internal(conn, vuser->session_info, vuid);
680 bool change_to_user_by_fsp(struct files_struct *fsp)
682 return change_to_user(fsp->conn, fsp->vuid);
685 static bool change_to_user_by_session(connection_struct *conn,
686 const struct auth_session_info *session_info)
688 SMB_ASSERT(conn != NULL);
689 SMB_ASSERT(session_info != NULL);
691 return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
694 /****************************************************************************
695 Go back to being root without changing the security context stack,
696 but modify the current_user entries.
697 ****************************************************************************/
699 bool smbd_change_to_root_user(void)
701 set_root_sec_ctx();
703 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
704 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
706 current_user.conn = NULL;
707 current_user.vuid = UID_FIELD_INVALID;
708 current_user.need_chdir = false;
709 current_user.done_chdir = false;
711 return(True);
714 /****************************************************************************
715 Become the user of an authenticated connected named pipe.
716 When this is called we are currently running as the connection
717 user. Doesn't modify current_user.
718 ****************************************************************************/
720 bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
722 if (!push_sec_ctx())
723 return False;
725 set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
726 session_info->unix_token->ngroups, session_info->unix_token->groups,
727 session_info->security_token);
729 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
730 (int)getuid(),
731 (int)geteuid(),
732 (int)getgid(),
733 (int)getegid()));
735 return True;
738 /****************************************************************************
739 Unbecome the user of an authenticated connected named pipe.
740 When this is called we are running as the authenticated pipe
741 user and need to go back to being the connection user. Doesn't modify
742 current_user.
743 ****************************************************************************/
745 bool smbd_unbecome_authenticated_pipe_user(void)
747 return pop_sec_ctx();
750 /****************************************************************************
751 Utility functions used by become_xxx/unbecome_xxx.
752 ****************************************************************************/
754 static void push_conn_ctx(void)
756 struct conn_ctx *ctx_p;
757 extern userdom_struct current_user_info;
759 /* Check we don't overflow our stack */
761 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
762 DEBUG(0, ("Connection context stack overflow!\n"));
763 smb_panic("Connection context stack overflow!\n");
766 /* Store previous user context */
767 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
769 ctx_p->conn = current_user.conn;
770 ctx_p->vuid = current_user.vuid;
771 ctx_p->need_chdir = current_user.need_chdir;
772 ctx_p->done_chdir = current_user.done_chdir;
773 ctx_p->user_info = current_user_info;
775 DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
776 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
778 conn_ctx_stack_ndx++;
781 static void pop_conn_ctx(void)
783 struct conn_ctx *ctx_p;
785 /* Check for stack underflow. */
787 if (conn_ctx_stack_ndx == 0) {
788 DEBUG(0, ("Connection context stack underflow!\n"));
789 smb_panic("Connection context stack underflow!\n");
792 conn_ctx_stack_ndx--;
793 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
795 set_current_user_info(ctx_p->user_info.smb_name,
796 ctx_p->user_info.unix_name,
797 ctx_p->user_info.domain);
800 * Check if the current context did a chdir_current_service()
801 * and restore the cwd_fname of the previous context
802 * if needed.
804 if (current_user.done_chdir && ctx_p->need_chdir) {
805 int ret;
807 ret = vfs_ChDir(ctx_p->conn, ctx_p->conn->cwd_fname);
808 if (ret != 0) {
809 DBG_ERR("vfs_ChDir() failed!\n");
810 smb_panic("vfs_ChDir() failed!\n");
814 current_user.conn = ctx_p->conn;
815 current_user.vuid = ctx_p->vuid;
816 current_user.need_chdir = ctx_p->need_chdir;
817 current_user.done_chdir = ctx_p->done_chdir;
819 *ctx_p = (struct conn_ctx) {
820 .vuid = UID_FIELD_INVALID,
824 /****************************************************************************
825 Temporarily become a root user. Must match with unbecome_root(). Saves and
826 restores the connection context.
827 ****************************************************************************/
829 void smbd_become_root(void)
832 * no good way to handle push_sec_ctx() failing without changing
833 * the prototype of become_root()
835 if (!push_sec_ctx()) {
836 smb_panic("become_root: push_sec_ctx failed");
838 push_conn_ctx();
839 set_root_sec_ctx();
842 /* Unbecome the root user */
844 void smbd_unbecome_root(void)
846 pop_sec_ctx();
847 pop_conn_ctx();
850 bool become_guest(void)
852 bool ok;
854 ok = push_sec_ctx();
855 if (!ok) {
856 return false;
859 push_conn_ctx();
861 ok = change_to_guest();
862 if (!ok) {
863 pop_sec_ctx();
864 pop_conn_ctx();
865 return false;
868 return true;
871 void unbecome_guest(void)
873 pop_sec_ctx();
874 pop_conn_ctx();
875 return;
878 /****************************************************************************
879 Push the current security context then force a change via change_to_user().
880 Saves and restores the connection context.
881 ****************************************************************************/
883 bool become_user(connection_struct *conn, uint64_t vuid)
885 if (!push_sec_ctx())
886 return False;
888 push_conn_ctx();
890 if (!change_to_user(conn, vuid)) {
891 pop_sec_ctx();
892 pop_conn_ctx();
893 return False;
896 return True;
899 bool become_user_by_fsp(struct files_struct *fsp)
901 return become_user(fsp->conn, fsp->vuid);
904 bool become_user_by_session(connection_struct *conn,
905 const struct auth_session_info *session_info)
907 if (!push_sec_ctx())
908 return false;
910 push_conn_ctx();
912 if (!change_to_user_by_session(conn, session_info)) {
913 pop_sec_ctx();
914 pop_conn_ctx();
915 return false;
918 return true;
921 bool unbecome_user(void)
923 pop_sec_ctx();
924 pop_conn_ctx();
925 return True;
928 /****************************************************************************
929 Return the current user we are running effectively as on this connection.
930 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
931 doesn't alter this value.
932 ****************************************************************************/
934 uid_t get_current_uid(connection_struct *conn)
936 return current_user.ut.uid;
939 /****************************************************************************
940 Return the current group we are running effectively as on this connection.
941 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
942 doesn't alter this value.
943 ****************************************************************************/
945 gid_t get_current_gid(connection_struct *conn)
947 return current_user.ut.gid;
950 /****************************************************************************
951 Return the UNIX token we are running effectively as on this connection.
952 I'd like to make this return &conn->session_info->unix_token-> but become_root()
953 doesn't alter this value.
954 ****************************************************************************/
956 const struct security_unix_token *get_current_utok(connection_struct *conn)
958 return &current_user.ut;
961 /****************************************************************************
962 Return the Windows token we are running effectively as on this connection.
963 If this is currently a NULL token as we're inside become_root() - a temporary
964 UNIX security override, then we search up the stack for the previous active
965 token.
966 ****************************************************************************/
968 const struct security_token *get_current_nttok(connection_struct *conn)
970 if (current_user.nt_user_token) {
971 return current_user.nt_user_token;
973 return sec_ctx_active_token();
976 uint64_t get_current_vuid(connection_struct *conn)
978 return current_user.vuid;
981 struct smbd_impersonate_conn_vuid_state {
982 struct connection_struct *conn;
983 uint64_t vuid;
986 static bool smbd_impersonate_conn_vuid_before_use(
987 struct tevent_context *wrap_ev,
988 void *private_data,
989 struct tevent_context *main_ev,
990 const char *location)
992 struct smbd_impersonate_conn_vuid_state *state =
993 talloc_get_type_abort(private_data,
994 struct smbd_impersonate_conn_vuid_state);
995 bool ok;
997 DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
998 "old uid[%ju] old gid[%ju] vuid[%ju] cwd[%s]\n",
999 __func__, wrap_ev, main_ev, location,
1000 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1001 (uintmax_t)state->vuid, state->conn->cwd_fname->base_name));
1003 ok = become_user(state->conn, state->vuid);
1004 if (!ok) {
1005 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1006 return false;
1009 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1010 __func__, state->conn->session_info->unix_info->unix_name,
1011 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1012 state->conn->cwd_fname->base_name));
1014 return true;
1017 static void smbd_impersonate_conn_vuid_after_use(
1018 struct tevent_context *wrap_ev,
1019 void *private_data,
1020 struct tevent_context *main_ev,
1021 const char *location)
1023 struct smbd_impersonate_conn_vuid_state *state =
1024 talloc_get_type_abort(private_data,
1025 struct smbd_impersonate_conn_vuid_state);
1026 bool ok;
1028 DEBUG(11,("%s: deimpersonating[%s] uid[%ju] gid[%ju] cwd[%s] "
1029 "location[%s]\n",
1030 __func__, state->conn->session_info->unix_info->unix_name,
1031 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1032 state->conn->cwd_fname->base_name, location));
1034 ok = unbecome_user();
1035 if (!ok) {
1036 smb_panic("smbd_impersonate_conn_vuid_after_use() - failed");
1037 return;
1040 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1041 __func__, state->conn->session_info->unix_info->unix_name,
1042 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1043 state->conn->cwd_fname->base_name));
1046 static void smbd_impersonate_conn_vuid_before_fd_handler(
1047 struct tevent_context *wrap_ev,
1048 void *private_data,
1049 struct tevent_context *main_ev,
1050 struct tevent_fd *fde,
1051 uint16_t flags,
1052 const char *handler_name,
1053 const char *location)
1055 struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1056 private_data, struct smbd_impersonate_conn_vuid_state);
1057 bool ok;
1059 DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1060 __func__, fde, (uintmax_t)flags, handler_name, location));
1062 ok = change_to_user(state->conn, state->vuid);
1063 if (!ok) {
1064 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1065 return;
1068 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1069 __func__, state->conn->session_info->unix_info->unix_name,
1070 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1071 state->conn->cwd_fname->base_name));
1074 static void smbd_impersonate_conn_vuid_after_fd_handler(
1075 struct tevent_context *wrap_ev,
1076 void *private_data,
1077 struct tevent_context *main_ev,
1078 struct tevent_fd *fde,
1079 uint16_t flags,
1080 const char *handler_name,
1081 const char *location)
1083 DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1084 __func__, fde, handler_name, location));
1086 /* be lazy and defer change_to_root_user() */
1089 static void smbd_impersonate_conn_vuid_before_timer_handler(
1090 struct tevent_context *wrap_ev,
1091 void *private_data,
1092 struct tevent_context *main_ev,
1093 struct tevent_timer *te,
1094 struct timeval requested_time,
1095 struct timeval trigger_time,
1096 const char *handler_name,
1097 const char *location)
1099 struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1100 private_data, struct smbd_impersonate_conn_vuid_state);
1101 struct timeval_buf requested_buf;
1102 struct timeval_buf trigger_buf;
1103 bool ok;
1105 DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1106 "handler_name[%s] location[%s]\n",
1107 __func__, te,
1108 timeval_str_buf(&requested_time, true, true, &requested_buf),
1109 timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1110 handler_name, location));
1112 ok = change_to_user(state->conn, state->vuid);
1113 if (!ok) {
1114 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1115 return;
1118 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1119 __func__, state->conn->session_info->unix_info->unix_name,
1120 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1121 state->conn->cwd_fname->base_name));
1124 static void smbd_impersonate_conn_vuid_after_timer_handler(
1125 struct tevent_context *wrap_ev,
1126 void *private_data,
1127 struct tevent_context *main_ev,
1128 struct tevent_timer *te,
1129 struct timeval requested_time,
1130 struct timeval trigger_time,
1131 const char *handler_name,
1132 const char *location)
1134 DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1135 __func__, te, handler_name, location));
1137 /* be lazy and defer change_to_root_user() */
1140 static void smbd_impersonate_conn_vuid_before_immediate_handler(
1141 struct tevent_context *wrap_ev,
1142 void *private_data,
1143 struct tevent_context *main_ev,
1144 struct tevent_immediate *im,
1145 const char *handler_name,
1146 const char *location)
1148 struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1149 private_data, struct smbd_impersonate_conn_vuid_state);
1150 bool ok;
1152 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1153 __func__, im, handler_name, location));
1155 ok = change_to_user(state->conn, state->vuid);
1156 if (!ok) {
1157 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1158 return;
1161 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1162 __func__, state->conn->session_info->unix_info->unix_name,
1163 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1164 state->conn->cwd_fname->base_name));
1167 static void smbd_impersonate_conn_vuid_after_immediate_handler(
1168 struct tevent_context *wrap_ev,
1169 void *private_data,
1170 struct tevent_context *main_ev,
1171 struct tevent_immediate *im,
1172 const char *handler_name,
1173 const char *location)
1175 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1176 __func__, im, handler_name, location));
1178 /* be lazy and defer unbecome_user() */
1181 static void smbd_impersonate_conn_vuid_before_signal_handler(
1182 struct tevent_context *wrap_ev,
1183 void *private_data,
1184 struct tevent_context *main_ev,
1185 struct tevent_signal *se,
1186 int signum,
1187 int count,
1188 void *siginfo,
1189 const char *handler_name,
1190 const char *location)
1192 struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1193 private_data, struct smbd_impersonate_conn_vuid_state);
1194 bool ok;
1196 DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1197 "handler_name[%s] location[%s]\n",
1198 __func__, se, signum, count, siginfo, handler_name, location));
1200 ok = change_to_user(state->conn, state->vuid);
1201 if (!ok) {
1202 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1203 return;
1206 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1207 __func__, state->conn->session_info->unix_info->unix_name,
1208 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1209 state->conn->cwd_fname->base_name));
1212 static void smbd_impersonate_conn_vuid_after_signal_handler(
1213 struct tevent_context *wrap_ev,
1214 void *private_data,
1215 struct tevent_context *main_ev,
1216 struct tevent_signal *se,
1217 int signum,
1218 int count,
1219 void *siginfo,
1220 const char *handler_name,
1221 const char *location)
1223 DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1224 __func__, se, handler_name, location));
1226 /* be lazy and defer change_to_root_user() */
1229 static const struct tevent_wrapper_ops smbd_impersonate_conn_vuid_ops = {
1230 .name = "smbd_impersonate_conn_vuid",
1231 .before_use = smbd_impersonate_conn_vuid_before_use,
1232 .after_use = smbd_impersonate_conn_vuid_after_use,
1233 .before_fd_handler = smbd_impersonate_conn_vuid_before_fd_handler,
1234 .after_fd_handler = smbd_impersonate_conn_vuid_after_fd_handler,
1235 .before_timer_handler = smbd_impersonate_conn_vuid_before_timer_handler,
1236 .after_timer_handler = smbd_impersonate_conn_vuid_after_timer_handler,
1237 .before_immediate_handler = smbd_impersonate_conn_vuid_before_immediate_handler,
1238 .after_immediate_handler = smbd_impersonate_conn_vuid_after_immediate_handler,
1239 .before_signal_handler = smbd_impersonate_conn_vuid_before_signal_handler,
1240 .after_signal_handler = smbd_impersonate_conn_vuid_after_signal_handler,
1243 struct tevent_context *smbd_impersonate_conn_vuid_create(
1244 struct tevent_context *main_ev,
1245 struct connection_struct *conn,
1246 uint64_t vuid)
1248 struct tevent_context *ev = NULL;
1249 struct smbd_impersonate_conn_vuid_state *state = NULL;
1251 ev = tevent_context_wrapper_create(main_ev,
1252 conn,
1253 &smbd_impersonate_conn_vuid_ops,
1254 &state,
1255 struct smbd_impersonate_conn_vuid_state);
1256 if (ev == NULL) {
1257 return NULL;
1259 state->conn = conn;
1260 state->vuid = vuid;
1262 return ev;
1265 struct smbd_impersonate_conn_sess_state {
1266 struct connection_struct *conn;
1267 struct auth_session_info *session_info;
1270 static bool smbd_impersonate_conn_sess_before_use(struct tevent_context *wrap_ev,
1271 void *private_data,
1272 struct tevent_context *main_ev,
1273 const char *location)
1275 struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1276 private_data, struct smbd_impersonate_conn_sess_state);
1277 bool ok;
1279 DEBUG(11,("%s: impersonating user[%s] wrap_ev[%p] main_ev[%p] "
1280 "location[%s] old uid[%ju] old gid[%ju] cwd[%s]\n",
1281 __func__, state->session_info->unix_info->unix_name,
1282 wrap_ev, main_ev, location,
1283 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1284 state->conn->cwd_fname->base_name));
1286 ok = become_user_by_session(state->conn, state->session_info);
1287 if (!ok) {
1288 return false;
1291 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1292 __func__, state->conn->session_info->unix_info->unix_name,
1293 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1294 state->conn->cwd_fname->base_name));
1296 return true;
1299 static void smbd_impersonate_conn_sess_after_use(struct tevent_context *wrap_ev,
1300 void *private_data,
1301 struct tevent_context *main_ev,
1302 const char *location)
1304 struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1305 private_data, struct smbd_impersonate_conn_sess_state);
1306 bool ok;
1308 DEBUG(11,("%s: deimpersonating[%s] uid[%ju] gid[%ju] cwd[%s] "
1309 "location[%s]\n",
1310 __func__, state->session_info->unix_info->unix_name,
1311 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1312 state->conn->cwd_fname->base_name, location));
1314 ok = unbecome_user();
1315 if (!ok) {
1316 smb_panic("smbd_impersonate_conn_sess_after_use() - failed");
1317 return;
1320 DEBUG(11,("%s: deimpersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1321 __func__, state->conn->session_info->unix_info->unix_name,
1322 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1323 state->conn->cwd_fname->base_name));
1326 static void smbd_impersonate_conn_sess_before_fd_handler(
1327 struct tevent_context *wrap_ev,
1328 void *private_data,
1329 struct tevent_context *main_ev,
1330 struct tevent_fd *fde,
1331 uint16_t flags,
1332 const char *handler_name,
1333 const char *location)
1335 struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1336 private_data, struct smbd_impersonate_conn_sess_state);
1337 bool ok;
1339 DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1340 __func__, fde, (uintmax_t)flags, handler_name, location));
1342 ok = change_to_user_by_session(state->conn, state->session_info);
1343 if (!ok) {
1344 smb_panic("smbd_impersonate_conn_sess_before_fd_handler failed");
1345 return;
1348 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1349 __func__, state->conn->session_info->unix_info->unix_name,
1350 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1351 state->conn->cwd_fname->base_name));
1354 static void smbd_impersonate_conn_sess_after_fd_handler(struct tevent_context *wrap_ev,
1355 void *private_data,
1356 struct tevent_context *main_ev,
1357 struct tevent_fd *fde,
1358 uint16_t flags,
1359 const char *handler_name,
1360 const char *location)
1362 DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1363 __func__, fde, handler_name, location));
1365 /* be lazy and defer change_to_root_user() */
1368 static void smbd_impersonate_conn_sess_before_timer_handler(
1369 struct tevent_context *wrap_ev,
1370 void *private_data,
1371 struct tevent_context *main_ev,
1372 struct tevent_timer *te,
1373 struct timeval requested_time,
1374 struct timeval trigger_time,
1375 const char *handler_name,
1376 const char *location)
1378 struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1379 private_data, struct smbd_impersonate_conn_sess_state);
1380 struct timeval_buf requested_buf;
1381 struct timeval_buf trigger_buf;
1382 bool ok;
1384 DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1385 "handler_name[%s] location[%s]\n",
1386 __func__, te,
1387 timeval_str_buf(&requested_time, true, true, &requested_buf),
1388 timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1389 handler_name, location));
1391 ok = change_to_user_by_session(state->conn, state->session_info);
1392 if (!ok) {
1393 smb_panic("smbd_impersonate_conn_sess_before_tm_handler failed");
1394 return;
1397 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1398 __func__, state->conn->session_info->unix_info->unix_name,
1399 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1400 state->conn->cwd_fname->base_name));
1403 static void smbd_impersonate_conn_sess_after_timer_handler(
1404 struct tevent_context *wrap_ev,
1405 void *private_data,
1406 struct tevent_context *main_ev,
1407 struct tevent_timer *te,
1408 struct timeval requested_time,
1409 struct timeval trigger_time,
1410 const char *handler_name,
1411 const char *location)
1413 DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1414 __func__, te, handler_name, location));
1416 /* be lazy and defer change_to_root_user() */
1419 static void smbd_impersonate_conn_sess_before_immediate_handler(
1420 struct tevent_context *wrap_ev,
1421 void *private_data,
1422 struct tevent_context *main_ev,
1423 struct tevent_immediate *im,
1424 const char *handler_name,
1425 const char *location)
1427 struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1428 private_data, struct smbd_impersonate_conn_sess_state);
1429 bool ok;
1431 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1432 __func__, im, handler_name, location));
1434 ok = change_to_user_by_session(state->conn, state->session_info);
1435 if (!ok) {
1436 smb_panic("smbd_impersonate_conn_sess_before_im_handler failed");
1437 return;
1440 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1441 __func__, state->conn->session_info->unix_info->unix_name,
1442 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1443 state->conn->cwd_fname->base_name));
1446 static void smbd_impersonate_conn_sess_after_immediate_handler(
1447 struct tevent_context *wrap_ev,
1448 void *private_data,
1449 struct tevent_context *main_ev,
1450 struct tevent_immediate *im,
1451 const char *handler_name,
1452 const char *location)
1454 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1455 __func__, im, handler_name, location));
1457 /* be lazy and defer unbecome_user() */
1460 static void smbd_impersonate_conn_sess_before_signal_handler(
1461 struct tevent_context *wrap_ev,
1462 void *private_data,
1463 struct tevent_context *main_ev,
1464 struct tevent_signal *se,
1465 int signum,
1466 int count,
1467 void *siginfo,
1468 const char *handler_name,
1469 const char *location)
1471 struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1472 private_data, struct smbd_impersonate_conn_sess_state);
1473 bool ok;
1475 DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1476 "handler_name[%s] location[%s]\n",
1477 __func__, se, signum, count, siginfo, handler_name, location));
1479 ok = change_to_user_by_session(state->conn, state->session_info);
1480 if (!ok) {
1481 smb_panic("smbd_impersonate_conn_sess_before_si_handler failed");
1482 return;
1485 DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1486 __func__, state->conn->session_info->unix_info->unix_name,
1487 (uintmax_t)geteuid(), (uintmax_t)getegid(),
1488 state->conn->cwd_fname->base_name));
1491 static void smbd_impersonate_conn_sess_after_signal_handler(
1492 struct tevent_context *wrap_ev,
1493 void *private_data,
1494 struct tevent_context *main_ev,
1495 struct tevent_signal *se,
1496 int signum,
1497 int count,
1498 void *siginfo,
1499 const char *handler_name,
1500 const char *location)
1502 DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1503 __func__, se, handler_name, location));
1505 /* be lazy and defer change_to_root_user() */
1508 static const struct tevent_wrapper_ops smbd_impersonate_conn_sess_ops = {
1509 .name = "smbd_impersonate_conn_sess",
1510 .before_use = smbd_impersonate_conn_sess_before_use,
1511 .after_use = smbd_impersonate_conn_sess_after_use,
1512 .before_fd_handler = smbd_impersonate_conn_sess_before_fd_handler,
1513 .after_fd_handler = smbd_impersonate_conn_sess_after_fd_handler,
1514 .before_timer_handler = smbd_impersonate_conn_sess_before_timer_handler,
1515 .after_timer_handler = smbd_impersonate_conn_sess_after_timer_handler,
1516 .before_immediate_handler = smbd_impersonate_conn_sess_before_immediate_handler,
1517 .after_immediate_handler = smbd_impersonate_conn_sess_after_immediate_handler,
1518 .before_signal_handler = smbd_impersonate_conn_sess_before_signal_handler,
1519 .after_signal_handler = smbd_impersonate_conn_sess_after_signal_handler,
1522 struct tevent_context *smbd_impersonate_conn_sess_create(
1523 struct tevent_context *main_ev,
1524 struct connection_struct *conn,
1525 struct auth_session_info *session_info)
1527 struct tevent_context *ev = NULL;
1528 struct smbd_impersonate_conn_sess_state *state = NULL;
1530 ev = tevent_context_wrapper_create(main_ev,
1531 conn,
1532 &smbd_impersonate_conn_sess_ops,
1533 &state,
1534 struct smbd_impersonate_conn_sess_state);
1535 if (ev == NULL) {
1536 return NULL;
1538 state->conn = conn;
1539 state->session_info = session_info;
1541 return ev;
1544 struct smbd_impersonate_root_state {
1545 uint8_t _dummy;
1548 static bool smbd_impersonate_root_before_use(struct tevent_context *wrap_ev,
1549 void *private_data,
1550 struct tevent_context *main_ev,
1551 const char *location)
1553 DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
1554 "uid[%ju] gid[%ju]\n",
1555 __func__, wrap_ev, main_ev, location,
1556 (uintmax_t)geteuid(), (uintmax_t)getegid()));
1558 become_root();
1559 return true;
1562 static void smbd_impersonate_root_after_use(struct tevent_context *wrap_ev,
1563 void *private_data,
1564 struct tevent_context *main_ev,
1565 const char *location)
1567 unbecome_root();
1569 DEBUG(11,("%s: uid[%ju] gid[%ju] location[%s]\n",
1570 __func__, (uintmax_t)geteuid(), (uintmax_t)getegid(),
1571 location));
1574 static void smbd_impersonate_root_before_fd_handler(struct tevent_context *wrap_ev,
1575 void *private_data,
1576 struct tevent_context *main_ev,
1577 struct tevent_fd *fde,
1578 uint16_t flags,
1579 const char *handler_name,
1580 const char *location)
1582 DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1583 __func__, fde, (uintmax_t)flags, handler_name, location));
1585 smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1588 static void smbd_impersonate_root_after_fd_handler(struct tevent_context *wrap_ev,
1589 void *private_data,
1590 struct tevent_context *main_ev,
1591 struct tevent_fd *fde,
1592 uint16_t flags,
1593 const char *handler_name,
1594 const char *location)
1596 DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1597 __func__, fde, handler_name, location));
1599 smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1602 static void smbd_impersonate_root_before_timer_handler(struct tevent_context *wrap_ev,
1603 void *private_data,
1604 struct tevent_context *main_ev,
1605 struct tevent_timer *te,
1606 struct timeval requested_time,
1607 struct timeval trigger_time,
1608 const char *handler_name,
1609 const char *location)
1611 struct timeval_buf requested_buf;
1612 struct timeval_buf trigger_buf;
1614 DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1615 "handler_name[%s] location[%s]\n",
1616 __func__, te,
1617 timeval_str_buf(&requested_time, true, true, &requested_buf),
1618 timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1619 handler_name, location));
1621 smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1624 static void smbd_impersonate_root_after_timer_handler(struct tevent_context *wrap_ev,
1625 void *private_data,
1626 struct tevent_context *main_ev,
1627 struct tevent_timer *te,
1628 struct timeval requested_time,
1629 struct timeval trigger_time,
1630 const char *handler_name,
1631 const char *location)
1633 DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1634 __func__, te, handler_name, location));
1636 smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1639 static void smbd_impersonate_root_before_immediate_handler(struct tevent_context *wrap_ev,
1640 void *private_data,
1641 struct tevent_context *main_ev,
1642 struct tevent_immediate *im,
1643 const char *handler_name,
1644 const char *location)
1646 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1647 __func__, im, handler_name, location));
1649 smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1652 static void smbd_impersonate_root_after_immediate_handler(struct tevent_context *wrap_ev,
1653 void *private_data,
1654 struct tevent_context *main_ev,
1655 struct tevent_immediate *im,
1656 const char *handler_name,
1657 const char *location)
1659 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1660 __func__, im, handler_name, location));
1662 smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1665 static void smbd_impersonate_root_before_signal_handler(struct tevent_context *wrap_ev,
1666 void *private_data,
1667 struct tevent_context *main_ev,
1668 struct tevent_signal *se,
1669 int signum,
1670 int count,
1671 void *siginfo,
1672 const char *handler_name,
1673 const char *location)
1675 DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1676 "handler_name[%s] location[%s]\n",
1677 __func__, se, signum, count, siginfo, handler_name, location));
1679 smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1682 static void smbd_impersonate_root_after_signal_handler(struct tevent_context *wrap_ev,
1683 void *private_data,
1684 struct tevent_context *main_ev,
1685 struct tevent_signal *se,
1686 int signum,
1687 int count,
1688 void *siginfo,
1689 const char *handler_name,
1690 const char *location)
1692 DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1693 __func__, se, handler_name, location));
1695 smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1698 static const struct tevent_wrapper_ops smbd_impersonate_root_ops = {
1699 .name = "smbd_impersonate_root",
1700 .before_use = smbd_impersonate_root_before_use,
1701 .after_use = smbd_impersonate_root_after_use,
1702 .before_fd_handler = smbd_impersonate_root_before_fd_handler,
1703 .after_fd_handler = smbd_impersonate_root_after_fd_handler,
1704 .before_timer_handler = smbd_impersonate_root_before_timer_handler,
1705 .after_timer_handler = smbd_impersonate_root_after_timer_handler,
1706 .before_immediate_handler = smbd_impersonate_root_before_immediate_handler,
1707 .after_immediate_handler = smbd_impersonate_root_after_immediate_handler,
1708 .before_signal_handler = smbd_impersonate_root_before_signal_handler,
1709 .after_signal_handler = smbd_impersonate_root_after_signal_handler,
1712 struct tevent_context *smbd_impersonate_root_create(struct tevent_context *main_ev)
1714 struct tevent_context *ev = NULL;
1715 struct smbd_impersonate_root_state *state = NULL;
1717 ev = tevent_context_wrapper_create(main_ev,
1718 main_ev,
1719 &smbd_impersonate_root_ops,
1720 &state,
1721 struct smbd_impersonate_root_state);
1722 if (ev == NULL) {
1723 return NULL;
1726 return ev;
1729 struct smbd_impersonate_guest_state {
1730 uint8_t _dummy;
1733 static bool smbd_impersonate_guest_before_use(struct tevent_context *wrap_ev,
1734 void *private_data,
1735 struct tevent_context *main_ev,
1736 const char *location)
1738 DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
1739 "uid[%ju] gid[%ju]\n",
1740 __func__, wrap_ev, main_ev, location,
1741 (uintmax_t)geteuid(), (uintmax_t)getegid()));
1743 return become_guest();
1746 static void smbd_impersonate_guest_after_use(struct tevent_context *wrap_ev,
1747 void *private_data,
1748 struct tevent_context *main_ev,
1749 const char *location)
1751 unbecome_guest();
1753 DEBUG(11,("%s: uid[%ju] gid[%ju] location[%s]\n",
1754 __func__, (uintmax_t)geteuid(), (uintmax_t)getegid(),
1755 location));
1758 static void smbd_impersonate_guest_before_fd_handler(struct tevent_context *wrap_ev,
1759 void *private_data,
1760 struct tevent_context *main_ev,
1761 struct tevent_fd *fde,
1762 uint16_t flags,
1763 const char *handler_name,
1764 const char *location)
1766 bool ok;
1768 DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1769 __func__, fde, (uintmax_t)flags, handler_name, location));
1771 ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1772 main_ev, location);
1773 if (!ok) {
1774 smb_panic("smbd_impersonate_guest_before_use() - failed");
1775 return;
1779 static void smbd_impersonate_guest_after_fd_handler(struct tevent_context *wrap_ev,
1780 void *private_data,
1781 struct tevent_context *main_ev,
1782 struct tevent_fd *fde,
1783 uint16_t flags,
1784 const char *handler_name,
1785 const char *location)
1787 DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1788 __func__, fde, handler_name, location));
1790 smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1793 static void smbd_impersonate_guest_before_timer_handler(struct tevent_context *wrap_ev,
1794 void *private_data,
1795 struct tevent_context *main_ev,
1796 struct tevent_timer *te,
1797 struct timeval requested_time,
1798 struct timeval trigger_time,
1799 const char *handler_name,
1800 const char *location)
1802 bool ok;
1803 struct timeval_buf requested_buf;
1804 struct timeval_buf trigger_buf;
1806 DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1807 "handler_name[%s] location[%s]\n",
1808 __func__, te,
1809 timeval_str_buf(&requested_time, true, true, &requested_buf),
1810 timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1811 handler_name, location));
1813 ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1814 main_ev, location);
1815 if (!ok) {
1816 smb_panic("smbd_impersonate_guest_before_use() - failed");
1817 return;
1821 static void smbd_impersonate_guest_after_timer_handler(struct tevent_context *wrap_ev,
1822 void *private_data,
1823 struct tevent_context *main_ev,
1824 struct tevent_timer *te,
1825 struct timeval requested_time,
1826 struct timeval trigger_time,
1827 const char *handler_name,
1828 const char *location)
1830 DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1831 __func__, te, handler_name, location));
1833 smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1836 static void smbd_impersonate_guest_before_immediate_handler(struct tevent_context *wrap_ev,
1837 void *private_data,
1838 struct tevent_context *main_ev,
1839 struct tevent_immediate *im,
1840 const char *handler_name,
1841 const char *location)
1843 bool ok;
1845 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1846 __func__, im, handler_name, location));
1848 ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1849 main_ev, location);
1850 if (!ok) {
1851 smb_panic("smbd_impersonate_guest_before_use() - failed");
1852 return;
1856 static void smbd_impersonate_guest_after_immediate_handler(struct tevent_context *wrap_ev,
1857 void *private_data,
1858 struct tevent_context *main_ev,
1859 struct tevent_immediate *im,
1860 const char *handler_name,
1861 const char *location)
1863 DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1864 __func__, im, handler_name, location));
1866 smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1869 static void smbd_impersonate_guest_before_signal_handler(struct tevent_context *wrap_ev,
1870 void *private_data,
1871 struct tevent_context *main_ev,
1872 struct tevent_signal *se,
1873 int signum,
1874 int count,
1875 void *siginfo,
1876 const char *handler_name,
1877 const char *location)
1879 bool ok;
1881 DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1882 "handler_name[%s] location[%s]\n",
1883 __func__, se, signum, count, siginfo, handler_name, location));
1885 ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1886 main_ev, location);
1887 if (!ok) {
1888 smb_panic("smbd_impersonate_guest_before_use() - failed");
1889 return;
1893 static void smbd_impersonate_guest_after_signal_handler(struct tevent_context *wrap_ev,
1894 void *private_data,
1895 struct tevent_context *main_ev,
1896 struct tevent_signal *se,
1897 int signum,
1898 int count,
1899 void *siginfo,
1900 const char *handler_name,
1901 const char *location)
1903 DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1904 __func__, se, handler_name, location));
1906 smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1909 static const struct tevent_wrapper_ops smbd_impersonate_guest_ops = {
1910 .name = "smbd_impersonate_guest",
1911 .before_use = smbd_impersonate_guest_before_use,
1912 .after_use = smbd_impersonate_guest_after_use,
1913 .before_fd_handler = smbd_impersonate_guest_before_fd_handler,
1914 .after_fd_handler = smbd_impersonate_guest_after_fd_handler,
1915 .before_timer_handler = smbd_impersonate_guest_before_timer_handler,
1916 .after_timer_handler = smbd_impersonate_guest_after_timer_handler,
1917 .before_immediate_handler = smbd_impersonate_guest_before_immediate_handler,
1918 .after_immediate_handler = smbd_impersonate_guest_after_immediate_handler,
1919 .before_signal_handler = smbd_impersonate_guest_before_signal_handler,
1920 .after_signal_handler = smbd_impersonate_guest_after_signal_handler,
1923 struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev)
1925 struct tevent_context *ev = NULL;
1926 struct smbd_impersonate_guest_state *state = NULL;
1928 ev = tevent_context_wrapper_create(main_ev,
1929 main_ev,
1930 &smbd_impersonate_guest_ops,
1931 &state,
1932 struct smbd_impersonate_guest_state);
1933 if (ev == NULL) {
1934 return NULL;
1937 return ev;
1940 struct smbd_impersonate_tp_current_state {
1941 const void *conn_ptr;
1942 uint64_t vuid; /* SMB2 compat */
1943 struct security_unix_token partial_ut;
1944 bool chdir_safe;
1945 int saved_cwd_fd;
1948 static int smbd_impersonate_tp_current_state_destructor(
1949 struct smbd_impersonate_tp_current_state *state)
1951 if (state->saved_cwd_fd != -1) {
1952 smb_panic(__location__);
1955 return 0;
1958 static bool smbd_impersonate_tp_current_before_job(struct pthreadpool_tevent *wrap,
1959 void *private_data,
1960 struct pthreadpool_tevent *main,
1961 const char *location)
1963 struct smbd_impersonate_tp_current_state *state =
1964 talloc_get_type_abort(private_data,
1965 struct smbd_impersonate_tp_current_state);
1967 if (state->conn_ptr != current_user.conn) {
1968 smb_panic(__location__);
1971 if (state->vuid != current_user.vuid) {
1972 smb_panic(__location__);
1975 if (state->partial_ut.uid != current_user.ut.uid) {
1976 smb_panic(__location__);
1979 if (state->partial_ut.gid != current_user.ut.gid) {
1980 smb_panic(__location__);
1983 if (state->partial_ut.ngroups != current_user.ut.ngroups) {
1984 smb_panic(__location__);
1988 * We don't verify the group list, we should have hit
1989 * an assert before. We only want to catch programmer
1990 * errors here!
1992 * We just have a sync pool and want to make sure
1993 * we're already in the correct state.
1995 * So we don't do any active impersonation.
1999 * we may need to remember the current working directory
2000 * and later restore it in the after_job hook.
2002 if (state->chdir_safe) {
2003 int open_flags = O_RDONLY;
2004 bool ok;
2006 #ifdef O_DIRECTORY
2007 open_flags |= O_DIRECTORY;
2008 #endif
2009 #ifdef O_CLOEXEC
2010 open_flags |= O_CLOEXEC;
2011 #endif
2013 state->saved_cwd_fd = open(".", open_flags);
2014 if (state->saved_cwd_fd == -1) {
2015 DBG_ERR("unable to open '.' with open_flags[0x%x] - %s\n",
2016 open_flags, strerror(errno));
2017 smb_panic("smbd_impersonate_tp_current_before_job: "
2018 "unable to open cwd '.'");
2019 return false;
2021 ok = smb_set_close_on_exec(state->saved_cwd_fd);
2022 SMB_ASSERT(ok);
2025 return true;
2028 static bool smbd_impersonate_tp_current_after_job(struct pthreadpool_tevent *wrap,
2029 void *private_data,
2030 struct pthreadpool_tevent *main,
2031 const char *location)
2033 struct smbd_impersonate_tp_current_state *state =
2034 talloc_get_type_abort(private_data,
2035 struct smbd_impersonate_tp_current_state);
2036 int ret;
2039 * There's no impersonation to revert.
2041 * But we may need to reset the current working directory.
2043 if (state->saved_cwd_fd == -1) {
2044 return true;
2047 ret = fchdir(state->saved_cwd_fd);
2048 if (ret != 0) {
2049 DBG_ERR("unable to fchdir to the original directory - %s\n",
2050 strerror(errno));
2051 smb_panic("smbd_impersonate_tp_current_after_job: "
2052 "unable restore cwd with fchdir.");
2053 return false;
2056 close(state->saved_cwd_fd);
2057 state->saved_cwd_fd = -1;
2059 return true;
2062 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_current_ops = {
2063 .name = "smbd_impersonate_tp_current",
2064 .before_job = smbd_impersonate_tp_current_before_job,
2065 .after_job = smbd_impersonate_tp_current_after_job,
2068 struct pthreadpool_tevent *smbd_impersonate_tp_current_create(
2069 TALLOC_CTX *mem_ctx,
2070 struct pthreadpool_tevent *sync_tp,
2071 struct connection_struct *conn,
2072 uint64_t vuid, bool chdir_safe,
2073 const struct security_unix_token *unix_token)
2075 struct pthreadpool_tevent *wrap_tp = NULL;
2076 struct smbd_impersonate_tp_current_state *state = NULL;
2077 size_t max_threads;
2079 max_threads = pthreadpool_tevent_max_threads(sync_tp);
2080 SMB_ASSERT(max_threads == 0);
2083 * We have a fake threadpool without real threads.
2084 * So we just provide a a wrapper that asserts that
2085 * we are already in the required impersonation state.
2088 wrap_tp = pthreadpool_tevent_wrapper_create(sync_tp,
2089 mem_ctx,
2090 &smbd_impersonate_tp_current_ops,
2091 &state,
2092 struct smbd_impersonate_tp_current_state);
2093 if (wrap_tp == NULL) {
2094 return NULL;
2097 state->conn_ptr = conn;
2098 state->vuid = vuid;
2099 state->partial_ut = *unix_token;
2100 state->partial_ut.groups = NULL;
2101 state->chdir_safe = chdir_safe;
2102 state->saved_cwd_fd = -1;
2104 if (chdir_safe) {
2105 pthreadpool_tevent_force_per_thread_cwd(wrap_tp, state);
2108 talloc_set_destructor(state, smbd_impersonate_tp_current_state_destructor);
2110 return wrap_tp;
2113 struct smbd_impersonate_tp_sess_state {
2114 const struct security_unix_token *unix_token;
2117 static bool smbd_impersonate_tp_sess_before_job(struct pthreadpool_tevent *wrap,
2118 void *private_data,
2119 struct pthreadpool_tevent *main,
2120 const char *location)
2122 struct smbd_impersonate_tp_sess_state *state =
2123 talloc_get_type_abort(private_data,
2124 struct smbd_impersonate_tp_sess_state);
2125 int ret;
2127 /* Become the correct credential on this thread. */
2128 ret = set_thread_credentials(state->unix_token->uid,
2129 state->unix_token->gid,
2130 (size_t)state->unix_token->ngroups,
2131 state->unix_token->groups);
2132 if (ret != 0) {
2133 return false;
2136 return true;
2139 static bool smbd_impersonate_tp_sess_after_job(struct pthreadpool_tevent *wrap,
2140 void *private_data,
2141 struct pthreadpool_tevent *main,
2142 const char *location)
2145 * We skip the 'unbecome' here, if the following
2146 * job cares, it already called set_thread_credentials() again.
2148 * fd based jobs on the raw pool, don't really care...
2150 return true;
2153 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_sess_ops = {
2154 .name = "smbd_impersonate_tp_sess",
2155 .before_job = smbd_impersonate_tp_sess_before_job,
2156 .after_job = smbd_impersonate_tp_sess_after_job,
2159 static struct pthreadpool_tevent *smbd_impersonate_tp_sess_create(
2160 TALLOC_CTX *mem_ctx,
2161 struct pthreadpool_tevent *main_tp,
2162 struct auth_session_info *session_info)
2164 struct pthreadpool_tevent *wrap_tp = NULL;
2165 struct smbd_impersonate_tp_sess_state *state = NULL;
2166 size_t max_threads;
2168 max_threads = pthreadpool_tevent_max_threads(main_tp);
2169 SMB_ASSERT(max_threads > 0);
2171 wrap_tp = pthreadpool_tevent_wrapper_create(main_tp,
2172 mem_ctx,
2173 &smbd_impersonate_tp_sess_ops,
2174 &state,
2175 struct smbd_impersonate_tp_sess_state);
2176 if (wrap_tp == NULL) {
2177 return NULL;
2180 state->unix_token = copy_unix_token(state, session_info->unix_token);
2181 if (state->unix_token == NULL) {
2182 int saved_errno = errno;
2183 TALLOC_FREE(wrap_tp);
2184 errno = saved_errno;
2185 return NULL;
2188 return wrap_tp;
2191 struct smbd_impersonate_tp_become_state {
2192 void (*become_fn)(void);
2193 void (*unbecome_fn)(void);
2194 bool chdir_safe;
2195 int saved_cwd_fd;
2198 static int smbd_impersonate_tp_become_state_destructor(
2199 struct smbd_impersonate_tp_become_state *state)
2201 if (state->saved_cwd_fd != -1) {
2202 smb_panic(__location__);
2205 return 0;
2209 static bool smbd_impersonate_tp_become_before_job(struct pthreadpool_tevent *wrap,
2210 void *private_data,
2211 struct pthreadpool_tevent *main,
2212 const char *location)
2214 struct smbd_impersonate_tp_become_state *state =
2215 talloc_get_type_abort(private_data,
2216 struct smbd_impersonate_tp_become_state);
2219 * we may need to remember the current working directory
2220 * and later restore it in the after_job hook.
2222 if (state->chdir_safe) {
2223 int open_flags = O_RDONLY;
2224 bool ok;
2226 #ifdef O_DIRECTORY
2227 open_flags |= O_DIRECTORY;
2228 #endif
2229 #ifdef O_CLOEXEC
2230 open_flags |= O_CLOEXEC;
2231 #endif
2233 state->saved_cwd_fd = open(".", open_flags);
2234 if (state->saved_cwd_fd == -1) {
2235 DBG_ERR("unable to open '.' with open_flags[0x%x] - %s\n",
2236 open_flags, strerror(errno));
2237 smb_panic("smbd_impersonate_tp_current_before_job: "
2238 "unable to open cwd '.'");
2239 return false;
2241 ok = smb_set_close_on_exec(state->saved_cwd_fd);
2242 SMB_ASSERT(ok);
2246 * The function should abort on error...
2248 state->become_fn();
2250 return true;
2253 static bool smbd_impersonate_tp_become_after_job(struct pthreadpool_tevent *wrap,
2254 void *private_data,
2255 struct pthreadpool_tevent *main,
2256 const char *location)
2258 struct smbd_impersonate_tp_become_state *state =
2259 talloc_get_type_abort(private_data,
2260 struct smbd_impersonate_tp_become_state);
2261 int ret;
2264 * The function should abort on error...
2266 state->unbecome_fn();
2269 * There's no impersonation to revert.
2271 * But we may need to reset the current working directory.
2273 if (state->saved_cwd_fd == -1) {
2274 return true;
2277 ret = fchdir(state->saved_cwd_fd);
2278 if (ret != 0) {
2279 DBG_ERR("unable to fchdir to the original directory - %s\n",
2280 strerror(errno));
2281 smb_panic("smbd_impersonate_tp_current_after_job: "
2282 "unable restore cwd with fchdir.");
2283 return false;
2286 close(state->saved_cwd_fd);
2287 state->saved_cwd_fd = -1;
2289 return true;
2292 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_become_ops = {
2293 .name = "smbd_impersonate_tp_become",
2294 .before_job = smbd_impersonate_tp_become_before_job,
2295 .after_job = smbd_impersonate_tp_become_after_job,
2298 struct pthreadpool_tevent *smbd_impersonate_tp_become_create(
2299 TALLOC_CTX *mem_ctx,
2300 struct pthreadpool_tevent *sync_tp,
2301 bool chdir_safe,
2302 void (*become_fn)(void),
2303 void (*unbecome_fn)(void))
2305 struct pthreadpool_tevent *wrap_tp = NULL;
2306 struct smbd_impersonate_tp_become_state *state = NULL;
2307 size_t max_threads;
2309 max_threads = pthreadpool_tevent_max_threads(sync_tp);
2310 SMB_ASSERT(max_threads == 0);
2313 * We have a fake threadpool without real threads.
2314 * So we just provide a a wrapper that asserts that
2315 * we are already in the required impersonation state.
2318 wrap_tp = pthreadpool_tevent_wrapper_create(sync_tp,
2319 mem_ctx,
2320 &smbd_impersonate_tp_become_ops,
2321 &state,
2322 struct smbd_impersonate_tp_become_state);
2323 if (wrap_tp == NULL) {
2324 return NULL;
2327 state->become_fn = become_fn;
2328 state->unbecome_fn = unbecome_fn;
2329 state->chdir_safe = chdir_safe;
2330 state->saved_cwd_fd = -1;
2332 if (chdir_safe) {
2333 pthreadpool_tevent_force_per_thread_cwd(wrap_tp, state);
2336 talloc_set_destructor(state, smbd_impersonate_tp_become_state_destructor);
2338 return wrap_tp;
2341 struct smbd_impersonate_tp_root_state {
2342 const struct security_unix_token *fallback_token;
2345 static bool smbd_impersonate_tp_root_before_job(struct pthreadpool_tevent *wrap,
2346 void *private_data,
2347 struct pthreadpool_tevent *main,
2348 const char *location)
2350 int ret;
2353 * Become root in this thread.
2355 ret = set_thread_credentials(0, 0, 0, NULL);
2356 if (ret != 0) {
2357 return false;
2360 return true;
2363 static bool smbd_impersonate_tp_root_after_job(struct pthreadpool_tevent *wrap,
2364 void *private_data,
2365 struct pthreadpool_tevent *main,
2366 const char *location)
2368 struct smbd_impersonate_tp_root_state *state =
2369 talloc_get_type_abort(private_data,
2370 struct smbd_impersonate_tp_root_state);
2371 int ret;
2374 * Move to a non root token again.
2375 * We just use the one of the user_ev_ctx.
2377 * The main goal is that we don't leave
2378 * a thread arround with a root token.
2380 ret = set_thread_credentials(state->fallback_token->uid,
2381 state->fallback_token->gid,
2382 (size_t)state->fallback_token->ngroups,
2383 state->fallback_token->groups);
2384 if (ret != 0) {
2385 return false;
2388 return true;
2391 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_root_ops = {
2392 .name = "smbd_impersonate_tp_root",
2393 .before_job = smbd_impersonate_tp_root_before_job,
2394 .after_job = smbd_impersonate_tp_root_after_job,
2397 static struct pthreadpool_tevent *smbd_impersonate_tp_root_create(
2398 TALLOC_CTX *mem_ctx,
2399 struct pthreadpool_tevent *main_tp,
2400 int snum,
2401 const struct security_unix_token *fallback_token)
2403 struct pthreadpool_tevent *wrap_tp = NULL;
2404 struct smbd_impersonate_tp_root_state *state = NULL;
2405 size_t max_threads;
2407 max_threads = pthreadpool_tevent_max_threads(main_tp);
2408 SMB_ASSERT(max_threads > 0);
2410 wrap_tp = pthreadpool_tevent_wrapper_create(main_tp,
2411 mem_ctx,
2412 &smbd_impersonate_tp_root_ops,
2413 &state,
2414 struct smbd_impersonate_tp_root_state);
2415 if (wrap_tp == NULL) {
2416 return NULL;
2419 state->fallback_token = copy_unix_token(state, fallback_token);
2420 if (state->fallback_token == NULL) {
2421 int saved_errno = errno;
2422 TALLOC_FREE(wrap_tp);
2423 errno = saved_errno;
2424 return NULL;
2427 return wrap_tp;
2430 static struct smb_vfs_ev_glue *smbd_impersonate_user_ev_glue_create(
2431 struct connection_struct *conn,
2432 uint64_t vuid,
2433 struct auth_session_info *session_info)
2435 TALLOC_CTX *frame = talloc_stackframe();
2436 struct smb_vfs_ev_glue *user_vfs_evg = NULL;
2437 struct tevent_context *user_ev_ctx = NULL;
2438 struct pthreadpool_tevent *user_tp_fd_safe = NULL;
2439 struct pthreadpool_tevent *user_tp_path_safe = NULL;
2440 bool user_tp_path_sync = true;
2441 struct pthreadpool_tevent *user_tp_chdir_safe = NULL;
2442 bool user_tp_chdir_sync = true;
2443 struct pthreadpool_tevent *root_tp_fd_safe = NULL;
2444 struct pthreadpool_tevent *root_tp_path_safe = NULL;
2445 bool root_tp_path_sync = true;
2446 struct pthreadpool_tevent *root_tp_chdir_safe = NULL;
2447 bool root_tp_chdir_sync = true;
2448 size_t max_threads;
2450 if (vuid == UID_FIELD_INVALID) {
2451 user_ev_ctx = smbd_impersonate_conn_sess_create(
2452 conn->sconn->raw_ev_ctx, conn, session_info);
2453 if (user_ev_ctx == NULL) {
2454 TALLOC_FREE(frame);
2455 return NULL;
2457 } else {
2458 user_ev_ctx = smbd_impersonate_conn_vuid_create(
2459 conn->sconn->raw_ev_ctx, conn, vuid);
2460 if (user_ev_ctx == NULL) {
2461 TALLOC_FREE(frame);
2462 return NULL;
2465 SMB_ASSERT(talloc_reparent(conn, frame, user_ev_ctx));
2467 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
2468 user_tp_path_sync = lp_parm_bool(SNUM(conn),
2469 "smbd",
2470 "force sync user path safe threadpool",
2471 false);
2472 user_tp_chdir_sync = lp_parm_bool(SNUM(conn),
2473 "smbd",
2474 "force sync user chdir safe threadpool",
2475 false);
2476 root_tp_path_sync = lp_parm_bool(SNUM(conn),
2477 "smbd",
2478 "force sync root path safe threadpool",
2479 false);
2480 root_tp_chdir_sync = lp_parm_bool(SNUM(conn),
2481 "smbd",
2482 "force sync root chdir safe threadpool",
2483 false);
2484 #endif
2486 max_threads = pthreadpool_tevent_max_threads(conn->sconn->raw_thread_pool);
2487 if (max_threads == 0) {
2489 * We don't have real threads, so we need to force
2490 * the sync versions...
2492 user_tp_path_sync = true;
2493 user_tp_chdir_sync = true;
2494 root_tp_path_sync = true;
2495 root_tp_chdir_sync = true;
2499 * fd_safe is easy :-)
2501 user_tp_fd_safe = conn->sconn->raw_thread_pool;
2502 root_tp_fd_safe = conn->sconn->raw_thread_pool;
2504 if (user_tp_path_sync) {
2506 * We don't have support for per thread credentials,
2507 * so we just provide a sync thread pool with a wrapper
2508 * that asserts that we are already in the required
2509 * impersonation state.
2511 user_tp_path_safe = smbd_impersonate_tp_current_create(conn,
2512 conn->sconn->sync_thread_pool,
2513 conn,
2514 vuid,
2515 false, /* chdir_safe */
2516 session_info->unix_token);
2517 if (user_tp_path_safe == NULL) {
2518 TALLOC_FREE(frame);
2519 return NULL;
2521 } else {
2522 user_tp_path_safe = smbd_impersonate_tp_sess_create(conn,
2523 conn->sconn->raw_thread_pool,
2524 session_info);
2525 if (user_tp_path_safe == NULL) {
2526 TALLOC_FREE(frame);
2527 return NULL;
2530 SMB_ASSERT(talloc_reparent(conn, frame, user_tp_path_safe));
2532 if (pthreadpool_tevent_per_thread_cwd(user_tp_path_safe)) {
2533 user_tp_chdir_safe = user_tp_path_safe;
2534 } else {
2535 user_tp_chdir_sync = true;
2538 if (user_tp_chdir_sync) {
2540 * We don't have support for per thread credentials,
2541 * so we just provide a sync thread pool with a wrapper
2542 * that asserts that we are already in the required
2543 * impersonation state.
2545 * And it needs to cleanup after [f]chdir() within
2546 * the job...
2548 user_tp_chdir_safe = smbd_impersonate_tp_current_create(conn,
2549 conn->sconn->sync_thread_pool,
2550 conn,
2551 vuid,
2552 true, /* chdir_safe */
2553 session_info->unix_token);
2554 if (user_tp_chdir_safe == NULL) {
2555 TALLOC_FREE(frame);
2556 return NULL;
2558 SMB_ASSERT(talloc_reparent(conn, frame, user_tp_chdir_safe));
2559 } else {
2560 SMB_ASSERT(user_tp_chdir_safe != NULL);
2563 if (root_tp_path_sync) {
2565 * We don't have support for per thread credentials,
2566 * so we just provide a sync thread pool with a wrapper
2567 * that wrapps the job in become_root()/unbecome_root().
2569 root_tp_path_safe = smbd_impersonate_tp_become_create(conn,
2570 conn->sconn->sync_thread_pool,
2571 false, /* chdir_safe */
2572 become_root,
2573 unbecome_root);
2574 if (root_tp_path_safe == NULL) {
2575 TALLOC_FREE(frame);
2576 return NULL;
2578 } else {
2579 root_tp_path_safe = smbd_impersonate_tp_root_create(conn,
2580 conn->sconn->raw_thread_pool,
2581 SNUM(conn),
2582 session_info->unix_token);
2583 if (root_tp_path_safe == NULL) {
2584 TALLOC_FREE(frame);
2585 return NULL;
2588 SMB_ASSERT(talloc_reparent(conn, frame, root_tp_path_safe));
2590 if (pthreadpool_tevent_per_thread_cwd(root_tp_path_safe)) {
2591 root_tp_chdir_safe = root_tp_path_safe;
2592 } else {
2593 root_tp_chdir_sync = true;
2596 if (root_tp_chdir_sync) {
2598 * We don't have support for per thread credentials,
2599 * so we just provide a sync thread pool with a wrapper
2600 * that wrapps the job in become_root()/unbecome_root().
2602 * And it needs to cleanup after [f]chdir() within
2603 * the job...
2605 root_tp_chdir_safe = smbd_impersonate_tp_become_create(conn,
2606 conn->sconn->sync_thread_pool,
2607 true, /* chdir_safe */
2608 become_root,
2609 unbecome_root);
2610 if (root_tp_chdir_safe == NULL) {
2611 TALLOC_FREE(frame);
2612 return NULL;
2614 SMB_ASSERT(talloc_reparent(conn, frame, root_tp_chdir_safe));
2615 } else {
2616 SMB_ASSERT(root_tp_chdir_safe != NULL);
2619 user_vfs_evg = smb_vfs_ev_glue_create(conn,
2620 user_ev_ctx,
2621 user_tp_fd_safe,
2622 user_tp_path_safe,
2623 user_tp_chdir_safe,
2624 conn->sconn->root_ev_ctx,
2625 root_tp_fd_safe,
2626 root_tp_path_safe,
2627 root_tp_chdir_safe);
2628 if (user_vfs_evg == NULL) {
2629 TALLOC_FREE(frame);
2630 return NULL;
2634 * Make sure everything is a talloc child of user_vfs_evg
2636 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_ev_ctx));
2637 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_tp_path_safe));
2638 if (user_tp_path_safe != user_tp_chdir_safe) {
2639 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_tp_chdir_safe));
2641 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, root_tp_path_safe));
2642 if (root_tp_path_safe != root_tp_chdir_safe) {
2643 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, root_tp_chdir_safe));
2646 TALLOC_FREE(frame);
2647 return user_vfs_evg;