Revert "smbd: add simple noop smbd_impersonate_{conn_vuid,conn_sess,root,guest}_creat...
[samba.git] / source3 / smbd / uid.c
1 /* 
2    Unix SMB/CIFS implementation.
3    uid/user handling
4    Copyright (C) Andrew Tridgell 1992-1998
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/passwd.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../librpc/gen_ndr/netlogon.h"
25 #include "libcli/security/security.h"
26 #include "passdb/lookup_sid.h"
27 #include "auth.h"
28 #include "../auth/auth_util.h"
29 #include "lib/util/time_basic.h"
30
31 struct smbd_impersonate_debug_state {
32         int dbg_lvl;
33         const char *name;
34 };
35
36 static bool smbd_impersonate_debug_before_use(struct tevent_context *wrap_ev,
37                                               void *private_data,
38                                               struct tevent_context *main_ev,
39                                               const char *location)
40 {
41         struct smbd_impersonate_debug_state *state =
42                 (struct smbd_impersonate_debug_state *)private_data;
43
44         DEBUG(state->dbg_lvl, (
45               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
46               __func__, state->name, wrap_ev, state, main_ev, location));
47
48         return true;
49 }
50
51 static void smbd_impersonate_debug_after_use(struct tevent_context *wrap_ev,
52                                              void *private_data,
53                                              struct tevent_context *main_ev,
54                                              const char *location)
55 {
56         struct smbd_impersonate_debug_state *state =
57                 (struct smbd_impersonate_debug_state *)private_data;
58
59         DEBUG(state->dbg_lvl, (
60               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
61               __func__, state->name, wrap_ev, state, main_ev, location));
62 }
63
64 static void smbd_impersonate_debug_before_fd_handler(struct tevent_context *wrap_ev,
65                                                 void *private_data,
66                                                 struct tevent_context *main_ev,
67                                                 struct tevent_fd *fde,
68                                                 uint16_t flags,
69                                                 const char *handler_name,
70                                                 const char *location)
71 {
72         struct smbd_impersonate_debug_state *state =
73                 (struct smbd_impersonate_debug_state *)private_data;
74
75         DEBUG(state->dbg_lvl, (
76               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
77               "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
78               __func__, state->name, wrap_ev, state, main_ev,
79               fde, flags, handler_name, location));
80 }
81
82 static void smbd_impersonate_debug_after_fd_handler(struct tevent_context *wrap_ev,
83                                                 void *private_data,
84                                                 struct tevent_context *main_ev,
85                                                 struct tevent_fd *fde,
86                                                 uint16_t flags,
87                                                 const char *handler_name,
88                                                 const char *location)
89 {
90         struct smbd_impersonate_debug_state *state =
91                 (struct smbd_impersonate_debug_state *)private_data;
92
93         DEBUG(state->dbg_lvl, (
94               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
95               "fde[%p] flags[0x%X] handler_name[%s] location[%s]\n",
96               __func__, state->name, wrap_ev, state, main_ev,
97               fde, flags, handler_name, location));
98 }
99
100 static void smbd_impersonate_debug_before_timer_handler(struct tevent_context *wrap_ev,
101                                                 void *private_data,
102                                                 struct tevent_context *main_ev,
103                                                 struct tevent_timer *te,
104                                                 struct timeval requested_time,
105                                                 struct timeval trigger_time,
106                                                 const char *handler_name,
107                                                 const char *location)
108 {
109         struct smbd_impersonate_debug_state *state =
110                 (struct smbd_impersonate_debug_state *)private_data;
111         struct timeval_buf requested_buf;
112         struct timeval_buf trigger_buf;
113
114         DEBUG(state->dbg_lvl, (
115               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
116               "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
117               __func__, state->name, wrap_ev, state, main_ev, te,
118               timeval_str_buf(&requested_time, true, true, &requested_buf),
119               timeval_str_buf(&trigger_time, true, true, &trigger_buf),
120               handler_name, location));
121 }
122
123 static void smbd_impersonate_debug_after_timer_handler(struct tevent_context *wrap_ev,
124                                                 void *private_data,
125                                                 struct tevent_context *main_ev,
126                                                 struct tevent_timer *te,
127                                                 struct timeval requested_time,
128                                                 struct timeval trigger_time,
129                                                 const char *handler_name,
130                                                 const char *location)
131 {
132         struct smbd_impersonate_debug_state *state =
133                 (struct smbd_impersonate_debug_state *)private_data;
134         struct timeval_buf requested_buf;
135         struct timeval_buf trigger_buf;
136
137         DEBUG(state->dbg_lvl, (
138               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
139               "te[%p] requested_time[%s] trigger_time[%s] handler_name[%s] location[%s]\n",
140               __func__, state->name, wrap_ev, state, main_ev, te,
141               timeval_str_buf(&requested_time, true, true, &requested_buf),
142               timeval_str_buf(&trigger_time, true, true, &trigger_buf),
143               handler_name, location));
144 }
145
146 static void smbd_impersonate_debug_before_immediate_handler(struct tevent_context *wrap_ev,
147                                                 void *private_data,
148                                                 struct tevent_context *main_ev,
149                                                 struct tevent_immediate *im,
150                                                 const char *handler_name,
151                                                 const char *location)
152 {
153         struct smbd_impersonate_debug_state *state =
154                 (struct smbd_impersonate_debug_state *)private_data;
155
156         DEBUG(state->dbg_lvl, (
157               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
158               "im[%p] handler_name[%s] location[%s]\n",
159               __func__, state->name, wrap_ev, state, main_ev,
160               im, handler_name, location));
161 }
162
163 static void smbd_impersonate_debug_after_immediate_handler(struct tevent_context *wrap_ev,
164                                                 void *private_data,
165                                                 struct tevent_context *main_ev,
166                                                 struct tevent_immediate *im,
167                                                 const char *handler_name,
168                                                 const char *location)
169 {
170         struct smbd_impersonate_debug_state *state =
171                 (struct smbd_impersonate_debug_state *)private_data;
172
173         DEBUG(state->dbg_lvl, (
174               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
175               "im[%p] handler_name[%s] location[%s]\n",
176               __func__, state->name, wrap_ev, state, main_ev,
177               im, handler_name, location));
178 }
179
180 static void smbd_impersonate_debug_before_signal_handler(struct tevent_context *wrap_ev,
181                                                 void *private_data,
182                                                 struct tevent_context *main_ev,
183                                                 struct tevent_signal *se,
184                                                 int signum,
185                                                 int count,
186                                                 void *siginfo,
187                                                 const char *handler_name,
188                                                 const char *location)
189 {
190         struct smbd_impersonate_debug_state *state =
191                 (struct smbd_impersonate_debug_state *)private_data;
192
193         DEBUG(state->dbg_lvl, (
194               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
195               "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
196               __func__, state->name, wrap_ev, state, main_ev,
197               se, signum, count, siginfo, handler_name, location));
198 }
199
200 static void smbd_impersonate_debug_after_signal_handler(struct tevent_context *wrap_ev,
201                                                 void *private_data,
202                                                 struct tevent_context *main_ev,
203                                                 struct tevent_signal *se,
204                                                 int signum,
205                                                 int count,
206                                                 void *siginfo,
207                                                 const char *handler_name,
208                                                 const char *location)
209 {
210         struct smbd_impersonate_debug_state *state =
211                 (struct smbd_impersonate_debug_state *)private_data;
212
213         DEBUG(state->dbg_lvl, (
214               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] "
215               "se[%p] signum[%d] count[%d] siginfo[%p] handler_name[%s] location[%s]\n",
216               __func__, state->name, wrap_ev, state, main_ev,
217               se, signum, count, siginfo, handler_name, location));
218 }
219
220 static const struct tevent_wrapper_ops smbd_impersonate_debug_ops = {
221         .name                           = "smbd_impersonate_debug",
222         .before_use                     = smbd_impersonate_debug_before_use,
223         .after_use                      = smbd_impersonate_debug_after_use,
224         .before_fd_handler              = smbd_impersonate_debug_before_fd_handler,
225         .after_fd_handler               = smbd_impersonate_debug_after_fd_handler,
226         .before_timer_handler           = smbd_impersonate_debug_before_timer_handler,
227         .after_timer_handler            = smbd_impersonate_debug_after_timer_handler,
228         .before_immediate_handler       = smbd_impersonate_debug_before_immediate_handler,
229         .after_immediate_handler        = smbd_impersonate_debug_after_immediate_handler,
230         .before_signal_handler          = smbd_impersonate_debug_before_signal_handler,
231         .after_signal_handler           = smbd_impersonate_debug_after_signal_handler,
232 };
233
234 struct tevent_context *_smbd_impersonate_debug_create(struct tevent_context *main_ev,
235                                                       const char *name,
236                                                       int dbg_lvl,
237                                                       const char *location)
238 {
239         struct tevent_context *wrap_ev = NULL;
240         struct smbd_impersonate_debug_state *state = NULL;
241
242         wrap_ev = tevent_context_wrapper_create(main_ev,
243                                         main_ev,
244                                         &smbd_impersonate_debug_ops,
245                                         &state,
246                                         struct smbd_impersonate_debug_state);
247         if (wrap_ev == NULL) {
248                 return NULL;
249         }
250         state->name = name;
251         state->dbg_lvl = dbg_lvl;
252         DEBUG(state->dbg_lvl, (
253               "%s: name[%s] wrap_ev[%p] state[%p] main_ev[%p] location[%s]\n",
254               __func__, state->name, wrap_ev, state, main_ev, location));
255
256         return wrap_ev;
257 }
258
259 /* what user is current? */
260 extern struct current_user current_user;
261
262 /****************************************************************************
263  Become the guest user without changing the security context stack.
264 ****************************************************************************/
265
266 bool change_to_guest(void)
267 {
268         struct passwd *pass;
269
270         pass = Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
271         if (!pass) {
272                 return false;
273         }
274
275 #ifdef AIX
276         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
277            setting IDs */
278         initgroups(pass->pw_name, pass->pw_gid);
279 #endif
280
281         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
282
283         current_user.conn = NULL;
284         current_user.vuid = UID_FIELD_INVALID;
285         current_user.need_chdir = false;
286         current_user.done_chdir = false;
287
288         TALLOC_FREE(pass);
289
290         return true;
291 }
292
293 /****************************************************************************
294  talloc free the conn->session_info if not used in the vuid cache.
295 ****************************************************************************/
296
297 static void free_conn_session_info_if_unused(connection_struct *conn)
298 {
299         unsigned int i;
300
301         for (i = 0; i < VUID_CACHE_SIZE; i++) {
302                 struct vuid_cache_entry *ent;
303                 ent = &conn->vuid_cache->array[i];
304                 if (ent->vuid != UID_FIELD_INVALID &&
305                                 conn->session_info == ent->session_info) {
306                         return;
307                 }
308         }
309         /* Not used, safe to free. */
310         conn->user_ev_ctx = NULL;
311         TALLOC_FREE(conn->session_info);
312 }
313
314 /****************************************************************************
315   Setup the share access mask for a connection.
316 ****************************************************************************/
317
318 static uint32_t create_share_access_mask(int snum,
319                                 bool readonly_share,
320                                 const struct security_token *token)
321 {
322         uint32_t share_access = 0;
323
324         share_access_check(token,
325                         lp_const_servicename(snum),
326                         MAXIMUM_ALLOWED_ACCESS,
327                         &share_access);
328
329         if (readonly_share) {
330                 share_access &=
331                         ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
332                           SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
333                           SEC_DIR_DELETE_CHILD );
334         }
335
336         if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
337                 share_access |= SEC_FLAG_SYSTEM_SECURITY;
338         }
339         if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
340                 share_access |= SEC_RIGHTS_PRIV_RESTORE;
341         }
342         if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
343                 share_access |= SEC_RIGHTS_PRIV_BACKUP;
344         }
345         if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
346                 share_access |= SEC_STD_WRITE_OWNER;
347         }
348
349         return share_access;
350 }
351
352 /*******************************************************************
353  Calculate access mask and if this user can access this share.
354 ********************************************************************/
355
356 NTSTATUS check_user_share_access(connection_struct *conn,
357                                 const struct auth_session_info *session_info,
358                                 uint32_t *p_share_access,
359                                 bool *p_readonly_share)
360 {
361         int snum = SNUM(conn);
362         uint32_t share_access = 0;
363         bool readonly_share = false;
364
365         if (!user_ok_token(session_info->unix_info->unix_name,
366                            session_info->info->domain_name,
367                            session_info->security_token, snum)) {
368                 return NT_STATUS_ACCESS_DENIED;
369         }
370
371         readonly_share = is_share_read_only_for_token(
372                 session_info->unix_info->unix_name,
373                 session_info->info->domain_name,
374                 session_info->security_token,
375                 conn);
376
377         share_access = create_share_access_mask(snum,
378                                         readonly_share,
379                                         session_info->security_token);
380
381         if ((share_access & (FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
382                 /* No access, read or write. */
383                 DBG_NOTICE("user %s connection to %s denied due to share "
384                          "security descriptor.\n",
385                          session_info->unix_info->unix_name,
386                          lp_const_servicename(snum));
387                 return NT_STATUS_ACCESS_DENIED;
388         }
389
390         if (!readonly_share &&
391             !(share_access & FILE_WRITE_DATA)) {
392                 /* smb.conf allows r/w, but the security descriptor denies
393                  * write. Fall back to looking at readonly. */
394                 readonly_share = true;
395                 DBG_INFO("falling back to read-only access-evaluation due to "
396                          "security descriptor\n");
397         }
398
399         *p_share_access = share_access;
400         *p_readonly_share = readonly_share;
401
402         return NT_STATUS_OK;
403 }
404
405 /*******************************************************************
406  Check if a username is OK.
407
408  This sets up conn->session_info with a copy related to this vuser that
409  later code can then mess with.
410 ********************************************************************/
411
412 static bool check_user_ok(connection_struct *conn,
413                         uint64_t vuid,
414                         const struct auth_session_info *session_info,
415                         int snum)
416 {
417         unsigned int i;
418         bool readonly_share = false;
419         bool admin_user = false;
420         struct vuid_cache_entry *ent = NULL;
421         uint32_t share_access = 0;
422         NTSTATUS status;
423
424         for (i=0; i<VUID_CACHE_SIZE; i++) {
425                 ent = &conn->vuid_cache->array[i];
426                 if (ent->vuid == vuid) {
427                         if (vuid == UID_FIELD_INVALID) {
428                                 /*
429                                  * Slow path, we don't care
430                                  * about the array traversal.
431                                 */
432                                 continue;
433                         }
434                         free_conn_session_info_if_unused(conn);
435                         conn->session_info = ent->session_info;
436                         conn->user_ev_ctx = ent->user_ev_ctx;
437                         conn->read_only = ent->read_only;
438                         conn->share_access = ent->share_access;
439                         conn->vuid = ent->vuid;
440                         return(True);
441                 }
442         }
443
444         status = check_user_share_access(conn,
445                                         session_info,
446                                         &share_access,
447                                         &readonly_share);
448         if (!NT_STATUS_IS_OK(status)) {
449                 return false;
450         }
451
452         admin_user = token_contains_name_in_list(
453                 session_info->unix_info->unix_name,
454                 session_info->info->domain_name,
455                 NULL, session_info->security_token, lp_admin_users(snum));
456
457         ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry];
458
459         conn->vuid_cache->next_entry =
460                 (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE;
461
462         TALLOC_FREE(ent->session_info);
463
464         /*
465          * If force_user was set, all session_info's are based on the same
466          * username-based faked one.
467          */
468
469         ent->session_info = copy_session_info(
470                 conn, conn->force_user ? conn->session_info : session_info);
471
472         if (ent->session_info == NULL) {
473                 ent->vuid = UID_FIELD_INVALID;
474                 return false;
475         }
476
477         if (admin_user) {
478                 DEBUG(2,("check_user_ok: user %s is an admin user. "
479                         "Setting uid as %d\n",
480                         ent->session_info->unix_info->unix_name,
481                         sec_initial_uid() ));
482                 ent->session_info->unix_token->uid = sec_initial_uid();
483         }
484
485         ent->user_ev_ctx = conn->sconn->raw_ev_ctx;
486
487         /*
488          * It's actually OK to call check_user_ok() with
489          * vuid == UID_FIELD_INVALID as called from change_to_user_by_session().
490          * All this will do is throw away one entry in the cache.
491          */
492
493         ent->vuid = vuid;
494         ent->read_only = readonly_share;
495         ent->share_access = share_access;
496         free_conn_session_info_if_unused(conn);
497         conn->session_info = ent->session_info;
498         conn->vuid = ent->vuid;
499         conn->user_ev_ctx = ent->user_ev_ctx;
500         if (vuid == UID_FIELD_INVALID) {
501                 /*
502                  * Not strictly needed, just make it really
503                  * clear this entry is actually an unused one.
504                  */
505                 ent->read_only = false;
506                 ent->share_access = 0;
507                 ent->session_info = NULL;
508                 ent->user_ev_ctx = NULL;
509         }
510
511         conn->read_only = readonly_share;
512         conn->share_access = share_access;
513
514         return(True);
515 }
516
517 /****************************************************************************
518  Become the user of a connection number without changing the security context
519  stack, but modify the current_user entries.
520 ****************************************************************************/
521
522 static bool change_to_user_internal(connection_struct *conn,
523                                     const struct auth_session_info *session_info,
524                                     uint64_t vuid)
525 {
526         int snum;
527         gid_t gid;
528         uid_t uid;
529         char group_c;
530         int num_groups = 0;
531         gid_t *group_list = NULL;
532         bool ok;
533
534         if ((current_user.conn == conn) &&
535             (current_user.vuid == vuid) &&
536             (current_user.need_chdir == conn->tcon_done) &&
537             (current_user.ut.uid == session_info->unix_token->uid))
538         {
539                 DBG_INFO("Skipping user change - already user\n");
540                 return true;
541         }
542
543         set_current_user_info(session_info->unix_info->sanitized_username,
544                               session_info->unix_info->unix_name,
545                               session_info->info->domain_name);
546
547         snum = SNUM(conn);
548
549         ok = check_user_ok(conn, vuid, session_info, snum);
550         if (!ok) {
551                 DBG_WARNING("SMB user %s (unix user %s) "
552                          "not permitted access to share %s.\n",
553                          session_info->unix_info->sanitized_username,
554                          session_info->unix_info->unix_name,
555                          lp_const_servicename(snum));
556                 return false;
557         }
558
559         uid = conn->session_info->unix_token->uid;
560         gid = conn->session_info->unix_token->gid;
561         num_groups = conn->session_info->unix_token->ngroups;
562         group_list  = conn->session_info->unix_token->groups;
563
564         /*
565          * See if we should force group for this service. If so this overrides
566          * any group set in the force user code.
567          */
568         if((group_c = *lp_force_group(talloc_tos(), snum))) {
569
570                 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
571
572                 if (group_c == '+') {
573                         int i;
574
575                         /*
576                          * Only force group if the user is a member of the
577                          * service group. Check the group memberships for this
578                          * user (we already have this) to see if we should force
579                          * the group.
580                          */
581                         for (i = 0; i < num_groups; i++) {
582                                 if (group_list[i] == conn->force_group_gid) {
583                                         conn->session_info->unix_token->gid =
584                                                 conn->force_group_gid;
585                                         gid = conn->force_group_gid;
586                                         gid_to_sid(&conn->session_info->security_token
587                                                    ->sids[1], gid);
588                                         break;
589                                 }
590                         }
591                 } else {
592                         conn->session_info->unix_token->gid = conn->force_group_gid;
593                         gid = conn->force_group_gid;
594                         gid_to_sid(&conn->session_info->security_token->sids[1],
595                                    gid);
596                 }
597         }
598
599         /*Set current_user since we will immediately also call set_sec_ctx() */
600         current_user.ut.ngroups = num_groups;
601         current_user.ut.groups  = group_list;
602
603         set_sec_ctx(uid,
604                     gid,
605                     current_user.ut.ngroups,
606                     current_user.ut.groups,
607                     conn->session_info->security_token);
608
609         current_user.conn = conn;
610         current_user.vuid = vuid;
611         current_user.need_chdir = conn->tcon_done;
612
613         if (current_user.need_chdir) {
614                 ok = chdir_current_service(conn);
615                 if (!ok) {
616                         DBG_ERR("chdir_current_service() failed!\n");
617                         return false;
618                 }
619                 current_user.done_chdir = true;
620         }
621
622         if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
623                 struct smb_filename *cwdfname = vfs_GetWd(talloc_tos(), conn);
624                 if (cwdfname == NULL) {
625                         return false;
626                 }
627                 DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
628                          (int)getuid(),
629                          (int)geteuid(),
630                          (int)getgid(),
631                          (int)getegid(),
632                          cwdfname->base_name);
633                 TALLOC_FREE(cwdfname);
634         }
635
636         return true;
637 }
638
639 bool change_to_user(connection_struct *conn, uint64_t vuid)
640 {
641         struct user_struct *vuser;
642         int snum = SNUM(conn);
643
644         if (!conn) {
645                 DEBUG(2,("Connection not open\n"));
646                 return(False);
647         }
648
649         vuser = get_valid_user_struct(conn->sconn, vuid);
650         if (vuser == NULL) {
651                 /* Invalid vuid sent */
652                 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
653                             (unsigned long long)vuid,
654                             lp_const_servicename(snum));
655                 return false;
656         }
657
658         return change_to_user_internal(conn, vuser->session_info, vuid);
659 }
660
661 bool change_to_user_by_fsp(struct files_struct *fsp)
662 {
663         return change_to_user(fsp->conn, fsp->vuid);
664 }
665
666 static bool change_to_user_by_session(connection_struct *conn,
667                                       const struct auth_session_info *session_info)
668 {
669         SMB_ASSERT(conn != NULL);
670         SMB_ASSERT(session_info != NULL);
671
672         return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
673 }
674
675 /****************************************************************************
676  Go back to being root without changing the security context stack,
677  but modify the current_user entries.
678 ****************************************************************************/
679
680 bool smbd_change_to_root_user(void)
681 {
682         set_root_sec_ctx();
683
684         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
685                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
686
687         current_user.conn = NULL;
688         current_user.vuid = UID_FIELD_INVALID;
689         current_user.need_chdir = false;
690         current_user.done_chdir = false;
691
692         return(True);
693 }
694
695 /****************************************************************************
696  Become the user of an authenticated connected named pipe.
697  When this is called we are currently running as the connection
698  user. Doesn't modify current_user.
699 ****************************************************************************/
700
701 bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
702 {
703         if (!push_sec_ctx())
704                 return False;
705
706         set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
707                     session_info->unix_token->ngroups, session_info->unix_token->groups,
708                     session_info->security_token);
709
710         DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
711                  (int)getuid(),
712                  (int)geteuid(),
713                  (int)getgid(),
714                  (int)getegid()));
715
716         return True;
717 }
718
719 /****************************************************************************
720  Unbecome the user of an authenticated connected named pipe.
721  When this is called we are running as the authenticated pipe
722  user and need to go back to being the connection user. Doesn't modify
723  current_user.
724 ****************************************************************************/
725
726 bool smbd_unbecome_authenticated_pipe_user(void)
727 {
728         return pop_sec_ctx();
729 }
730
731 /****************************************************************************
732  Utility functions used by become_xxx/unbecome_xxx.
733 ****************************************************************************/
734
735 static void push_conn_ctx(void)
736 {
737         struct conn_ctx *ctx_p;
738         extern userdom_struct current_user_info;
739
740         /* Check we don't overflow our stack */
741
742         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
743                 DEBUG(0, ("Connection context stack overflow!\n"));
744                 smb_panic("Connection context stack overflow!\n");
745         }
746
747         /* Store previous user context */
748         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
749
750         ctx_p->conn = current_user.conn;
751         ctx_p->vuid = current_user.vuid;
752         ctx_p->need_chdir = current_user.need_chdir;
753         ctx_p->done_chdir = current_user.done_chdir;
754         ctx_p->user_info = current_user_info;
755
756         DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
757                 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
758
759         conn_ctx_stack_ndx++;
760 }
761
762 static void pop_conn_ctx(void)
763 {
764         struct conn_ctx *ctx_p;
765
766         /* Check for stack underflow. */
767
768         if (conn_ctx_stack_ndx == 0) {
769                 DEBUG(0, ("Connection context stack underflow!\n"));
770                 smb_panic("Connection context stack underflow!\n");
771         }
772
773         conn_ctx_stack_ndx--;
774         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
775
776         set_current_user_info(ctx_p->user_info.smb_name,
777                               ctx_p->user_info.unix_name,
778                               ctx_p->user_info.domain);
779
780         /*
781          * Check if the current context did a chdir_current_service()
782          * and restore the cwd_fname of the previous context
783          * if needed.
784          */
785         if (current_user.done_chdir && ctx_p->need_chdir) {
786                 int ret;
787
788                 ret = vfs_ChDir(ctx_p->conn, ctx_p->conn->cwd_fname);
789                 if (ret != 0) {
790                         DBG_ERR("vfs_ChDir() failed!\n");
791                         smb_panic("vfs_ChDir() failed!\n");
792                 }
793         }
794
795         current_user.conn = ctx_p->conn;
796         current_user.vuid = ctx_p->vuid;
797         current_user.need_chdir = ctx_p->need_chdir;
798         current_user.done_chdir = ctx_p->done_chdir;
799
800         *ctx_p = (struct conn_ctx) {
801                 .vuid = UID_FIELD_INVALID,
802         };
803 }
804
805 /****************************************************************************
806  Temporarily become a root user.  Must match with unbecome_root(). Saves and
807  restores the connection context.
808 ****************************************************************************/
809
810 void smbd_become_root(void)
811 {
812          /*
813           * no good way to handle push_sec_ctx() failing without changing
814           * the prototype of become_root()
815           */
816         if (!push_sec_ctx()) {
817                 smb_panic("become_root: push_sec_ctx failed");
818         }
819         push_conn_ctx();
820         set_root_sec_ctx();
821 }
822
823 /* Unbecome the root user */
824
825 void smbd_unbecome_root(void)
826 {
827         pop_sec_ctx();
828         pop_conn_ctx();
829 }
830
831 bool become_guest(void)
832 {
833         bool ok;
834
835         ok = push_sec_ctx();
836         if (!ok) {
837                 return false;
838         }
839
840         push_conn_ctx();
841
842         ok = change_to_guest();
843         if (!ok) {
844                 pop_sec_ctx();
845                 pop_conn_ctx();
846                 return false;
847         }
848
849         return true;
850 }
851
852 void unbecome_guest(void)
853 {
854         pop_sec_ctx();
855         pop_conn_ctx();
856         return;
857 }
858
859 /****************************************************************************
860  Push the current security context then force a change via change_to_user().
861  Saves and restores the connection context.
862 ****************************************************************************/
863
864 bool become_user(connection_struct *conn, uint64_t vuid)
865 {
866         if (!push_sec_ctx())
867                 return False;
868
869         push_conn_ctx();
870
871         if (!change_to_user(conn, vuid)) {
872                 pop_sec_ctx();
873                 pop_conn_ctx();
874                 return False;
875         }
876
877         return True;
878 }
879
880 bool become_user_by_fsp(struct files_struct *fsp)
881 {
882         return become_user(fsp->conn, fsp->vuid);
883 }
884
885 bool become_user_by_session(connection_struct *conn,
886                             const struct auth_session_info *session_info)
887 {
888         if (!push_sec_ctx())
889                 return false;
890
891         push_conn_ctx();
892
893         if (!change_to_user_by_session(conn, session_info)) {
894                 pop_sec_ctx();
895                 pop_conn_ctx();
896                 return false;
897         }
898
899         return true;
900 }
901
902 bool unbecome_user(void)
903 {
904         pop_sec_ctx();
905         pop_conn_ctx();
906         return True;
907 }
908
909 /****************************************************************************
910  Return the current user we are running effectively as on this connection.
911  I'd like to make this return conn->session_info->unix_token->uid, but become_root()
912  doesn't alter this value.
913 ****************************************************************************/
914
915 uid_t get_current_uid(connection_struct *conn)
916 {
917         return current_user.ut.uid;
918 }
919
920 /****************************************************************************
921  Return the current group we are running effectively as on this connection.
922  I'd like to make this return conn->session_info->unix_token->gid, but become_root()
923  doesn't alter this value.
924 ****************************************************************************/
925
926 gid_t get_current_gid(connection_struct *conn)
927 {
928         return current_user.ut.gid;
929 }
930
931 /****************************************************************************
932  Return the UNIX token we are running effectively as on this connection.
933  I'd like to make this return &conn->session_info->unix_token-> but become_root()
934  doesn't alter this value.
935 ****************************************************************************/
936
937 const struct security_unix_token *get_current_utok(connection_struct *conn)
938 {
939         return &current_user.ut;
940 }
941
942 /****************************************************************************
943  Return the Windows token we are running effectively as on this connection.
944  If this is currently a NULL token as we're inside become_root() - a temporary
945  UNIX security override, then we search up the stack for the previous active
946  token.
947 ****************************************************************************/
948
949 const struct security_token *get_current_nttok(connection_struct *conn)
950 {
951         if (current_user.nt_user_token) {
952                 return current_user.nt_user_token;
953         }
954         return sec_ctx_active_token();
955 }
956
957 uint64_t get_current_vuid(connection_struct *conn)
958 {
959         return current_user.vuid;
960 }