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