77e5f8c83b71899fd7d5b124c6f2a0977baecd84
[samba.git] / source3 / smbd / uid.c
1 /* 
2    Unix SMB/CIFS implementation.
3    uid/user handling
4    Copyright (C) Andrew Tridgell 1992-1998
5
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.
10
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.
15
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/>.
18 */
19
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 "../auth/auth_util.h"
30 #include "lib/util/time_basic.h"
31 #include "lib/pthreadpool/pthreadpool_tevent.h"
32
33 static struct smb_vfs_ev_glue *smbd_impersonate_user_ev_glue_create(
34                                 struct connection_struct *conn,
35                                 uint64_t vuid,
36                                 struct auth_session_info *session_info);
37
38 struct smbd_impersonate_debug_state {
39         int dbg_lvl;
40         const char *name;
41 };
42
43 static bool smbd_impersonate_debug_before_use(struct tevent_context *wrap_ev,
44                                               void *private_data,
45                                               struct tevent_context *main_ev,
46                                               const char *location)
47 {
48         struct smbd_impersonate_debug_state *state =
49                 (struct smbd_impersonate_debug_state *)private_data;
50
51         DEBUG(state->dbg_lvl, (
52               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
53               __func__, state->name, wrap_ev, state, main_ev, location));
54
55         return true;
56 }
57
58 static void smbd_impersonate_debug_after_use(struct tevent_context *wrap_ev,
59                                              void *private_data,
60                                              struct tevent_context *main_ev,
61                                              const char *location)
62 {
63         struct smbd_impersonate_debug_state *state =
64                 (struct smbd_impersonate_debug_state *)private_data;
65
66         DEBUG(state->dbg_lvl, (
67               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
68               __func__, state->name, wrap_ev, state, main_ev, location));
69 }
70
71 static void smbd_impersonate_debug_before_fd_handler(struct tevent_context *wrap_ev,
72                                                 void *private_data,
73                                                 struct tevent_context *main_ev,
74                                                 struct tevent_fd *fde,
75                                                 uint16_t flags,
76                                                 const char *handler_name,
77                                                 const char *location)
78 {
79         struct smbd_impersonate_debug_state *state =
80                 (struct smbd_impersonate_debug_state *)private_data;
81
82         DEBUG(state->dbg_lvl, (
83               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
84               "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
85               __func__, state->name, wrap_ev, state, main_ev,
86               fde, flags, handler_name, location));
87 }
88
89 static void smbd_impersonate_debug_after_fd_handler(struct tevent_context *wrap_ev,
90                                                 void *private_data,
91                                                 struct tevent_context *main_ev,
92                                                 struct tevent_fd *fde,
93                                                 uint16_t flags,
94                                                 const char *handler_name,
95                                                 const char *location)
96 {
97         struct smbd_impersonate_debug_state *state =
98                 (struct smbd_impersonate_debug_state *)private_data;
99
100         DEBUG(state->dbg_lvl, (
101               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
102               "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
103               __func__, state->name, wrap_ev, state, main_ev,
104               fde, flags, handler_name, location));
105 }
106
107 static void smbd_impersonate_debug_before_timer_handler(struct tevent_context *wrap_ev,
108                                                 void *private_data,
109                                                 struct tevent_context *main_ev,
110                                                 struct tevent_timer *te,
111                                                 struct timeval requested_time,
112                                                 struct timeval trigger_time,
113                                                 const char *handler_name,
114                                                 const char *location)
115 {
116         struct smbd_impersonate_debug_state *state =
117                 (struct smbd_impersonate_debug_state *)private_data;
118         struct timeval_buf requested_buf;
119         struct timeval_buf trigger_buf;
120
121         DEBUG(state->dbg_lvl, (
122               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
123               "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
124               __func__, state->name, wrap_ev, state, main_ev, te,
125               timeval_str_buf(&requested_time, true, true, &requested_buf),
126               timeval_str_buf(&trigger_time, true, true, &trigger_buf),
127               handler_name, location));
128 }
129
130 static void smbd_impersonate_debug_after_timer_handler(struct tevent_context *wrap_ev,
131                                                 void *private_data,
132                                                 struct tevent_context *main_ev,
133                                                 struct tevent_timer *te,
134                                                 struct timeval requested_time,
135                                                 struct timeval trigger_time,
136                                                 const char *handler_name,
137                                                 const char *location)
138 {
139         struct smbd_impersonate_debug_state *state =
140                 (struct smbd_impersonate_debug_state *)private_data;
141         struct timeval_buf requested_buf;
142         struct timeval_buf trigger_buf;
143
144         DEBUG(state->dbg_lvl, (
145               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
146               "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
147               __func__, state->name, wrap_ev, state, main_ev, te,
148               timeval_str_buf(&requested_time, true, true, &requested_buf),
149               timeval_str_buf(&trigger_time, true, true, &trigger_buf),
150               handler_name, location));
151 }
152
153 static void smbd_impersonate_debug_before_immediate_handler(struct tevent_context *wrap_ev,
154                                                 void *private_data,
155                                                 struct tevent_context *main_ev,
156                                                 struct tevent_immediate *im,
157                                                 const char *handler_name,
158                                                 const char *location)
159 {
160         struct smbd_impersonate_debug_state *state =
161                 (struct smbd_impersonate_debug_state *)private_data;
162
163         DEBUG(state->dbg_lvl, (
164               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
165               "im[%p] handler_name[%s] location[%s]\n",
166               __func__, state->name, wrap_ev, state, main_ev,
167               im, handler_name, location));
168 }
169
170 static void smbd_impersonate_debug_after_immediate_handler(struct tevent_context *wrap_ev,
171                                                 void *private_data,
172                                                 struct tevent_context *main_ev,
173                                                 struct tevent_immediate *im,
174                                                 const char *handler_name,
175                                                 const char *location)
176 {
177         struct smbd_impersonate_debug_state *state =
178                 (struct smbd_impersonate_debug_state *)private_data;
179
180         DEBUG(state->dbg_lvl, (
181               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
182               "im[%p] handler_name[%s] location[%s]\n",
183               __func__, state->name, wrap_ev, state, main_ev,
184               im, handler_name, location));
185 }
186
187 static void smbd_impersonate_debug_before_signal_handler(struct tevent_context *wrap_ev,
188                                                 void *private_data,
189                                                 struct tevent_context *main_ev,
190                                                 struct tevent_signal *se,
191                                                 int signum,
192                                                 int count,
193                                                 void *siginfo,
194                                                 const char *handler_name,
195                                                 const char *location)
196 {
197         struct smbd_impersonate_debug_state *state =
198                 (struct smbd_impersonate_debug_state *)private_data;
199
200         DEBUG(state->dbg_lvl, (
201               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
202               "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
203               __func__, state->name, wrap_ev, state, main_ev,
204               se, signum, count, siginfo, handler_name, location));
205 }
206
207 static void smbd_impersonate_debug_after_signal_handler(struct tevent_context *wrap_ev,
208                                                 void *private_data,
209                                                 struct tevent_context *main_ev,
210                                                 struct tevent_signal *se,
211                                                 int signum,
212                                                 int count,
213                                                 void *siginfo,
214                                                 const char *handler_name,
215                                                 const char *location)
216 {
217         struct smbd_impersonate_debug_state *state =
218                 (struct smbd_impersonate_debug_state *)private_data;
219
220         DEBUG(state->dbg_lvl, (
221               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
222               "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
223               __func__, state->name, wrap_ev, state, main_ev,
224               se, signum, count, siginfo, handler_name, location));
225 }
226
227 static const struct tevent_wrapper_ops smbd_impersonate_debug_ops = {
228         .name                           = "smbd_impersonate_debug",
229         .before_use                     = smbd_impersonate_debug_before_use,
230         .after_use                      = smbd_impersonate_debug_after_use,
231         .before_fd_handler              = smbd_impersonate_debug_before_fd_handler,
232         .after_fd_handler               = smbd_impersonate_debug_after_fd_handler,
233         .before_timer_handler           = smbd_impersonate_debug_before_timer_handler,
234         .after_timer_handler            = smbd_impersonate_debug_after_timer_handler,
235         .before_immediate_handler       = smbd_impersonate_debug_before_immediate_handler,
236         .after_immediate_handler        = smbd_impersonate_debug_after_immediate_handler,
237         .before_signal_handler          = smbd_impersonate_debug_before_signal_handler,
238         .after_signal_handler           = smbd_impersonate_debug_after_signal_handler,
239 };
240
241 struct tevent_context *_smbd_impersonate_debug_create(struct tevent_context *main_ev,
242                                                       const char *name,
243                                                       int dbg_lvl,
244                                                       const char *location)
245 {
246         struct tevent_context *wrap_ev = NULL;
247         struct smbd_impersonate_debug_state *state = NULL;
248
249         wrap_ev = tevent_context_wrapper_create(main_ev,
250                                         main_ev,
251                                         &smbd_impersonate_debug_ops,
252                                         &state,
253                                         struct smbd_impersonate_debug_state);
254         if (wrap_ev == NULL) {
255                 return NULL;
256         }
257         state->name = name;
258         state->dbg_lvl = dbg_lvl;
259         DEBUG(state->dbg_lvl, (
260               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
261               __func__, state->name, wrap_ev, state, main_ev, location));
262
263         return wrap_ev;
264 }
265
266 /* what user is current? */
267 extern struct current_user current_user;
268
269 /****************************************************************************
270  Become the guest user without changing the security context stack.
271 ****************************************************************************/
272
273 bool change_to_guest(void)
274 {
275         struct passwd *pass;
276
277         pass = Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
278         if (!pass) {
279                 return false;
280         }
281
282 #ifdef AIX
283         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
284            setting IDs */
285         initgroups(pass->pw_name, pass->pw_gid);
286 #endif
287
288         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
289
290         current_user.conn = NULL;
291         current_user.vuid = UID_FIELD_INVALID;
292         current_user.need_chdir = false;
293         current_user.done_chdir = false;
294
295         TALLOC_FREE(pass);
296
297         return true;
298 }
299
300 /****************************************************************************
301  talloc free the conn->session_info if not used in the vuid cache.
302 ****************************************************************************/
303
304 static void free_conn_session_info_if_unused(connection_struct *conn)
305 {
306         unsigned int i;
307
308         for (i = 0; i < VUID_CACHE_SIZE; i++) {
309                 struct vuid_cache_entry *ent;
310                 ent = &conn->vuid_cache->array[i];
311                 if (ent->vuid != UID_FIELD_INVALID &&
312                                 conn->session_info == ent->session_info) {
313                         return;
314                 }
315         }
316         /* Not used, safe to free. */
317         conn->user_ev_ctx = NULL;
318         TALLOC_FREE(conn->user_vfs_evg);
319         TALLOC_FREE(conn->session_info);
320 }
321
322 /****************************************************************************
323   Setup the share access mask for a connection.
324 ****************************************************************************/
325
326 static uint32_t create_share_access_mask(int snum,
327                                 bool readonly_share,
328                                 const struct security_token *token)
329 {
330         uint32_t share_access = 0;
331
332         share_access_check(token,
333                         lp_const_servicename(snum),
334                         MAXIMUM_ALLOWED_ACCESS,
335                         &share_access);
336
337         if (readonly_share) {
338                 share_access &=
339                         ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
340                           SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
341                           SEC_DIR_DELETE_CHILD );
342         }
343
344         if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
345                 share_access |= SEC_FLAG_SYSTEM_SECURITY;
346         }
347         if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
348                 share_access |= SEC_RIGHTS_PRIV_RESTORE;
349         }
350         if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
351                 share_access |= SEC_RIGHTS_PRIV_BACKUP;
352         }
353         if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
354                 share_access |= SEC_STD_WRITE_OWNER;
355         }
356
357         return share_access;
358 }
359
360 /*******************************************************************
361  Calculate access mask and if this user can access this share.
362 ********************************************************************/
363
364 NTSTATUS check_user_share_access(connection_struct *conn,
365                                 const struct auth_session_info *session_info,
366                                 uint32_t *p_share_access,
367                                 bool *p_readonly_share)
368 {
369         int snum = SNUM(conn);
370         uint32_t share_access = 0;
371         bool readonly_share = false;
372
373         if (!user_ok_token(session_info->unix_info->unix_name,
374                            session_info->info->domain_name,
375                            session_info->security_token, snum)) {
376                 return NT_STATUS_ACCESS_DENIED;
377         }
378
379         readonly_share = is_share_read_only_for_token(
380                 session_info->unix_info->unix_name,
381                 session_info->info->domain_name,
382                 session_info->security_token,
383                 conn);
384
385         share_access = create_share_access_mask(snum,
386                                         readonly_share,
387                                         session_info->security_token);
388
389         if ((share_access & (FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
390                 /* No access, read or write. */
391                 DBG_NOTICE("user %s connection to %s denied due to share "
392                          "security descriptor.\n",
393                          session_info->unix_info->unix_name,
394                          lp_const_servicename(snum));
395                 return NT_STATUS_ACCESS_DENIED;
396         }
397
398         if (!readonly_share &&
399             !(share_access & FILE_WRITE_DATA)) {
400                 /* smb.conf allows r/w, but the security descriptor denies
401                  * write. Fall back to looking at readonly. */
402                 readonly_share = true;
403                 DBG_INFO("falling back to read-only access-evaluation due to "
404                          "security descriptor\n");
405         }
406
407         *p_share_access = share_access;
408         *p_readonly_share = readonly_share;
409
410         return NT_STATUS_OK;
411 }
412
413 /*******************************************************************
414  Check if a username is OK.
415
416  This sets up conn->session_info with a copy related to this vuser that
417  later code can then mess with.
418 ********************************************************************/
419
420 static bool check_user_ok(connection_struct *conn,
421                         uint64_t vuid,
422                         const struct auth_session_info *session_info,
423                         int snum)
424 {
425         unsigned int i;
426         bool readonly_share = false;
427         bool admin_user = false;
428         struct vuid_cache_entry *ent = NULL;
429         uint32_t share_access = 0;
430         NTSTATUS status;
431
432         for (i=0; i<VUID_CACHE_SIZE; i++) {
433                 ent = &conn->vuid_cache->array[i];
434                 if (ent->vuid == vuid) {
435                         if (vuid == UID_FIELD_INVALID) {
436                                 /*
437                                  * Slow path, we don't care
438                                  * about the array traversal.
439                                 */
440                                 continue;
441                         }
442                         free_conn_session_info_if_unused(conn);
443                         conn->session_info = ent->session_info;
444                         conn->user_vfs_evg = ent->user_vfs_evg;
445                         conn->read_only = ent->read_only;
446                         conn->share_access = ent->share_access;
447                         conn->vuid = ent->vuid;
448                         conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(
449                                                 conn->user_vfs_evg);
450                         SMB_ASSERT(conn->user_ev_ctx != NULL);
451                         return(True);
452                 }
453         }
454
455         status = check_user_share_access(conn,
456                                         session_info,
457                                         &share_access,
458                                         &readonly_share);
459         if (!NT_STATUS_IS_OK(status)) {
460                 return false;
461         }
462
463         admin_user = token_contains_name_in_list(
464                 session_info->unix_info->unix_name,
465                 session_info->info->domain_name,
466                 NULL, session_info->security_token, lp_admin_users(snum));
467
468         ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry];
469
470         conn->vuid_cache->next_entry =
471                 (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE;
472
473         TALLOC_FREE(ent->session_info);
474
475         /*
476          * If force_user was set, all session_info's are based on the same
477          * username-based faked one.
478          */
479
480         ent->session_info = copy_session_info(
481                 conn, conn->force_user ? conn->session_info : session_info);
482
483         if (ent->session_info == NULL) {
484                 ent->vuid = UID_FIELD_INVALID;
485                 return false;
486         }
487
488         if (admin_user) {
489                 DEBUG(2,("check_user_ok: user %s is an admin user. "
490                         "Setting uid as %d\n",
491                         ent->session_info->unix_info->unix_name,
492                         sec_initial_uid() ));
493                 ent->session_info->unix_token->uid = sec_initial_uid();
494         }
495
496         ent->user_vfs_evg = smbd_impersonate_user_ev_glue_create(conn,
497                                                         vuid, ent->session_info);
498         if (ent->user_vfs_evg == NULL) {
499                 TALLOC_FREE(ent->session_info);
500                 ent->vuid = UID_FIELD_INVALID;
501                 return false;
502         }
503
504         /*
505          * It's actually OK to call check_user_ok() with
506          * vuid == UID_FIELD_INVALID as called from change_to_user_by_session().
507          * All this will do is throw away one entry in the cache.
508          */
509
510         ent->vuid = vuid;
511         ent->read_only = readonly_share;
512         ent->share_access = share_access;
513         free_conn_session_info_if_unused(conn);
514         conn->session_info = ent->session_info;
515         conn->vuid = ent->vuid;
516         conn->user_vfs_evg = ent->user_vfs_evg;
517         conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(conn->user_vfs_evg);
518         SMB_ASSERT(conn->user_ev_ctx != NULL);
519
520         if (vuid == UID_FIELD_INVALID) {
521                 /*
522                  * Not strictly needed, just make it really
523                  * clear this entry is actually an unused one.
524                  */
525                 ent->read_only = false;
526                 ent->share_access = 0;
527                 ent->session_info = NULL;
528                 ent->user_vfs_evg = NULL;
529         }
530
531         conn->read_only = readonly_share;
532         conn->share_access = share_access;
533
534         return(True);
535 }
536
537 /****************************************************************************
538  Become the user of a connection number without changing the security context
539  stack, but modify the current_user entries.
540 ****************************************************************************/
541
542 static bool change_to_user_internal(connection_struct *conn,
543                                     const struct auth_session_info *session_info,
544                                     uint64_t vuid)
545 {
546         int snum;
547         gid_t gid;
548         uid_t uid;
549         char group_c;
550         int num_groups = 0;
551         gid_t *group_list = NULL;
552         bool ok;
553
554         if ((current_user.conn == conn) &&
555             (current_user.vuid == vuid) &&
556             (current_user.need_chdir == conn->tcon_done) &&
557             (current_user.ut.uid == session_info->unix_token->uid))
558         {
559                 DBG_INFO("Skipping user change - already user\n");
560                 return true;
561         }
562
563         set_current_user_info(session_info->unix_info->sanitized_username,
564                               session_info->unix_info->unix_name,
565                               session_info->info->domain_name);
566
567         snum = SNUM(conn);
568
569         ok = check_user_ok(conn, vuid, session_info, snum);
570         if (!ok) {
571                 DBG_WARNING("SMB user %s (unix user %s) "
572                          "not permitted access to share %s.\n",
573                          session_info->unix_info->sanitized_username,
574                          session_info->unix_info->unix_name,
575                          lp_const_servicename(snum));
576                 return false;
577         }
578
579         uid = conn->session_info->unix_token->uid;
580         gid = conn->session_info->unix_token->gid;
581         num_groups = conn->session_info->unix_token->ngroups;
582         group_list  = conn->session_info->unix_token->groups;
583
584         /*
585          * See if we should force group for this service. If so this overrides
586          * any group set in the force user code.
587          */
588         if((group_c = *lp_force_group(talloc_tos(), snum))) {
589
590                 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
591
592                 if (group_c == '+') {
593                         int i;
594
595                         /*
596                          * Only force group if the user is a member of the
597                          * service group. Check the group memberships for this
598                          * user (we already have this) to see if we should force
599                          * the group.
600                          */
601                         for (i = 0; i < num_groups; i++) {
602                                 if (group_list[i] == conn->force_group_gid) {
603                                         conn->session_info->unix_token->gid =
604                                                 conn->force_group_gid;
605                                         gid = conn->force_group_gid;
606                                         gid_to_sid(&conn->session_info->security_token
607                                                    ->sids[1], gid);
608                                         break;
609                                 }
610                         }
611                 } else {
612                         conn->session_info->unix_token->gid = conn->force_group_gid;
613                         gid = conn->force_group_gid;
614                         gid_to_sid(&conn->session_info->security_token->sids[1],
615                                    gid);
616                 }
617         }
618
619         /*Set current_user since we will immediately also call set_sec_ctx() */
620         current_user.ut.ngroups = num_groups;
621         current_user.ut.groups  = group_list;
622
623         set_sec_ctx(uid,
624                     gid,
625                     current_user.ut.ngroups,
626                     current_user.ut.groups,
627                     conn->session_info->security_token);
628
629         current_user.conn = conn;
630         current_user.vuid = vuid;
631         current_user.need_chdir = conn->tcon_done;
632
633         if (current_user.need_chdir) {
634                 ok = chdir_current_service(conn);
635                 if (!ok) {
636                         DBG_ERR("chdir_current_service() failed!\n");
637                         return false;
638                 }
639                 current_user.done_chdir = true;
640         }
641
642         if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
643                 struct smb_filename *cwdfname = vfs_GetWd(talloc_tos(), conn);
644                 if (cwdfname == NULL) {
645                         return false;
646                 }
647                 DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
648                          (int)getuid(),
649                          (int)geteuid(),
650                          (int)getgid(),
651                          (int)getegid(),
652                          cwdfname->base_name);
653                 TALLOC_FREE(cwdfname);
654         }
655
656         return true;
657 }
658
659 bool change_to_user(connection_struct *conn, uint64_t vuid)
660 {
661         struct user_struct *vuser;
662         int snum = SNUM(conn);
663
664         if (!conn) {
665                 DEBUG(2,("Connection not open\n"));
666                 return(False);
667         }
668
669         vuser = get_valid_user_struct(conn->sconn, vuid);
670         if (vuser == NULL) {
671                 /* Invalid vuid sent */
672                 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
673                             (unsigned long long)vuid,
674                             lp_const_servicename(snum));
675                 return false;
676         }
677
678         return change_to_user_internal(conn, vuser->session_info, vuid);
679 }
680
681 bool change_to_user_by_fsp(struct files_struct *fsp)
682 {
683         return change_to_user(fsp->conn, fsp->vuid);
684 }
685
686 static bool change_to_user_by_session(connection_struct *conn,
687                                       const struct auth_session_info *session_info)
688 {
689         SMB_ASSERT(conn != NULL);
690         SMB_ASSERT(session_info != NULL);
691
692         return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
693 }
694
695 /****************************************************************************
696  Go back to being root without changing the security context stack,
697  but modify the current_user entries.
698 ****************************************************************************/
699
700 bool smbd_change_to_root_user(void)
701 {
702         set_root_sec_ctx();
703
704         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
705                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
706
707         current_user.conn = NULL;
708         current_user.vuid = UID_FIELD_INVALID;
709         current_user.need_chdir = false;
710         current_user.done_chdir = false;
711
712         return(True);
713 }
714
715 /****************************************************************************
716  Become the user of an authenticated connected named pipe.
717  When this is called we are currently running as the connection
718  user. Doesn't modify current_user.
719 ****************************************************************************/
720
721 bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
722 {
723         if (!push_sec_ctx())
724                 return False;
725
726         set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
727                     session_info->unix_token->ngroups, session_info->unix_token->groups,
728                     session_info->security_token);
729
730         DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
731                  (int)getuid(),
732                  (int)geteuid(),
733                  (int)getgid(),
734                  (int)getegid()));
735
736         return True;
737 }
738
739 /****************************************************************************
740  Unbecome the user of an authenticated connected named pipe.
741  When this is called we are running as the authenticated pipe
742  user and need to go back to being the connection user. Doesn't modify
743  current_user.
744 ****************************************************************************/
745
746 bool smbd_unbecome_authenticated_pipe_user(void)
747 {
748         return pop_sec_ctx();
749 }
750
751 /****************************************************************************
752  Utility functions used by become_xxx/unbecome_xxx.
753 ****************************************************************************/
754
755 static void push_conn_ctx(void)
756 {
757         struct conn_ctx *ctx_p;
758         extern userdom_struct current_user_info;
759
760         /* Check we don't overflow our stack */
761
762         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
763                 DEBUG(0, ("Connection context stack overflow!\n"));
764                 smb_panic("Connection context stack overflow!\n");
765         }
766
767         /* Store previous user context */
768         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
769
770         ctx_p->conn = current_user.conn;
771         ctx_p->vuid = current_user.vuid;
772         ctx_p->need_chdir = current_user.need_chdir;
773         ctx_p->done_chdir = current_user.done_chdir;
774         ctx_p->user_info = current_user_info;
775
776         DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
777                 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
778
779         conn_ctx_stack_ndx++;
780 }
781
782 static void pop_conn_ctx(void)
783 {
784         struct conn_ctx *ctx_p;
785
786         /* Check for stack underflow. */
787
788         if (conn_ctx_stack_ndx == 0) {
789                 DEBUG(0, ("Connection context stack underflow!\n"));
790                 smb_panic("Connection context stack underflow!\n");
791         }
792
793         conn_ctx_stack_ndx--;
794         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
795
796         set_current_user_info(ctx_p->user_info.smb_name,
797                               ctx_p->user_info.unix_name,
798                               ctx_p->user_info.domain);
799
800         /*
801          * Check if the current context did a chdir_current_service()
802          * and restore the cwd_fname of the previous context
803          * if needed.
804          */
805         if (current_user.done_chdir && ctx_p->need_chdir) {
806                 int ret;
807
808                 ret = vfs_ChDir(ctx_p->conn, ctx_p->conn->cwd_fname);
809                 if (ret != 0) {
810                         DBG_ERR("vfs_ChDir() failed!\n");
811                         smb_panic("vfs_ChDir() failed!\n");
812                 }
813         }
814
815         current_user.conn = ctx_p->conn;
816         current_user.vuid = ctx_p->vuid;
817         current_user.need_chdir = ctx_p->need_chdir;
818         current_user.done_chdir = ctx_p->done_chdir;
819
820         *ctx_p = (struct conn_ctx) {
821                 .vuid = UID_FIELD_INVALID,
822         };
823 }
824
825 /****************************************************************************
826  Temporarily become a root user.  Must match with unbecome_root(). Saves and
827  restores the connection context.
828 ****************************************************************************/
829
830 void smbd_become_root(void)
831 {
832          /*
833           * no good way to handle push_sec_ctx() failing without changing
834           * the prototype of become_root()
835           */
836         if (!push_sec_ctx()) {
837                 smb_panic("become_root: push_sec_ctx failed");
838         }
839         push_conn_ctx();
840         set_root_sec_ctx();
841 }
842
843 /* Unbecome the root user */
844
845 void smbd_unbecome_root(void)
846 {
847         pop_sec_ctx();
848         pop_conn_ctx();
849 }
850
851 bool become_guest(void)
852 {
853         bool ok;
854
855         ok = push_sec_ctx();
856         if (!ok) {
857                 return false;
858         }
859
860         push_conn_ctx();
861
862         ok = change_to_guest();
863         if (!ok) {
864                 pop_sec_ctx();
865                 pop_conn_ctx();
866                 return false;
867         }
868
869         return true;
870 }
871
872 void unbecome_guest(void)
873 {
874         pop_sec_ctx();
875         pop_conn_ctx();
876         return;
877 }
878
879 /****************************************************************************
880  Push the current security context then force a change via change_to_user().
881  Saves and restores the connection context.
882 ****************************************************************************/
883
884 bool become_user(connection_struct *conn, uint64_t vuid)
885 {
886         if (!push_sec_ctx())
887                 return False;
888
889         push_conn_ctx();
890
891         if (!change_to_user(conn, vuid)) {
892                 pop_sec_ctx();
893                 pop_conn_ctx();
894                 return False;
895         }
896
897         return True;
898 }
899
900 bool become_user_by_fsp(struct files_struct *fsp)
901 {
902         return become_user(fsp->conn, fsp->vuid);
903 }
904
905 bool become_user_by_session(connection_struct *conn,
906                             const struct auth_session_info *session_info)
907 {
908         if (!push_sec_ctx())
909                 return false;
910
911         push_conn_ctx();
912
913         if (!change_to_user_by_session(conn, session_info)) {
914                 pop_sec_ctx();
915                 pop_conn_ctx();
916                 return false;
917         }
918
919         return true;
920 }
921
922 bool unbecome_user(void)
923 {
924         pop_sec_ctx();
925         pop_conn_ctx();
926         return True;
927 }
928
929 /****************************************************************************
930  Return the current user we are running effectively as on this connection.
931  I'd like to make this return conn->session_info->unix_token->uid, but become_root()
932  doesn't alter this value.
933 ****************************************************************************/
934
935 uid_t get_current_uid(connection_struct *conn)
936 {
937         return current_user.ut.uid;
938 }
939
940 /****************************************************************************
941  Return the current group we are running effectively as on this connection.
942  I'd like to make this return conn->session_info->unix_token->gid, but become_root()
943  doesn't alter this value.
944 ****************************************************************************/
945
946 gid_t get_current_gid(connection_struct *conn)
947 {
948         return current_user.ut.gid;
949 }
950
951 /****************************************************************************
952  Return the UNIX token we are running effectively as on this connection.
953  I'd like to make this return &conn->session_info->unix_token-> but become_root()
954  doesn't alter this value.
955 ****************************************************************************/
956
957 const struct security_unix_token *get_current_utok(connection_struct *conn)
958 {
959         return &current_user.ut;
960 }
961
962 /****************************************************************************
963  Return the Windows token we are running effectively as on this connection.
964  If this is currently a NULL token as we're inside become_root() - a temporary
965  UNIX security override, then we search up the stack for the previous active
966  token.
967 ****************************************************************************/
968
969 const struct security_token *get_current_nttok(connection_struct *conn)
970 {
971         if (current_user.nt_user_token) {
972                 return current_user.nt_user_token;
973         }
974         return sec_ctx_active_token();
975 }
976
977 uint64_t get_current_vuid(connection_struct *conn)
978 {
979         return current_user.vuid;
980 }
981
982 struct smbd_impersonate_conn_vuid_state {
983         struct connection_struct *conn;
984         uint64_t vuid;
985 };
986
987 static bool smbd_impersonate_conn_vuid_before_use(
988                 struct tevent_context *wrap_ev,
989                 void *private_data,
990                 struct tevent_context *main_ev,
991                 const char *location)
992 {
993         struct smbd_impersonate_conn_vuid_state *state =
994                 talloc_get_type_abort(private_data,
995                 struct smbd_impersonate_conn_vuid_state);
996         bool ok;
997
998         DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
999                   "old uid[%ju] old gid[%ju] vuid[%ju] cwd[%s]\n",
1000                   __func__, wrap_ev, main_ev, location,
1001                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1002                   (uintmax_t)state->vuid, state->conn->cwd_fname->base_name));
1003
1004         ok = become_user(state->conn, state->vuid);
1005         if (!ok) {
1006                 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1007                 return false;
1008         }
1009
1010         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1011                   __func__, state->conn->session_info->unix_info->unix_name,
1012                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1013                   state->conn->cwd_fname->base_name));
1014
1015         return true;
1016 }
1017
1018 static void smbd_impersonate_conn_vuid_after_use(
1019                 struct tevent_context *wrap_ev,
1020                 void *private_data,
1021                 struct tevent_context *main_ev,
1022                 const char *location)
1023 {
1024         struct smbd_impersonate_conn_vuid_state *state =
1025                 talloc_get_type_abort(private_data,
1026                 struct smbd_impersonate_conn_vuid_state);
1027         bool ok;
1028
1029         DEBUG(11,("%s: deimpersonating[%s] uid[%ju] gid[%ju] cwd[%s] "
1030                   "location[%s]\n",
1031                   __func__, state->conn->session_info->unix_info->unix_name,
1032                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1033                   state->conn->cwd_fname->base_name, location));
1034
1035         ok = unbecome_user();
1036         if (!ok) {
1037                 smb_panic("smbd_impersonate_conn_vuid_after_use() - failed");
1038                 return;
1039         }
1040
1041         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1042                   __func__, state->conn->session_info->unix_info->unix_name,
1043                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1044                   state->conn->cwd_fname->base_name));
1045 }
1046
1047 static void smbd_impersonate_conn_vuid_before_fd_handler(
1048                 struct tevent_context *wrap_ev,
1049                 void *private_data,
1050                 struct tevent_context *main_ev,
1051                 struct tevent_fd *fde,
1052                 uint16_t flags,
1053                 const char *handler_name,
1054                 const char *location)
1055 {
1056         struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1057                 private_data, struct smbd_impersonate_conn_vuid_state);
1058         bool ok;
1059
1060         DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1061                   __func__, fde, (uintmax_t)flags, handler_name, location));
1062
1063         ok = change_to_user(state->conn, state->vuid);
1064         if (!ok) {
1065                 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1066                 return;
1067         }
1068
1069         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1070                   __func__, state->conn->session_info->unix_info->unix_name,
1071                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1072                   state->conn->cwd_fname->base_name));
1073 }
1074
1075 static void smbd_impersonate_conn_vuid_after_fd_handler(
1076                 struct tevent_context *wrap_ev,
1077                 void *private_data,
1078                 struct tevent_context *main_ev,
1079                 struct tevent_fd *fde,
1080                 uint16_t flags,
1081                 const char *handler_name,
1082                 const char *location)
1083 {
1084         DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1085                   __func__, fde, handler_name, location));
1086
1087         /* be lazy and defer change_to_root_user() */
1088 }
1089
1090 static void smbd_impersonate_conn_vuid_before_timer_handler(
1091                 struct tevent_context *wrap_ev,
1092                 void *private_data,
1093                 struct tevent_context *main_ev,
1094                 struct tevent_timer *te,
1095                 struct timeval requested_time,
1096                 struct timeval trigger_time,
1097                 const char *handler_name,
1098                 const char *location)
1099 {
1100         struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1101                 private_data, struct smbd_impersonate_conn_vuid_state);
1102         struct timeval_buf requested_buf;
1103         struct timeval_buf trigger_buf;
1104         bool ok;
1105
1106         DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1107                   "handler_name[%s] location[%s]\n",
1108                   __func__, te,
1109                   timeval_str_buf(&requested_time, true, true, &requested_buf),
1110                   timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1111                   handler_name, location));
1112
1113         ok = change_to_user(state->conn, state->vuid);
1114         if (!ok) {
1115                 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1116                 return;
1117         }
1118
1119         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1120                   __func__, state->conn->session_info->unix_info->unix_name,
1121                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1122                   state->conn->cwd_fname->base_name));
1123 }
1124
1125 static void smbd_impersonate_conn_vuid_after_timer_handler(
1126                 struct tevent_context *wrap_ev,
1127                 void *private_data,
1128                 struct tevent_context *main_ev,
1129                 struct tevent_timer *te,
1130                 struct timeval requested_time,
1131                 struct timeval trigger_time,
1132                 const char *handler_name,
1133                 const char *location)
1134 {
1135         DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1136                   __func__, te, handler_name, location));
1137
1138         /* be lazy and defer change_to_root_user() */
1139 }
1140
1141 static void smbd_impersonate_conn_vuid_before_immediate_handler(
1142                 struct tevent_context *wrap_ev,
1143                 void *private_data,
1144                 struct tevent_context *main_ev,
1145                 struct tevent_immediate *im,
1146                 const char *handler_name,
1147                 const char *location)
1148 {
1149         struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1150                 private_data, struct smbd_impersonate_conn_vuid_state);
1151         bool ok;
1152
1153         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1154                   __func__, im, handler_name, location));
1155
1156         ok = change_to_user(state->conn, state->vuid);
1157         if (!ok) {
1158                 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1159                 return;
1160         }
1161
1162         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1163                   __func__, state->conn->session_info->unix_info->unix_name,
1164                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1165                   state->conn->cwd_fname->base_name));
1166 }
1167
1168 static void smbd_impersonate_conn_vuid_after_immediate_handler(
1169                 struct tevent_context *wrap_ev,
1170                 void *private_data,
1171                 struct tevent_context *main_ev,
1172                 struct tevent_immediate *im,
1173                 const char *handler_name,
1174                 const char *location)
1175 {
1176         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1177                   __func__, im, handler_name, location));
1178
1179         /* be lazy and defer unbecome_user() */
1180 }
1181
1182 static void smbd_impersonate_conn_vuid_before_signal_handler(
1183                 struct tevent_context *wrap_ev,
1184                 void *private_data,
1185                 struct tevent_context *main_ev,
1186                 struct tevent_signal *se,
1187                 int signum,
1188                 int count,
1189                 void *siginfo,
1190                 const char *handler_name,
1191                 const char *location)
1192 {
1193         struct smbd_impersonate_conn_vuid_state *state = talloc_get_type_abort(
1194                 private_data, struct smbd_impersonate_conn_vuid_state);
1195         bool ok;
1196
1197         DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1198                   "handler_name[%s] location[%s]\n",
1199                   __func__, se, signum, count, siginfo, handler_name, location));
1200
1201         ok = change_to_user(state->conn, state->vuid);
1202         if (!ok) {
1203                 smb_panic("smbd_impersonate_conn_vuid_before_use() - failed");
1204                 return;
1205         }
1206
1207         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1208                   __func__, state->conn->session_info->unix_info->unix_name,
1209                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1210                   state->conn->cwd_fname->base_name));
1211 }
1212
1213 static void smbd_impersonate_conn_vuid_after_signal_handler(
1214                 struct tevent_context *wrap_ev,
1215                 void *private_data,
1216                 struct tevent_context *main_ev,
1217                 struct tevent_signal *se,
1218                 int signum,
1219                 int count,
1220                 void *siginfo,
1221                 const char *handler_name,
1222                 const char *location)
1223 {
1224         DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1225                   __func__, se, handler_name, location));
1226
1227         /* be lazy and defer change_to_root_user() */
1228 }
1229
1230 static const struct tevent_wrapper_ops smbd_impersonate_conn_vuid_ops = {
1231         .name                           = "smbd_impersonate_conn_vuid",
1232         .before_use                     = smbd_impersonate_conn_vuid_before_use,
1233         .after_use                      = smbd_impersonate_conn_vuid_after_use,
1234         .before_fd_handler              = smbd_impersonate_conn_vuid_before_fd_handler,
1235         .after_fd_handler               = smbd_impersonate_conn_vuid_after_fd_handler,
1236         .before_timer_handler           = smbd_impersonate_conn_vuid_before_timer_handler,
1237         .after_timer_handler            = smbd_impersonate_conn_vuid_after_timer_handler,
1238         .before_immediate_handler       = smbd_impersonate_conn_vuid_before_immediate_handler,
1239         .after_immediate_handler        = smbd_impersonate_conn_vuid_after_immediate_handler,
1240         .before_signal_handler          = smbd_impersonate_conn_vuid_before_signal_handler,
1241         .after_signal_handler           = smbd_impersonate_conn_vuid_after_signal_handler,
1242 };
1243
1244 struct tevent_context *smbd_impersonate_conn_vuid_create(
1245                                 struct tevent_context *main_ev,
1246                                 struct connection_struct *conn,
1247                                 uint64_t vuid)
1248 {
1249         struct tevent_context *ev = NULL;
1250         struct smbd_impersonate_conn_vuid_state *state = NULL;
1251
1252         ev = tevent_context_wrapper_create(main_ev,
1253                                            conn,
1254                                            &smbd_impersonate_conn_vuid_ops,
1255                                            &state,
1256                                            struct smbd_impersonate_conn_vuid_state);
1257         if (ev == NULL) {
1258                 return NULL;
1259         }
1260         state->conn = conn;
1261         state->vuid = vuid;
1262
1263         return ev;
1264 }
1265
1266 struct smbd_impersonate_conn_sess_state {
1267         struct connection_struct *conn;
1268         struct auth_session_info *session_info;
1269 };
1270
1271 static bool smbd_impersonate_conn_sess_before_use(struct tevent_context *wrap_ev,
1272                                                   void *private_data,
1273                                                   struct tevent_context *main_ev,
1274                                                   const char *location)
1275 {
1276         struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1277                 private_data, struct smbd_impersonate_conn_sess_state);
1278         bool ok;
1279
1280         DEBUG(11,("%s: impersonating user[%s] wrap_ev[%p] main_ev[%p] "
1281                   "location[%s] old uid[%ju] old gid[%ju] cwd[%s]\n",
1282                   __func__, state->session_info->unix_info->unix_name,
1283                   wrap_ev, main_ev, location,
1284                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1285                   state->conn->cwd_fname->base_name));
1286
1287         ok = become_user_by_session(state->conn, state->session_info);
1288         if (!ok) {
1289                 return false;
1290         }
1291
1292         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1293                   __func__, state->conn->session_info->unix_info->unix_name,
1294                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1295                   state->conn->cwd_fname->base_name));
1296
1297         return true;
1298 }
1299
1300 static void smbd_impersonate_conn_sess_after_use(struct tevent_context *wrap_ev,
1301                                                  void *private_data,
1302                                                  struct tevent_context *main_ev,
1303                                                  const char *location)
1304 {
1305         struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1306                 private_data, struct smbd_impersonate_conn_sess_state);
1307         bool ok;
1308
1309         DEBUG(11,("%s: deimpersonating[%s] uid[%ju] gid[%ju] cwd[%s] "
1310                   "location[%s]\n",
1311                   __func__, state->session_info->unix_info->unix_name,
1312                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1313                   state->conn->cwd_fname->base_name, location));
1314
1315         ok = unbecome_user();
1316         if (!ok) {
1317                 smb_panic("smbd_impersonate_conn_sess_after_use() - failed");
1318                 return;
1319         }
1320
1321         DEBUG(11,("%s: deimpersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1322                   __func__, state->conn->session_info->unix_info->unix_name,
1323                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1324                   state->conn->cwd_fname->base_name));
1325 }
1326
1327 static void smbd_impersonate_conn_sess_before_fd_handler(
1328                 struct tevent_context *wrap_ev,
1329                 void *private_data,
1330                 struct tevent_context *main_ev,
1331                 struct tevent_fd *fde,
1332                 uint16_t flags,
1333                 const char *handler_name,
1334                 const char *location)
1335 {
1336         struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1337                 private_data, struct smbd_impersonate_conn_sess_state);
1338         bool ok;
1339
1340         DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1341                   __func__, fde, (uintmax_t)flags, handler_name, location));
1342
1343         ok = change_to_user_by_session(state->conn, state->session_info);
1344         if (!ok) {
1345                 smb_panic("smbd_impersonate_conn_sess_before_fd_handler failed");
1346                 return;
1347         }
1348
1349         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1350                   __func__, state->conn->session_info->unix_info->unix_name,
1351                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1352                   state->conn->cwd_fname->base_name));
1353 }
1354
1355 static void smbd_impersonate_conn_sess_after_fd_handler(struct tevent_context *wrap_ev,
1356                                                         void *private_data,
1357                                                         struct tevent_context *main_ev,
1358                                                         struct tevent_fd *fde,
1359                                                         uint16_t flags,
1360                                                         const char *handler_name,
1361                                                         const char *location)
1362 {
1363         DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1364                   __func__, fde, handler_name, location));
1365
1366         /* be lazy and defer change_to_root_user() */
1367 }
1368
1369 static void smbd_impersonate_conn_sess_before_timer_handler(
1370                 struct tevent_context *wrap_ev,
1371                 void *private_data,
1372                 struct tevent_context *main_ev,
1373                 struct tevent_timer *te,
1374                 struct timeval requested_time,
1375                 struct timeval trigger_time,
1376                 const char *handler_name,
1377                 const char *location)
1378 {
1379         struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1380                 private_data, struct smbd_impersonate_conn_sess_state);
1381         struct timeval_buf requested_buf;
1382         struct timeval_buf trigger_buf;
1383         bool ok;
1384
1385         DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1386                   "handler_name[%s] location[%s]\n",
1387                   __func__, te,
1388                   timeval_str_buf(&requested_time, true, true, &requested_buf),
1389                   timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1390                   handler_name, location));
1391
1392         ok = change_to_user_by_session(state->conn, state->session_info);
1393         if (!ok) {
1394                 smb_panic("smbd_impersonate_conn_sess_before_tm_handler failed");
1395                 return;
1396         }
1397
1398         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1399                   __func__, state->conn->session_info->unix_info->unix_name,
1400                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1401                   state->conn->cwd_fname->base_name));
1402 }
1403
1404 static void smbd_impersonate_conn_sess_after_timer_handler(
1405                 struct tevent_context *wrap_ev,
1406                 void *private_data,
1407                 struct tevent_context *main_ev,
1408                 struct tevent_timer *te,
1409                 struct timeval requested_time,
1410                 struct timeval trigger_time,
1411                 const char *handler_name,
1412                 const char *location)
1413 {
1414         DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1415                   __func__, te, handler_name, location));
1416
1417         /* be lazy and defer change_to_root_user() */
1418 }
1419
1420 static void smbd_impersonate_conn_sess_before_immediate_handler(
1421                 struct tevent_context *wrap_ev,
1422                 void *private_data,
1423                 struct tevent_context *main_ev,
1424                 struct tevent_immediate *im,
1425                 const char *handler_name,
1426                 const char *location)
1427 {
1428         struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1429                 private_data, struct smbd_impersonate_conn_sess_state);
1430         bool ok;
1431
1432         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1433                   __func__, im, handler_name, location));
1434
1435         ok = change_to_user_by_session(state->conn, state->session_info);
1436         if (!ok) {
1437                 smb_panic("smbd_impersonate_conn_sess_before_im_handler failed");
1438                 return;
1439         }
1440
1441         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1442                   __func__, state->conn->session_info->unix_info->unix_name,
1443                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1444                   state->conn->cwd_fname->base_name));
1445 }
1446
1447 static void smbd_impersonate_conn_sess_after_immediate_handler(
1448                 struct tevent_context *wrap_ev,
1449                 void *private_data,
1450                 struct tevent_context *main_ev,
1451                 struct tevent_immediate *im,
1452                 const char *handler_name,
1453                 const char *location)
1454 {
1455         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1456                   __func__, im, handler_name, location));
1457
1458         /* be lazy and defer unbecome_user() */
1459 }
1460
1461 static void smbd_impersonate_conn_sess_before_signal_handler(
1462                 struct tevent_context *wrap_ev,
1463                 void *private_data,
1464                 struct tevent_context *main_ev,
1465                 struct tevent_signal *se,
1466                 int signum,
1467                 int count,
1468                 void *siginfo,
1469                 const char *handler_name,
1470                 const char *location)
1471 {
1472         struct smbd_impersonate_conn_sess_state *state = talloc_get_type_abort(
1473                 private_data, struct smbd_impersonate_conn_sess_state);
1474         bool ok;
1475
1476         DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1477                   "handler_name[%s] location[%s]\n",
1478                   __func__, se, signum, count, siginfo, handler_name, location));
1479
1480         ok = change_to_user_by_session(state->conn, state->session_info);
1481         if (!ok) {
1482                 smb_panic("smbd_impersonate_conn_sess_before_si_handler failed");
1483                 return;
1484         }
1485
1486         DEBUG(11,("%s: impersonated user[%s] uid[%ju] gid[%ju] cwd[%s]\n",
1487                   __func__, state->conn->session_info->unix_info->unix_name,
1488                   (uintmax_t)geteuid(), (uintmax_t)getegid(),
1489                   state->conn->cwd_fname->base_name));
1490 }
1491
1492 static void smbd_impersonate_conn_sess_after_signal_handler(
1493                 struct tevent_context *wrap_ev,
1494                 void *private_data,
1495                 struct tevent_context *main_ev,
1496                 struct tevent_signal *se,
1497                 int signum,
1498                 int count,
1499                 void *siginfo,
1500                 const char *handler_name,
1501                 const char *location)
1502 {
1503         DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1504                   __func__, se, handler_name, location));
1505
1506         /* be lazy and defer change_to_root_user() */
1507 }
1508
1509 static const struct tevent_wrapper_ops smbd_impersonate_conn_sess_ops = {
1510         .name                           = "smbd_impersonate_conn_sess",
1511         .before_use                     = smbd_impersonate_conn_sess_before_use,
1512         .after_use                      = smbd_impersonate_conn_sess_after_use,
1513         .before_fd_handler              = smbd_impersonate_conn_sess_before_fd_handler,
1514         .after_fd_handler               = smbd_impersonate_conn_sess_after_fd_handler,
1515         .before_timer_handler           = smbd_impersonate_conn_sess_before_timer_handler,
1516         .after_timer_handler            = smbd_impersonate_conn_sess_after_timer_handler,
1517         .before_immediate_handler       = smbd_impersonate_conn_sess_before_immediate_handler,
1518         .after_immediate_handler        = smbd_impersonate_conn_sess_after_immediate_handler,
1519         .before_signal_handler          = smbd_impersonate_conn_sess_before_signal_handler,
1520         .after_signal_handler           = smbd_impersonate_conn_sess_after_signal_handler,
1521 };
1522
1523 struct tevent_context *smbd_impersonate_conn_sess_create(
1524                                 struct tevent_context *main_ev,
1525                                 struct connection_struct *conn,
1526                                 struct auth_session_info *session_info)
1527 {
1528         struct tevent_context *ev = NULL;
1529         struct smbd_impersonate_conn_sess_state *state = NULL;
1530
1531         ev = tevent_context_wrapper_create(main_ev,
1532                                            conn,
1533                                            &smbd_impersonate_conn_sess_ops,
1534                                            &state,
1535                                            struct smbd_impersonate_conn_sess_state);
1536         if (ev == NULL) {
1537                 return NULL;
1538         }
1539         state->conn = conn;
1540         state->session_info = session_info;
1541
1542         return ev;
1543 }
1544
1545 struct smbd_impersonate_root_state {
1546         uint8_t _dummy;
1547 };
1548
1549 static bool smbd_impersonate_root_before_use(struct tevent_context *wrap_ev,
1550                                              void *private_data,
1551                                              struct tevent_context *main_ev,
1552                                              const char *location)
1553 {
1554         DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
1555                   "uid[%ju] gid[%ju]\n",
1556                   __func__, wrap_ev, main_ev, location,
1557                   (uintmax_t)geteuid(), (uintmax_t)getegid()));
1558
1559         become_root();
1560         return true;
1561 }
1562
1563 static void smbd_impersonate_root_after_use(struct tevent_context *wrap_ev,
1564                                             void *private_data,
1565                                             struct tevent_context *main_ev,
1566                                             const char *location)
1567 {
1568         unbecome_root();
1569
1570         DEBUG(11,("%s: uid[%ju] gid[%ju] location[%s]\n",
1571                   __func__, (uintmax_t)geteuid(), (uintmax_t)getegid(),
1572                   location));
1573 }
1574
1575 static void smbd_impersonate_root_before_fd_handler(struct tevent_context *wrap_ev,
1576                                                 void *private_data,
1577                                                 struct tevent_context *main_ev,
1578                                                 struct tevent_fd *fde,
1579                                                 uint16_t flags,
1580                                                 const char *handler_name,
1581                                                 const char *location)
1582 {
1583         DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1584                   __func__, fde, (uintmax_t)flags, handler_name, location));
1585
1586         smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1587 }
1588
1589 static void smbd_impersonate_root_after_fd_handler(struct tevent_context *wrap_ev,
1590                                                 void *private_data,
1591                                                 struct tevent_context *main_ev,
1592                                                 struct tevent_fd *fde,
1593                                                 uint16_t flags,
1594                                                 const char *handler_name,
1595                                                 const char *location)
1596 {
1597         DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1598                   __func__, fde, handler_name, location));
1599
1600         smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1601 }
1602
1603 static void smbd_impersonate_root_before_timer_handler(struct tevent_context *wrap_ev,
1604                                                 void *private_data,
1605                                                 struct tevent_context *main_ev,
1606                                                 struct tevent_timer *te,
1607                                                 struct timeval requested_time,
1608                                                 struct timeval trigger_time,
1609                                                 const char *handler_name,
1610                                                 const char *location)
1611 {
1612         struct timeval_buf requested_buf;
1613         struct timeval_buf trigger_buf;
1614
1615         DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1616                   "handler_name[%s] location[%s]\n",
1617                   __func__, te,
1618                   timeval_str_buf(&requested_time, true, true, &requested_buf),
1619                   timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1620                   handler_name, location));
1621
1622         smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1623 }
1624
1625 static void smbd_impersonate_root_after_timer_handler(struct tevent_context *wrap_ev,
1626                                                 void *private_data,
1627                                                 struct tevent_context *main_ev,
1628                                                 struct tevent_timer *te,
1629                                                 struct timeval requested_time,
1630                                                 struct timeval trigger_time,
1631                                                 const char *handler_name,
1632                                                 const char *location)
1633 {
1634         DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1635                   __func__, te, handler_name, location));
1636
1637         smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1638 }
1639
1640 static void smbd_impersonate_root_before_immediate_handler(struct tevent_context *wrap_ev,
1641                                                 void *private_data,
1642                                                 struct tevent_context *main_ev,
1643                                                 struct tevent_immediate *im,
1644                                                 const char *handler_name,
1645                                                 const char *location)
1646 {
1647         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1648                   __func__, im, handler_name, location));
1649
1650         smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1651 }
1652
1653 static void smbd_impersonate_root_after_immediate_handler(struct tevent_context *wrap_ev,
1654                                                 void *private_data,
1655                                                 struct tevent_context *main_ev,
1656                                                 struct tevent_immediate *im,
1657                                                 const char *handler_name,
1658                                                 const char *location)
1659 {
1660         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1661                   __func__, im, handler_name, location));
1662
1663         smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1664 }
1665
1666 static void smbd_impersonate_root_before_signal_handler(struct tevent_context *wrap_ev,
1667                                                 void *private_data,
1668                                                 struct tevent_context *main_ev,
1669                                                 struct tevent_signal *se,
1670                                                 int signum,
1671                                                 int count,
1672                                                 void *siginfo,
1673                                                 const char *handler_name,
1674                                                 const char *location)
1675 {
1676         DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1677                   "handler_name[%s] location[%s]\n",
1678                   __func__, se, signum, count, siginfo, handler_name, location));
1679
1680         smbd_impersonate_root_before_use(wrap_ev, private_data, main_ev, location);
1681 }
1682
1683 static void smbd_impersonate_root_after_signal_handler(struct tevent_context *wrap_ev,
1684                                                 void *private_data,
1685                                                 struct tevent_context *main_ev,
1686                                                 struct tevent_signal *se,
1687                                                 int signum,
1688                                                 int count,
1689                                                 void *siginfo,
1690                                                 const char *handler_name,
1691                                                 const char *location)
1692 {
1693         DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1694                   __func__, se, handler_name, location));
1695
1696         smbd_impersonate_root_after_use(wrap_ev, private_data, main_ev, location);
1697 }
1698
1699 static const struct tevent_wrapper_ops smbd_impersonate_root_ops = {
1700         .name                           = "smbd_impersonate_root",
1701         .before_use                     = smbd_impersonate_root_before_use,
1702         .after_use                      = smbd_impersonate_root_after_use,
1703         .before_fd_handler              = smbd_impersonate_root_before_fd_handler,
1704         .after_fd_handler               = smbd_impersonate_root_after_fd_handler,
1705         .before_timer_handler           = smbd_impersonate_root_before_timer_handler,
1706         .after_timer_handler            = smbd_impersonate_root_after_timer_handler,
1707         .before_immediate_handler       = smbd_impersonate_root_before_immediate_handler,
1708         .after_immediate_handler        = smbd_impersonate_root_after_immediate_handler,
1709         .before_signal_handler          = smbd_impersonate_root_before_signal_handler,
1710         .after_signal_handler           = smbd_impersonate_root_after_signal_handler,
1711 };
1712
1713 struct tevent_context *smbd_impersonate_root_create(struct tevent_context *main_ev)
1714 {
1715         struct tevent_context *ev = NULL;
1716         struct smbd_impersonate_root_state *state = NULL;
1717
1718         ev = tevent_context_wrapper_create(main_ev,
1719                                            main_ev,
1720                                            &smbd_impersonate_root_ops,
1721                                            &state,
1722                                            struct smbd_impersonate_root_state);
1723         if (ev == NULL) {
1724                 return NULL;
1725         }
1726
1727         return ev;
1728 }
1729
1730 struct smbd_impersonate_guest_state {
1731         uint8_t _dummy;
1732 };
1733
1734 static bool smbd_impersonate_guest_before_use(struct tevent_context *wrap_ev,
1735                                               void *private_data,
1736                                               struct tevent_context *main_ev,
1737                                               const char *location)
1738 {
1739         DEBUG(11,("%s: wrap_ev[%p] main_ev[%p] location[%s]"
1740                   "uid[%ju] gid[%ju]\n",
1741                   __func__, wrap_ev, main_ev, location,
1742                   (uintmax_t)geteuid(), (uintmax_t)getegid()));
1743
1744         return become_guest();
1745 }
1746
1747 static void smbd_impersonate_guest_after_use(struct tevent_context *wrap_ev,
1748                                              void *private_data,
1749                                              struct tevent_context *main_ev,
1750                                              const char *location)
1751 {
1752         unbecome_guest();
1753
1754         DEBUG(11,("%s: uid[%ju] gid[%ju] location[%s]\n",
1755                   __func__, (uintmax_t)geteuid(), (uintmax_t)getegid(),
1756                   location));
1757 }
1758
1759 static void smbd_impersonate_guest_before_fd_handler(struct tevent_context *wrap_ev,
1760                                                 void *private_data,
1761                                                 struct tevent_context *main_ev,
1762                                                 struct tevent_fd *fde,
1763                                                 uint16_t flags,
1764                                                 const char *handler_name,
1765                                                 const char *location)
1766 {
1767         bool ok;
1768
1769         DEBUG(11,("%s: fde[%p] flags[%ju] handler_name[%s] location[%s]\n",
1770                   __func__, fde, (uintmax_t)flags, handler_name, location));
1771
1772         ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1773                                                 main_ev, location);
1774         if (!ok) {
1775                 smb_panic("smbd_impersonate_guest_before_use() - failed");
1776                 return;
1777         }
1778 }
1779
1780 static void smbd_impersonate_guest_after_fd_handler(struct tevent_context *wrap_ev,
1781                                                 void *private_data,
1782                                                 struct tevent_context *main_ev,
1783                                                 struct tevent_fd *fde,
1784                                                 uint16_t flags,
1785                                                 const char *handler_name,
1786                                                 const char *location)
1787 {
1788         DEBUG(11,("%s: fde[%p] handler_name[%s] location[%s]\n",
1789                   __func__, fde, handler_name, location));
1790
1791         smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1792 }
1793
1794 static void smbd_impersonate_guest_before_timer_handler(struct tevent_context *wrap_ev,
1795                                                 void *private_data,
1796                                                 struct tevent_context *main_ev,
1797                                                 struct tevent_timer *te,
1798                                                 struct timeval requested_time,
1799                                                 struct timeval trigger_time,
1800                                                 const char *handler_name,
1801                                                 const char *location)
1802 {
1803         bool ok;
1804         struct timeval_buf requested_buf;
1805         struct timeval_buf trigger_buf;
1806
1807         DEBUG(11,("%s: te[%p] requested_time[%s] trigger_time[%s] "
1808                   "handler_name[%s] location[%s]\n",
1809                   __func__, te,
1810                   timeval_str_buf(&requested_time, true, true, &requested_buf),
1811                   timeval_str_buf(&trigger_time, true, true, &trigger_buf),
1812                   handler_name, location));
1813
1814         ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1815                                                main_ev, location);
1816         if (!ok) {
1817                 smb_panic("smbd_impersonate_guest_before_use() - failed");
1818                 return;
1819         }
1820 }
1821
1822 static void smbd_impersonate_guest_after_timer_handler(struct tevent_context *wrap_ev,
1823                                                 void *private_data,
1824                                                 struct tevent_context *main_ev,
1825                                                 struct tevent_timer *te,
1826                                                 struct timeval requested_time,
1827                                                 struct timeval trigger_time,
1828                                                 const char *handler_name,
1829                                                 const char *location)
1830 {
1831         DEBUG(11,("%s: te[%p] handler_name[%s] location[%s]\n",
1832                   __func__, te, handler_name, location));
1833
1834         smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1835 }
1836
1837 static void smbd_impersonate_guest_before_immediate_handler(struct tevent_context *wrap_ev,
1838                                                 void *private_data,
1839                                                 struct tevent_context *main_ev,
1840                                                 struct tevent_immediate *im,
1841                                                 const char *handler_name,
1842                                                 const char *location)
1843 {
1844         bool ok;
1845
1846         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1847                   __func__, im, handler_name, location));
1848
1849         ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1850                                                main_ev, location);
1851         if (!ok) {
1852                 smb_panic("smbd_impersonate_guest_before_use() - failed");
1853                 return;
1854         }
1855 }
1856
1857 static void smbd_impersonate_guest_after_immediate_handler(struct tevent_context *wrap_ev,
1858                                                 void *private_data,
1859                                                 struct tevent_context *main_ev,
1860                                                 struct tevent_immediate *im,
1861                                                 const char *handler_name,
1862                                                 const char *location)
1863 {
1864         DEBUG(11,("%s: im[%p] handler_name[%s] location[%s]\n",
1865                   __func__, im, handler_name, location));
1866
1867         smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1868 }
1869
1870 static void smbd_impersonate_guest_before_signal_handler(struct tevent_context *wrap_ev,
1871                                                 void *private_data,
1872                                                 struct tevent_context *main_ev,
1873                                                 struct tevent_signal *se,
1874                                                 int signum,
1875                                                 int count,
1876                                                 void *siginfo,
1877                                                 const char *handler_name,
1878                                                 const char *location)
1879 {
1880         bool ok;
1881
1882         DEBUG(11,("%s: se[%p] signum[%d] count[%d] siginfo[%p] "
1883                   "handler_name[%s] location[%s]\n",
1884                   __func__, se, signum, count, siginfo, handler_name, location));
1885
1886         ok = smbd_impersonate_guest_before_use(wrap_ev, private_data,
1887                                                main_ev, location);
1888         if (!ok) {
1889                 smb_panic("smbd_impersonate_guest_before_use() - failed");
1890                 return;
1891         }
1892 }
1893
1894 static void smbd_impersonate_guest_after_signal_handler(struct tevent_context *wrap_ev,
1895                                                 void *private_data,
1896                                                 struct tevent_context *main_ev,
1897                                                 struct tevent_signal *se,
1898                                                 int signum,
1899                                                 int count,
1900                                                 void *siginfo,
1901                                                 const char *handler_name,
1902                                                 const char *location)
1903 {
1904         DEBUG(11,("%s: se[%p] handler_name[%s] location[%s]\n",
1905                   __func__, se, handler_name, location));
1906
1907         smbd_impersonate_guest_after_use(wrap_ev, private_data, main_ev, location);
1908 }
1909
1910 static const struct tevent_wrapper_ops smbd_impersonate_guest_ops = {
1911         .name                           = "smbd_impersonate_guest",
1912         .before_use                     = smbd_impersonate_guest_before_use,
1913         .after_use                      = smbd_impersonate_guest_after_use,
1914         .before_fd_handler              = smbd_impersonate_guest_before_fd_handler,
1915         .after_fd_handler               = smbd_impersonate_guest_after_fd_handler,
1916         .before_timer_handler           = smbd_impersonate_guest_before_timer_handler,
1917         .after_timer_handler            = smbd_impersonate_guest_after_timer_handler,
1918         .before_immediate_handler       = smbd_impersonate_guest_before_immediate_handler,
1919         .after_immediate_handler        = smbd_impersonate_guest_after_immediate_handler,
1920         .before_signal_handler          = smbd_impersonate_guest_before_signal_handler,
1921         .after_signal_handler           = smbd_impersonate_guest_after_signal_handler,
1922 };
1923
1924 struct tevent_context *smbd_impersonate_guest_create(struct tevent_context *main_ev)
1925 {
1926         struct tevent_context *ev = NULL;
1927         struct smbd_impersonate_guest_state *state = NULL;
1928
1929         ev = tevent_context_wrapper_create(main_ev,
1930                                            main_ev,
1931                                            &smbd_impersonate_guest_ops,
1932                                            &state,
1933                                            struct smbd_impersonate_guest_state);
1934         if (ev == NULL) {
1935                 return NULL;
1936         }
1937
1938         return ev;
1939 }
1940
1941 struct smbd_impersonate_tp_current_state {
1942         const void *conn_ptr;
1943         uint64_t vuid; /* SMB2 compat */
1944         struct security_unix_token partial_ut;
1945         bool chdir_safe;
1946         int saved_cwd_fd;
1947 };
1948
1949 static int smbd_impersonate_tp_current_state_destructor(
1950                 struct smbd_impersonate_tp_current_state *state)
1951 {
1952         if (state->saved_cwd_fd != -1) {
1953                 smb_panic(__location__);
1954         }
1955
1956         return 0;
1957 }
1958
1959 static bool smbd_impersonate_tp_current_before_job(struct pthreadpool_tevent *wrap,
1960                                                    void *private_data,
1961                                                    struct pthreadpool_tevent *main,
1962                                                    const char *location)
1963 {
1964         struct smbd_impersonate_tp_current_state *state =
1965                 talloc_get_type_abort(private_data,
1966                 struct smbd_impersonate_tp_current_state);
1967
1968         if (state->conn_ptr != current_user.conn) {
1969                 smb_panic(__location__);
1970         }
1971
1972         if (state->vuid != current_user.vuid) {
1973                 smb_panic(__location__);
1974         }
1975
1976         if (state->partial_ut.uid != current_user.ut.uid) {
1977                 smb_panic(__location__);
1978         }
1979
1980         if (state->partial_ut.gid != current_user.ut.gid) {
1981                 smb_panic(__location__);
1982         }
1983
1984         if (state->partial_ut.ngroups != current_user.ut.ngroups) {
1985                 smb_panic(__location__);
1986         }
1987
1988         /*
1989          * We don't verify the group list, we should have hit
1990          * an assert before. We only want to catch programmer
1991          * errors here!
1992          *
1993          * We just have a sync pool and want to make sure
1994          * we're already in the correct state.
1995          *
1996          * So we don't do any active impersonation.
1997          */
1998
1999         /*
2000          * we may need to remember the current working directory
2001          * and later restore it in the after_job hook.
2002          */
2003         if (state->chdir_safe) {
2004                 int open_flags = O_RDONLY;
2005                 bool ok;
2006
2007 #ifdef O_DIRECTORY
2008                 open_flags |= O_DIRECTORY;
2009 #endif
2010 #ifdef O_CLOEXEC
2011                 open_flags |= O_CLOEXEC;
2012 #endif
2013
2014                 state->saved_cwd_fd = open(".", open_flags);
2015                 if (state->saved_cwd_fd == -1) {
2016                         DBG_ERR("unable to open '.' with open_flags[0x%x] - %s\n",
2017                                 open_flags, strerror(errno));
2018                         smb_panic("smbd_impersonate_tp_current_before_job: "
2019                                   "unable to open cwd '.'");
2020                         return false;
2021                 }
2022                 ok = smb_set_close_on_exec(state->saved_cwd_fd);
2023                 SMB_ASSERT(ok);
2024         }
2025
2026         return true;
2027 }
2028
2029 static bool smbd_impersonate_tp_current_after_job(struct pthreadpool_tevent *wrap,
2030                                                   void *private_data,
2031                                                   struct pthreadpool_tevent *main,
2032                                                   const char *location)
2033 {
2034         struct smbd_impersonate_tp_current_state *state =
2035                 talloc_get_type_abort(private_data,
2036                 struct smbd_impersonate_tp_current_state);
2037         int ret;
2038
2039         /*
2040          * There's no impersonation to revert.
2041          *
2042          * But we may need to reset the current working directory.
2043          */
2044         if (state->saved_cwd_fd == -1) {
2045                 return true;
2046         }
2047
2048         ret = fchdir(state->saved_cwd_fd);
2049         if (ret != 0) {
2050                 DBG_ERR("unable to fchdir to the original directory - %s\n",
2051                         strerror(errno));
2052                 smb_panic("smbd_impersonate_tp_current_after_job: "
2053                           "unable restore cwd with fchdir.");
2054                 return false;
2055         }
2056
2057         close(state->saved_cwd_fd);
2058         state->saved_cwd_fd = -1;
2059
2060         return true;
2061 }
2062
2063 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_current_ops = {
2064         .name           = "smbd_impersonate_tp_current",
2065         .before_job     = smbd_impersonate_tp_current_before_job,
2066         .after_job      = smbd_impersonate_tp_current_after_job,
2067 };
2068
2069 struct pthreadpool_tevent *smbd_impersonate_tp_current_create(
2070                                 TALLOC_CTX *mem_ctx,
2071                                 struct pthreadpool_tevent *sync_tp,
2072                                 struct connection_struct *conn,
2073                                 uint64_t vuid, bool chdir_safe,
2074                                 const struct security_unix_token *unix_token)
2075 {
2076         struct pthreadpool_tevent *wrap_tp = NULL;
2077         struct smbd_impersonate_tp_current_state *state = NULL;
2078         size_t max_threads;
2079
2080         max_threads = pthreadpool_tevent_max_threads(sync_tp);
2081         SMB_ASSERT(max_threads == 0);
2082
2083         /*
2084          * We have a fake threadpool without real threads.
2085          * So we just provide a a wrapper that asserts that
2086          * we are already in the required impersonation state.
2087          */
2088
2089         wrap_tp = pthreadpool_tevent_wrapper_create(sync_tp,
2090                                         mem_ctx,
2091                                         &smbd_impersonate_tp_current_ops,
2092                                         &state,
2093                                         struct smbd_impersonate_tp_current_state);
2094         if (wrap_tp == NULL) {
2095                 return NULL;
2096         }
2097
2098         state->conn_ptr = conn;
2099         state->vuid = vuid;
2100         state->partial_ut = *unix_token;
2101         state->partial_ut.groups = NULL;
2102         state->chdir_safe = chdir_safe;
2103         state->saved_cwd_fd = -1;
2104
2105         if (chdir_safe) {
2106                 pthreadpool_tevent_force_per_thread_cwd(wrap_tp, state);
2107         }
2108
2109         talloc_set_destructor(state, smbd_impersonate_tp_current_state_destructor);
2110
2111         return wrap_tp;
2112 }
2113
2114 struct smbd_impersonate_tp_sess_state {
2115         const struct security_unix_token *unix_token;
2116 };
2117
2118 static bool smbd_impersonate_tp_sess_before_job(struct pthreadpool_tevent *wrap,
2119                                                 void *private_data,
2120                                                 struct pthreadpool_tevent *main,
2121                                                 const char *location)
2122 {
2123         struct smbd_impersonate_tp_sess_state *state =
2124                 talloc_get_type_abort(private_data,
2125                 struct smbd_impersonate_tp_sess_state);
2126         int ret;
2127
2128         /* Become the correct credential on this thread. */
2129         ret = set_thread_credentials(state->unix_token->uid,
2130                                      state->unix_token->gid,
2131                                      (size_t)state->unix_token->ngroups,
2132                                      state->unix_token->groups);
2133         if (ret != 0) {
2134                 return false;
2135         }
2136
2137         return true;
2138 }
2139
2140 static bool smbd_impersonate_tp_sess_after_job(struct pthreadpool_tevent *wrap,
2141                                                void *private_data,
2142                                                struct pthreadpool_tevent *main,
2143                                                const char *location)
2144 {
2145         /*
2146          * We skip the 'unbecome' here, if the following
2147          * job cares, it already called set_thread_credentials() again.
2148          *
2149          * fd based jobs on the raw pool, don't really care...
2150          */
2151         return true;
2152 }
2153
2154 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_sess_ops = {
2155         .name           = "smbd_impersonate_tp_sess",
2156         .before_job     = smbd_impersonate_tp_sess_before_job,
2157         .after_job      = smbd_impersonate_tp_sess_after_job,
2158 };
2159
2160 static struct pthreadpool_tevent *smbd_impersonate_tp_sess_create(
2161                                 TALLOC_CTX *mem_ctx,
2162                                 struct pthreadpool_tevent *main_tp,
2163                                 struct auth_session_info *session_info)
2164 {
2165         struct pthreadpool_tevent *wrap_tp = NULL;
2166         struct smbd_impersonate_tp_sess_state *state = NULL;
2167         size_t max_threads;
2168
2169         max_threads = pthreadpool_tevent_max_threads(main_tp);
2170         SMB_ASSERT(max_threads > 0);
2171
2172         wrap_tp = pthreadpool_tevent_wrapper_create(main_tp,
2173                                         mem_ctx,
2174                                         &smbd_impersonate_tp_sess_ops,
2175                                         &state,
2176                                         struct smbd_impersonate_tp_sess_state);
2177         if (wrap_tp == NULL) {
2178                 return NULL;
2179         }
2180
2181         state->unix_token = copy_unix_token(state, session_info->unix_token);
2182         if (state->unix_token == NULL) {
2183                 int saved_errno = errno;
2184                 TALLOC_FREE(wrap_tp);
2185                 errno = saved_errno;
2186                 return NULL;
2187         }
2188
2189         return wrap_tp;
2190 }
2191
2192 struct smbd_impersonate_tp_become_state {
2193         void (*become_fn)(void);
2194         void (*unbecome_fn)(void);
2195         bool chdir_safe;
2196         int saved_cwd_fd;
2197 };
2198
2199 static int smbd_impersonate_tp_become_state_destructor(
2200                 struct smbd_impersonate_tp_become_state *state)
2201 {
2202         if (state->saved_cwd_fd != -1) {
2203                 smb_panic(__location__);
2204         }
2205
2206         return 0;
2207 }
2208
2209
2210 static bool smbd_impersonate_tp_become_before_job(struct pthreadpool_tevent *wrap,
2211                                                    void *private_data,
2212                                                    struct pthreadpool_tevent *main,
2213                                                    const char *location)
2214 {
2215         struct smbd_impersonate_tp_become_state *state =
2216                 talloc_get_type_abort(private_data,
2217                 struct smbd_impersonate_tp_become_state);
2218
2219         /*
2220          * we may need to remember the current working directory
2221          * and later restore it in the after_job hook.
2222          */
2223         if (state->chdir_safe) {
2224                 int open_flags = O_RDONLY;
2225                 bool ok;
2226
2227 #ifdef O_DIRECTORY
2228                 open_flags |= O_DIRECTORY;
2229 #endif
2230 #ifdef O_CLOEXEC
2231                 open_flags |= O_CLOEXEC;
2232 #endif
2233
2234                 state->saved_cwd_fd = open(".", open_flags);
2235                 if (state->saved_cwd_fd == -1) {
2236                         DBG_ERR("unable to open '.' with open_flags[0x%x] - %s\n",
2237                                 open_flags, strerror(errno));
2238                         smb_panic("smbd_impersonate_tp_current_before_job: "
2239                                   "unable to open cwd '.'");
2240                         return false;
2241                 }
2242                 ok = smb_set_close_on_exec(state->saved_cwd_fd);
2243                 SMB_ASSERT(ok);
2244         }
2245
2246         /*
2247          * The function should abort on error...
2248          */
2249         state->become_fn();
2250
2251         return true;
2252 }
2253
2254 static bool smbd_impersonate_tp_become_after_job(struct pthreadpool_tevent *wrap,
2255                                                   void *private_data,
2256                                                   struct pthreadpool_tevent *main,
2257                                                   const char *location)
2258 {
2259         struct smbd_impersonate_tp_become_state *state =
2260                 talloc_get_type_abort(private_data,
2261                 struct smbd_impersonate_tp_become_state);
2262         int ret;
2263
2264         /*
2265          * The function should abort on error...
2266          */
2267         state->unbecome_fn();
2268
2269         /*
2270          * There's no impersonation to revert.
2271          *
2272          * But we may need to reset the current working directory.
2273          */
2274         if (state->saved_cwd_fd == -1) {
2275                 return true;
2276         }
2277
2278         ret = fchdir(state->saved_cwd_fd);
2279         if (ret != 0) {
2280                 DBG_ERR("unable to fchdir to the original directory - %s\n",
2281                         strerror(errno));
2282                 smb_panic("smbd_impersonate_tp_current_after_job: "
2283                           "unable restore cwd with fchdir.");
2284                 return false;
2285         }
2286
2287         close(state->saved_cwd_fd);
2288         state->saved_cwd_fd = -1;
2289
2290         return true;
2291 }
2292
2293 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_become_ops = {
2294         .name           = "smbd_impersonate_tp_become",
2295         .before_job     = smbd_impersonate_tp_become_before_job,
2296         .after_job      = smbd_impersonate_tp_become_after_job,
2297 };
2298
2299 struct pthreadpool_tevent *smbd_impersonate_tp_become_create(
2300                                         TALLOC_CTX *mem_ctx,
2301                                         struct pthreadpool_tevent *sync_tp,
2302                                         bool chdir_safe,
2303                                         void (*become_fn)(void),
2304                                         void (*unbecome_fn)(void))
2305 {
2306         struct pthreadpool_tevent *wrap_tp = NULL;
2307         struct smbd_impersonate_tp_become_state *state = NULL;
2308         size_t max_threads;
2309
2310         max_threads = pthreadpool_tevent_max_threads(sync_tp);
2311         SMB_ASSERT(max_threads == 0);
2312
2313         /*
2314          * We have a fake threadpool without real threads.
2315          * So we just provide a a wrapper that asserts that
2316          * we are already in the required impersonation state.
2317          */
2318
2319         wrap_tp = pthreadpool_tevent_wrapper_create(sync_tp,
2320                                         mem_ctx,
2321                                         &smbd_impersonate_tp_become_ops,
2322                                         &state,
2323                                         struct smbd_impersonate_tp_become_state);
2324         if (wrap_tp == NULL) {
2325                 return NULL;
2326         }
2327
2328         state->become_fn = become_fn;
2329         state->unbecome_fn = unbecome_fn;
2330         state->chdir_safe = chdir_safe;
2331         state->saved_cwd_fd = -1;
2332
2333         if (chdir_safe) {
2334                 pthreadpool_tevent_force_per_thread_cwd(wrap_tp, state);
2335         }
2336
2337         talloc_set_destructor(state, smbd_impersonate_tp_become_state_destructor);
2338
2339         return wrap_tp;
2340 }
2341
2342 struct smbd_impersonate_tp_root_state {
2343         const struct security_unix_token *fallback_token;
2344 };
2345
2346 static bool smbd_impersonate_tp_root_before_job(struct pthreadpool_tevent *wrap,
2347                                                 void *private_data,
2348                                                 struct pthreadpool_tevent *main,
2349                                                 const char *location)
2350 {
2351         int ret;
2352
2353         /*
2354          * Become root in this thread.
2355          */
2356         ret = set_thread_credentials(0, 0, 0, NULL);
2357         if (ret != 0) {
2358                 return false;
2359         }
2360
2361         return true;
2362 }
2363
2364 static bool smbd_impersonate_tp_root_after_job(struct pthreadpool_tevent *wrap,
2365                                                void *private_data,
2366                                                struct pthreadpool_tevent *main,
2367                                                const char *location)
2368 {
2369         struct smbd_impersonate_tp_root_state *state =
2370                 talloc_get_type_abort(private_data,
2371                 struct smbd_impersonate_tp_root_state);
2372         int ret;
2373
2374         /*
2375          * Move to a non root token again.
2376          * We just use the one of the user_ev_ctx.
2377          *
2378          * The main goal is that we don't leave
2379          * a thread arround with a root token.
2380          */
2381         ret = set_thread_credentials(state->fallback_token->uid,
2382                                      state->fallback_token->gid,
2383                                      (size_t)state->fallback_token->ngroups,
2384                                      state->fallback_token->groups);
2385         if (ret != 0) {
2386                 return false;
2387         }
2388
2389         return true;
2390 }
2391
2392 static const struct pthreadpool_tevent_wrapper_ops smbd_impersonate_tp_root_ops = {
2393         .name           = "smbd_impersonate_tp_root",
2394         .before_job     = smbd_impersonate_tp_root_before_job,
2395         .after_job      = smbd_impersonate_tp_root_after_job,
2396 };
2397
2398 static struct pthreadpool_tevent *smbd_impersonate_tp_root_create(
2399                                 TALLOC_CTX *mem_ctx,
2400                                 struct pthreadpool_tevent *main_tp,
2401                                 int snum,
2402                                 const struct security_unix_token *fallback_token)
2403 {
2404         struct pthreadpool_tevent *wrap_tp = NULL;
2405         struct smbd_impersonate_tp_root_state *state = NULL;
2406         size_t max_threads;
2407
2408         max_threads = pthreadpool_tevent_max_threads(main_tp);
2409         SMB_ASSERT(max_threads > 0);
2410
2411         wrap_tp = pthreadpool_tevent_wrapper_create(main_tp,
2412                                 mem_ctx,
2413                                 &smbd_impersonate_tp_root_ops,
2414                                 &state,
2415                                 struct smbd_impersonate_tp_root_state);
2416         if (wrap_tp == NULL) {
2417                 return NULL;
2418         }
2419
2420         state->fallback_token = copy_unix_token(state, fallback_token);
2421         if (state->fallback_token == NULL) {
2422                 int saved_errno = errno;
2423                 TALLOC_FREE(wrap_tp);
2424                 errno = saved_errno;
2425                 return NULL;
2426         }
2427
2428         return wrap_tp;
2429 }
2430
2431 static struct smb_vfs_ev_glue *smbd_impersonate_user_ev_glue_create(
2432                                 struct connection_struct *conn,
2433                                 uint64_t vuid,
2434                                 struct auth_session_info *session_info)
2435 {
2436         TALLOC_CTX *frame = talloc_stackframe();
2437         struct smb_vfs_ev_glue *user_vfs_evg = NULL;
2438         struct tevent_context *user_ev_ctx = NULL;
2439         struct pthreadpool_tevent *user_tp_fd_safe = NULL;
2440         struct pthreadpool_tevent *user_tp_path_safe = NULL;
2441         bool user_tp_path_sync = true;
2442         struct pthreadpool_tevent *user_tp_chdir_safe = NULL;
2443         bool user_tp_chdir_sync = true;
2444         struct pthreadpool_tevent *root_tp_fd_safe = NULL;
2445         struct pthreadpool_tevent *root_tp_path_safe = NULL;
2446         bool root_tp_path_sync = true;
2447         struct pthreadpool_tevent *root_tp_chdir_safe = NULL;
2448         bool root_tp_chdir_sync = true;
2449         size_t max_threads;
2450
2451         if (vuid == UID_FIELD_INVALID) {
2452                 user_ev_ctx = smbd_impersonate_conn_sess_create(
2453                         conn->sconn->raw_ev_ctx, conn, session_info);
2454                 if (user_ev_ctx == NULL) {
2455                         TALLOC_FREE(frame);
2456                         return NULL;
2457                 }
2458         } else {
2459                 user_ev_ctx = smbd_impersonate_conn_vuid_create(
2460                         conn->sconn->raw_ev_ctx, conn, vuid);
2461                 if (user_ev_ctx == NULL) {
2462                         TALLOC_FREE(frame);
2463                         return NULL;
2464                 }
2465         }
2466         SMB_ASSERT(talloc_reparent(conn, frame, user_ev_ctx));
2467
2468 #ifdef HAVE_LINUX_THREAD_CREDENTIALS
2469         user_tp_path_sync = lp_parm_bool(SNUM(conn),
2470                                          "smbd",
2471                                          "force sync user path safe threadpool",
2472                                          false);
2473         user_tp_chdir_sync = lp_parm_bool(SNUM(conn),
2474                                           "smbd",
2475                                           "force sync user chdir safe threadpool",
2476                                           false);
2477         root_tp_path_sync = lp_parm_bool(SNUM(conn),
2478                                          "smbd",
2479                                          "force sync root path safe threadpool",
2480                                          false);
2481         root_tp_chdir_sync = lp_parm_bool(SNUM(conn),
2482                                           "smbd",
2483                                           "force sync root chdir safe threadpool",
2484                                           false);
2485 #endif
2486
2487         max_threads = pthreadpool_tevent_max_threads(conn->sconn->raw_thread_pool);
2488         if (max_threads == 0) {
2489                 /*
2490                  * We don't have real threads, so we need to force
2491                  * the sync versions...
2492                  */
2493                 user_tp_path_sync = true;
2494                 user_tp_chdir_sync = true;
2495                 root_tp_path_sync = true;
2496                 root_tp_chdir_sync = true;
2497         }
2498
2499         /*
2500          * fd_safe is easy :-)
2501          */
2502         user_tp_fd_safe = conn->sconn->raw_thread_pool;
2503         root_tp_fd_safe = conn->sconn->raw_thread_pool;
2504
2505         if (user_tp_path_sync) {
2506                 /*
2507                  * We don't have support for per thread credentials,
2508                  * so we just provide a sync thread pool with a wrapper
2509                  * that asserts that we are already in the required
2510                  * impersonation state.
2511                  */
2512                 user_tp_path_safe = smbd_impersonate_tp_current_create(conn,
2513                                                 conn->sconn->sync_thread_pool,
2514                                                 conn,
2515                                                 vuid,
2516                                                 false, /* chdir_safe */
2517                                                 session_info->unix_token);
2518                 if (user_tp_path_safe == NULL) {
2519                         TALLOC_FREE(frame);
2520                         return NULL;
2521                 }
2522         } else {
2523                 user_tp_path_safe = smbd_impersonate_tp_sess_create(conn,
2524                                                 conn->sconn->raw_thread_pool,
2525                                                 session_info);
2526                 if (user_tp_path_safe == NULL) {
2527                         TALLOC_FREE(frame);
2528                         return NULL;
2529                 }
2530         }
2531         SMB_ASSERT(talloc_reparent(conn, frame, user_tp_path_safe));
2532
2533         if (pthreadpool_tevent_per_thread_cwd(user_tp_path_safe)) {
2534                 user_tp_chdir_safe = user_tp_path_safe;
2535         } else {
2536                 user_tp_chdir_sync = true;
2537         }
2538
2539         if (user_tp_chdir_sync) {
2540                 /*
2541                  * We don't have support for per thread credentials,
2542                  * so we just provide a sync thread pool with a wrapper
2543                  * that asserts that we are already in the required
2544                  * impersonation state.
2545                  *
2546                  * And it needs to cleanup after [f]chdir() within
2547                  * the job...
2548                  */
2549                 user_tp_chdir_safe = smbd_impersonate_tp_current_create(conn,
2550                                                 conn->sconn->sync_thread_pool,
2551                                                 conn,
2552                                                 vuid,
2553                                                 true, /* chdir_safe */
2554                                                 session_info->unix_token);
2555                 if (user_tp_chdir_safe == NULL) {
2556                         TALLOC_FREE(frame);
2557                         return NULL;
2558                 }
2559                 SMB_ASSERT(talloc_reparent(conn, frame, user_tp_chdir_safe));
2560         } else {
2561                 SMB_ASSERT(user_tp_chdir_safe != NULL);
2562         }
2563
2564         if (root_tp_path_sync) {
2565                 /*
2566                  * We don't have support for per thread credentials,
2567                  * so we just provide a sync thread pool with a wrapper
2568                  * that wrapps the job in become_root()/unbecome_root().
2569                  */
2570                 root_tp_path_safe = smbd_impersonate_tp_become_create(conn,
2571                                                 conn->sconn->sync_thread_pool,
2572                                                 false, /* chdir_safe */
2573                                                 become_root,
2574                                                 unbecome_root);
2575                 if (root_tp_path_safe == NULL) {
2576                         TALLOC_FREE(frame);
2577                         return NULL;
2578                 }
2579         } else {
2580                 root_tp_path_safe = smbd_impersonate_tp_root_create(conn,
2581                                                 conn->sconn->raw_thread_pool,
2582                                                 SNUM(conn),
2583                                                 session_info->unix_token);
2584                 if (root_tp_path_safe == NULL) {
2585                         TALLOC_FREE(frame);
2586                         return NULL;
2587                 }
2588         }
2589         SMB_ASSERT(talloc_reparent(conn, frame, root_tp_path_safe));
2590
2591         if (pthreadpool_tevent_per_thread_cwd(root_tp_path_safe)) {
2592                 root_tp_chdir_safe = root_tp_path_safe;
2593         } else {
2594                 root_tp_chdir_sync = true;
2595         }
2596
2597         if (root_tp_chdir_sync) {
2598                 /*
2599                  * We don't have support for per thread credentials,
2600                  * so we just provide a sync thread pool with a wrapper
2601                  * that wrapps the job in become_root()/unbecome_root().
2602                  *
2603                  * And it needs to cleanup after [f]chdir() within
2604                  * the job...
2605                  */
2606                 root_tp_chdir_safe = smbd_impersonate_tp_become_create(conn,
2607                                                 conn->sconn->sync_thread_pool,
2608                                                 true, /* chdir_safe */
2609                                                 become_root,
2610                                                 unbecome_root);
2611                 if (root_tp_chdir_safe == NULL) {
2612                         TALLOC_FREE(frame);
2613                         return NULL;
2614                 }
2615                 SMB_ASSERT(talloc_reparent(conn, frame, root_tp_chdir_safe));
2616         } else {
2617                 SMB_ASSERT(root_tp_chdir_safe != NULL);
2618         }
2619
2620         user_vfs_evg = smb_vfs_ev_glue_create(conn,
2621                                               user_ev_ctx,
2622                                               user_tp_fd_safe,
2623                                               user_tp_path_safe,
2624                                               user_tp_chdir_safe,
2625                                               conn->sconn->root_ev_ctx,
2626                                               root_tp_fd_safe,
2627                                               root_tp_path_safe,
2628                                               root_tp_chdir_safe);
2629         if (user_vfs_evg == NULL) {
2630                 TALLOC_FREE(frame);
2631                 return NULL;
2632         }
2633
2634         /*
2635          * Make sure everything is a talloc child of user_vfs_evg
2636          */
2637         SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_ev_ctx));
2638         SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_tp_path_safe));
2639         if (user_tp_path_safe != user_tp_chdir_safe) {
2640                 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, user_tp_chdir_safe));
2641         }
2642         SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, root_tp_path_safe));
2643         if (root_tp_path_safe != root_tp_chdir_safe) {
2644                 SMB_ASSERT(talloc_reparent(frame, user_vfs_evg, root_tp_chdir_safe));
2645         }
2646
2647         TALLOC_FREE(frame);
2648         return user_vfs_evg;
2649 }