Coverage Report

Created: 2026-05-24 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/uid.c
Line
Count
Source
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 "source3/smbd/smbXsrv_session.h"
25
#include "../librpc/gen_ndr/netlogon.h"
26
#include "libcli/security/security.h"
27
#include "passdb/lookup_sid.h"
28
#include "auth.h"
29
#include "../auth/auth_util.h"
30
#include "source3/lib/substitute.h"
31
32
/* what user is current? */
33
extern struct current_user current_user;
34
35
/****************************************************************************
36
 Become the guest user without changing the security context stack.
37
****************************************************************************/
38
39
bool change_to_guest(void)
40
0
{
41
0
  struct passwd *pass;
42
43
0
  pass = Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
44
0
  if (!pass) {
45
0
    return false;
46
0
  }
47
48
#ifdef AIX
49
  /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
50
     setting IDs */
51
  initgroups(pass->pw_name, pass->pw_gid);
52
#endif
53
54
0
  set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
55
56
0
  current_user.conn = NULL;
57
0
  current_user.vuid = UID_FIELD_INVALID;
58
59
0
  TALLOC_FREE(pass);
60
61
0
  return true;
62
0
}
63
64
/****************************************************************************
65
 talloc free the conn->session_info if not used in the vuid cache.
66
****************************************************************************/
67
68
static void free_conn_state_if_unused(connection_struct *conn)
69
0
{
70
0
  unsigned int i;
71
72
0
  for (i = 0; i < VUID_CACHE_SIZE; i++) {
73
0
    struct vuid_cache_entry *ent;
74
0
    ent = &conn->vuid_cache->array[i];
75
0
    if (ent->vuid != UID_FIELD_INVALID &&
76
0
        conn->session_info == ent->session_info) {
77
0
      break;
78
0
    }
79
0
  }
80
0
  if (i == VUID_CACHE_SIZE) {
81
    /* Not used, safe to free. */
82
0
    TALLOC_FREE(conn->session_info);
83
0
  }
84
0
}
85
86
/****************************************************************************
87
  Setup the share access mask for a connection.
88
****************************************************************************/
89
90
static uint32_t create_share_access_mask(int snum,
91
        bool readonly_share,
92
        const struct security_token *token)
93
0
{
94
0
  uint32_t share_access = 0;
95
96
0
  share_access_check(token,
97
0
      lp_const_servicename(snum),
98
0
      MAXIMUM_ALLOWED_ACCESS,
99
0
      &share_access);
100
101
0
  if (readonly_share) {
102
0
    share_access &=
103
0
      ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
104
0
        SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
105
0
        SEC_DIR_DELETE_CHILD );
106
0
  }
107
108
0
  if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
109
0
    share_access |= SEC_FLAG_SYSTEM_SECURITY;
110
0
  }
111
0
  if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
112
0
    share_access |= SEC_RIGHTS_PRIV_RESTORE;
113
0
  }
114
0
  if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
115
0
    share_access |= SEC_RIGHTS_PRIV_BACKUP;
116
0
  }
117
0
  if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
118
0
    share_access |= SEC_STD_WRITE_OWNER;
119
0
  }
120
121
0
  return share_access;
122
0
}
123
124
/*******************************************************************
125
 Calculate access mask and if this user can access this share.
126
********************************************************************/
127
128
NTSTATUS check_user_share_access(connection_struct *conn,
129
        const struct auth_session_info *session_info,
130
        uint32_t *p_share_access,
131
        bool *p_readonly_share)
132
0
{
133
0
  int snum = SNUM(conn);
134
0
  uint32_t share_access = 0;
135
0
  bool readonly_share = false;
136
0
  bool ok;
137
138
0
  if (!user_ok_token(session_info->unix_info->unix_name,
139
0
         session_info->info->domain_name,
140
0
         session_info->security_token, snum)) {
141
0
    return NT_STATUS_ACCESS_DENIED;
142
0
  }
143
144
0
  ok = is_share_read_only_for_token(
145
0
    session_info->unix_info->unix_name,
146
0
    session_info->info->domain_name,
147
0
    session_info->security_token,
148
0
    conn,
149
0
    &readonly_share);
150
0
  if (!ok) {
151
0
    return NT_STATUS_ACCESS_DENIED;
152
0
  }
153
154
0
  share_access = create_share_access_mask(snum,
155
0
          readonly_share,
156
0
          session_info->security_token);
157
158
0
  if ((share_access & (FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
159
    /* No access, read or write. */
160
0
    DBG_NOTICE("user %s connection to %s denied due to share "
161
0
       "security descriptor.\n",
162
0
       session_info->unix_info->unix_name,
163
0
       lp_const_servicename(snum));
164
0
    return NT_STATUS_ACCESS_DENIED;
165
0
  }
166
167
0
  if (!readonly_share &&
168
0
      !(share_access & FILE_WRITE_DATA)) {
169
    /* smb.conf allows r/w, but the security descriptor denies
170
     * write. Fall back to looking at readonly. */
171
0
    readonly_share = true;
172
0
    DBG_INFO("falling back to read-only access-evaluation due to "
173
0
       "security descriptor\n");
174
0
  }
175
176
0
  *p_share_access = share_access;
177
0
  *p_readonly_share = readonly_share;
178
179
0
  return NT_STATUS_OK;
180
0
}
181
182
struct scan_file_list_state {
183
  TALLOC_CTX *mem_ctx;
184
  const struct loadparm_substitution *lp_sub;
185
  int snum;
186
  const char *param_type;
187
  struct security_token *token;
188
  struct name_compare_entry **list;
189
  bool ok;
190
};
191
192
static bool scan_file_list_cb(const char *string,
193
            regmatch_t matches[],
194
            void *private_data)
195
0
{
196
0
  struct scan_file_list_state *state = private_data;
197
198
0
  if (matches[1].rm_so == -1) {
199
0
    DBG_WARNING("Found match, but no name??\n");
200
0
    goto fail;
201
0
  }
202
0
  if (matches[1].rm_eo <= matches[1].rm_so) {
203
0
    DBG_WARNING("Invalid match\n");
204
0
    goto fail;
205
0
  }
206
207
0
  {
208
0
    regoff_t len = matches[1].rm_eo - matches[1].rm_so;
209
0
    char name[len + 1];
210
0
    bool ok, match;
211
0
    char *files = NULL;
212
213
0
    memcpy(name, string + matches[1].rm_so, len);
214
0
    name[len] = '\0';
215
216
0
    DBG_DEBUG("Found name \"%s : %s\"\n", state->param_type, name);
217
218
0
    ok = token_contains_name(talloc_tos(),
219
0
           NULL,
220
0
           NULL,
221
0
           NULL,
222
0
           state->token,
223
0
           name,
224
0
           &match);
225
0
    if (!ok) {
226
0
      goto fail;
227
0
    }
228
0
    if (!match) {
229
0
      return false; /* don't stop traverse */
230
0
    }
231
232
0
    files = lp_parm_substituted_string(state->mem_ctx,
233
0
               state->lp_sub,
234
0
               state->snum,
235
0
               state->param_type,
236
0
               name,
237
0
               NULL);
238
0
    if (files == NULL) {
239
0
      goto fail;
240
0
    }
241
242
0
    ok = append_to_namearray(state->mem_ctx,
243
0
           files,
244
0
           state->list);
245
0
    if (!ok) {
246
0
      goto fail;
247
0
    }
248
249
0
    return false; /* don't stop traverse */
250
0
  }
251
252
0
fail:
253
0
  state->ok = false;
254
0
  return true; /* stop traverse */
255
0
}
256
257
/*******************************************************************
258
 Check if a username is OK.
259
260
 This sets up conn->session_info with a copy related to this vuser that
261
 later code can then mess with.
262
********************************************************************/
263
264
static bool check_user_ok(connection_struct *conn,
265
      uint64_t vuid,
266
      const struct auth_session_info *session_info,
267
      int snum)
268
0
{
269
0
  const struct loadparm_substitution *lp_sub =
270
0
    loadparm_s3_global_substitution();
271
0
  bool readonly_share = false;
272
0
  bool admin_user = false;
273
0
  struct vuid_cache_entry *ent = NULL;
274
0
  uint32_t share_access = 0;
275
0
  NTSTATUS status;
276
0
  bool ok;
277
278
0
  if (vuid != UID_FIELD_INVALID) {
279
0
    unsigned int i;
280
281
0
    for (i=0; i<VUID_CACHE_SIZE; i++) {
282
0
      ent = &conn->vuid_cache->array[i];
283
0
      if (ent->vuid == vuid) {
284
0
        free_conn_state_if_unused(conn);
285
0
        conn->session_info = ent->session_info;
286
0
        conn->read_only = ent->read_only;
287
0
        conn->share_access = ent->share_access;
288
0
        conn->vuid = ent->vuid;
289
0
        conn->veto_list = ent->veto_list;
290
0
        conn->hide_list = ent->hide_list;
291
0
        return(True);
292
0
      }
293
0
    }
294
0
  }
295
296
0
  status = check_user_share_access(conn,
297
0
          session_info,
298
0
          &share_access,
299
0
          &readonly_share);
300
0
  if (!NT_STATUS_IS_OK(status)) {
301
0
    return false;
302
0
  }
303
304
0
  ok = token_contains_name_in_list(
305
0
    session_info->unix_info->unix_name,
306
0
    session_info->info->domain_name,
307
0
    NULL,
308
0
    session_info->security_token,
309
0
    lp_admin_users(snum),
310
0
    &admin_user);
311
0
  if (!ok) {
312
    /* Log, but move on */
313
0
    DBG_ERR("Couldn't apply 'admin users'\n");
314
0
  }
315
316
0
  ent = &conn->vuid_cache->array[conn->vuid_cache->next_entry];
317
318
0
  conn->vuid_cache->next_entry =
319
0
    (conn->vuid_cache->next_entry + 1) % VUID_CACHE_SIZE;
320
321
0
  TALLOC_FREE(ent->session_info);
322
0
  TALLOC_FREE(ent->veto_list);
323
0
  TALLOC_FREE(ent->hide_list);
324
325
  /*
326
   * If force_user was set, all session_info's are based on the same
327
   * username-based faked one.
328
   */
329
330
0
  ent->session_info = copy_session_info(
331
0
    conn, conn->force_user ? conn->session_info : session_info);
332
333
0
  if (ent->session_info == NULL) {
334
0
    ent->vuid = UID_FIELD_INVALID;
335
0
    return false;
336
0
  }
337
338
0
  if (admin_user) {
339
0
    DEBUG(2,("check_user_ok: user %s is an admin user. "
340
0
      "Setting uid as %d\n",
341
0
      ent->session_info->unix_info->unix_name,
342
0
      sec_initial_uid() ));
343
0
    ent->session_info->unix_token->uid = sec_initial_uid();
344
0
  }
345
346
  /*
347
   * It's actually OK to call check_user_ok() with
348
   * vuid == UID_FIELD_INVALID as called from become_user_by_session().
349
   * All this will do is throw away one entry in the cache.
350
   */
351
352
0
  ent->vuid = vuid;
353
0
  ent->read_only = readonly_share;
354
0
  ent->share_access = share_access;
355
356
  /* Add veto/hide lists */
357
0
  if (!IS_IPC(conn) && !IS_PRINT(conn)) {
358
0
    struct scan_file_list_state state = {
359
0
      .mem_ctx = conn,
360
0
      .lp_sub = lp_sub,
361
0
      .snum = snum,
362
0
      .token = session_info->security_token,
363
0
      .ok = true,
364
0
    };
365
0
    int ret;
366
367
0
    ok = set_namearray(conn,
368
0
           lp_veto_files(talloc_tos(), lp_sub, snum),
369
0
           &ent->veto_list);
370
0
    if (!ok) {
371
0
      return false;
372
0
    }
373
374
    /*
375
     * A bit of boilerplate code duplication for userlevel
376
     * hide and veto files in the share and global
377
     * sections, but not enough to justify putting this
378
     * into functions for now :-)
379
     */
380
381
0
    state.param_type = "veto files";
382
0
    state.list = &ent->veto_list;
383
384
0
    ret = lp_wi_scan_global_parametrics("vetofiles:\\(.*\\)",
385
0
                2,
386
0
                scan_file_list_cb,
387
0
                &state);
388
0
    if ((ret != 0) || !state.ok) {
389
0
      return false;
390
0
    }
391
0
    ret = lp_wi_scan_share_parametrics(snum,
392
0
               "vetofiles:\\(.*\\)",
393
0
               2,
394
0
               scan_file_list_cb,
395
0
               &state);
396
0
    if ((ret != 0) || !state.ok) {
397
0
      return false;
398
0
    }
399
400
0
    ok = set_namearray(conn,
401
0
           lp_hide_files(talloc_tos(), lp_sub, snum),
402
0
           &ent->hide_list);
403
0
    if (!ok) {
404
0
      return false;
405
0
    }
406
407
0
    state.param_type = "hide files";
408
0
    state.list = &ent->hide_list;
409
410
0
    ret = lp_wi_scan_global_parametrics("hidefiles:\\(.*\\)",
411
0
                2,
412
0
                scan_file_list_cb,
413
0
                &state);
414
0
    if ((ret != 0) || !state.ok) {
415
0
      return false;
416
0
    }
417
0
    ret = lp_wi_scan_share_parametrics(snum,
418
0
               "hidefiles:\\(.*\\)",
419
0
               2,
420
0
               scan_file_list_cb,
421
0
               &state);
422
0
    if ((ret != 0) || !state.ok) {
423
0
      return false;
424
0
    }
425
0
  }
426
427
0
  free_conn_state_if_unused(conn);
428
0
  conn->session_info = ent->session_info;
429
0
  conn->veto_list = ent->veto_list;
430
0
  conn->hide_list = ent->hide_list;
431
0
  conn->vuid = ent->vuid;
432
0
  if (vuid == UID_FIELD_INVALID) {
433
    /*
434
     * Not strictly needed, just make it really
435
     * clear this entry is actually an unused one.
436
     */
437
0
    ent->read_only = false;
438
0
    ent->share_access = 0;
439
0
    ent->session_info = NULL;
440
0
  }
441
442
0
  conn->read_only = readonly_share;
443
0
  conn->share_access = share_access;
444
445
0
  return(True);
446
0
}
447
448
/****************************************************************************
449
 Become the user of a connection number without changing the security context
450
 stack, but modify the current_user entries.
451
****************************************************************************/
452
453
static bool change_to_user_impersonate(connection_struct *conn,
454
               const struct auth_session_info *session_info,
455
               uint64_t vuid)
456
0
{
457
0
  const struct loadparm_substitution *lp_sub =
458
0
    loadparm_s3_global_substitution();
459
0
  int snum;
460
0
  gid_t gid;
461
0
  uid_t uid;
462
0
  const char *force_group_name;
463
0
  char group_c;
464
0
  int num_groups = 0;
465
0
  gid_t *group_list = NULL;
466
0
  bool ok;
467
468
0
  if ((current_user.conn == conn) &&
469
0
      (current_user.vuid == vuid) &&
470
0
      (current_user.ut.uid == session_info->unix_token->uid))
471
0
  {
472
0
    DBG_INFO("Skipping user change - already user\n");
473
0
    return true;
474
0
  }
475
476
0
  set_current_user_info(session_info->unix_info->sanitized_username,
477
0
            session_info->unix_info->unix_name,
478
0
            session_info->info->domain_name);
479
480
0
  snum = SNUM(conn);
481
482
0
  ok = check_user_ok(conn, vuid, session_info, snum);
483
0
  if (!ok) {
484
0
    DBG_WARNING("SMB user %s (unix user %s) "
485
0
       "not permitted access to share %s.\n",
486
0
       session_info->unix_info->sanitized_username,
487
0
       session_info->unix_info->unix_name,
488
0
       lp_const_servicename(snum));
489
0
    return false;
490
0
  }
491
492
0
  uid = conn->session_info->unix_token->uid;
493
0
  gid = conn->session_info->unix_token->gid;
494
0
  num_groups = conn->session_info->unix_token->ngroups;
495
0
  group_list  = conn->session_info->unix_token->groups;
496
497
  /*
498
   * See if we should force group for this service. If so this overrides
499
   * any group set in the force user code.
500
   */
501
0
  force_group_name = lp_force_group(talloc_tos(), lp_sub, snum);
502
0
  group_c = *force_group_name;
503
504
0
  if ((group_c != '\0') && (conn->force_group_gid == (gid_t)-1)) {
505
    /*
506
     * This can happen if "force group" is added to a
507
     * share definition whilst an existing connection
508
     * to that share exists. In that case, don't change
509
     * the existing credentials for force group, only
510
     * do so for new connections.
511
     *
512
     * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
513
     */
514
0
    DBG_INFO("Not forcing group %s on existing connection to "
515
0
      "share %s for SMB user %s (unix user %s)\n",
516
0
      force_group_name,
517
0
      lp_const_servicename(snum),
518
0
      session_info->unix_info->sanitized_username,
519
0
      session_info->unix_info->unix_name);
520
0
  }
521
522
0
  if((group_c != '\0') && (conn->force_group_gid != (gid_t)-1)) {
523
    /*
524
     * Only force group for connections where
525
     * conn->force_group_gid has already been set
526
     * to the correct value (i.e. the connection
527
     * happened after the 'force group' definition
528
     * was added to the share definition. Connections
529
     * that were made before force group was added
530
     * should stay with their existing credentials.
531
     *
532
     * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
533
     */
534
535
0
    if (group_c == '+') {
536
0
      int i;
537
538
      /*
539
       * Only force group if the user is a member of the
540
       * service group. Check the group memberships for this
541
       * user (we already have this) to see if we should force
542
       * the group.
543
       */
544
0
      for (i = 0; i < num_groups; i++) {
545
0
        if (group_list[i] == conn->force_group_gid) {
546
0
          conn->session_info->unix_token->gid =
547
0
            conn->force_group_gid;
548
0
          gid = conn->force_group_gid;
549
0
          gid_to_sid(&conn->session_info->security_token
550
0
               ->sids[1], gid);
551
0
          break;
552
0
        }
553
0
      }
554
0
    } else {
555
0
      conn->session_info->unix_token->gid = conn->force_group_gid;
556
0
      gid = conn->force_group_gid;
557
0
      gid_to_sid(&conn->session_info->security_token->sids[1],
558
0
           gid);
559
0
    }
560
0
  }
561
562
0
  set_sec_ctx(uid,
563
0
        gid,
564
0
        num_groups,
565
0
        group_list,
566
0
        conn->session_info->security_token);
567
568
0
  current_user.conn = conn;
569
0
  current_user.vuid = vuid;
570
0
  return true;
571
0
}
572
573
/**
574
 * Impersonate user and change directory to service
575
 *
576
 * change_to_user_and_service() is used to impersonate the user associated with
577
 * the given vuid and to change the working directory of the process to the
578
 * service base directory.
579
 **/
580
bool change_to_user_and_service(connection_struct *conn, uint64_t vuid)
581
0
{
582
0
  int snum = SNUM(conn);
583
0
  struct auth_session_info *si = NULL;
584
0
  NTSTATUS status;
585
0
  bool ok;
586
587
0
  if (conn == NULL) {
588
0
    DBG_WARNING("Connection not open\n");
589
0
    return false;
590
0
  }
591
592
0
  status = smbXsrv_session_info_lookup(conn->sconn->client,
593
0
               vuid,
594
0
               &si);
595
0
  if (!NT_STATUS_IS_OK(status)) {
596
0
    DBG_WARNING("Invalid vuid %llu used on share %s.\n",
597
0
          (unsigned long long)vuid,
598
0
          lp_const_servicename(snum));
599
0
    return false;
600
0
  }
601
602
0
  ok = change_to_user_impersonate(conn, si, vuid);
603
0
  if (!ok) {
604
0
    return false;
605
0
  }
606
607
0
  if (conn->tcon_done) {
608
0
    ok = chdir_current_service(conn);
609
0
    if (!ok) {
610
0
      return false;
611
0
    }
612
0
  }
613
614
0
  DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
615
0
     (int)getuid(),
616
0
     (int)geteuid(),
617
0
     (int)getgid(),
618
0
     (int)getegid(),
619
0
     conn->tcon_done ? conn->connectpath : "no cwd");
620
621
0
  return true;
622
0
}
623
624
/**
625
 * Impersonate user and change directory to service
626
 *
627
 * change_to_user_and_service_by_fsp() is used to impersonate the user
628
 * associated with the given vuid and to change the working directory of the
629
 * process to the service base directory.
630
 **/
631
bool change_to_user_and_service_by_fsp(struct files_struct *fsp)
632
0
{
633
0
  return change_to_user_and_service(fsp->conn, fsp->vuid);
634
0
}
635
636
/****************************************************************************
637
 Go back to being root without changing the security context stack,
638
 but modify the current_user entries.
639
****************************************************************************/
640
641
bool smbd_change_to_root_user(void)
642
0
{
643
0
  set_root_sec_ctx();
644
645
0
  DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
646
0
    (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
647
648
0
  current_user.conn = NULL;
649
0
  current_user.vuid = UID_FIELD_INVALID;
650
651
0
  return(True);
652
0
}
653
654
/****************************************************************************
655
 Become the user of an authenticated connected named pipe.
656
 When this is called we are currently running as the connection
657
 user. Doesn't modify current_user.
658
****************************************************************************/
659
660
bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
661
0
{
662
0
  if (!push_sec_ctx())
663
0
    return False;
664
665
0
  set_current_user_info(session_info->unix_info->sanitized_username,
666
0
            session_info->unix_info->unix_name,
667
0
            session_info->info->domain_name);
668
669
0
  set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
670
0
        session_info->unix_token->ngroups, session_info->unix_token->groups,
671
0
        session_info->security_token);
672
673
0
  DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
674
0
     (int)getuid(),
675
0
     (int)geteuid(),
676
0
     (int)getgid(),
677
0
     (int)getegid()));
678
679
0
  return True;
680
0
}
681
682
/****************************************************************************
683
 Unbecome the user of an authenticated connected named pipe.
684
 When this is called we are running as the authenticated pipe
685
 user and need to go back to being the connection user. Doesn't modify
686
 current_user.
687
****************************************************************************/
688
689
bool smbd_unbecome_authenticated_pipe_user(void)
690
0
{
691
0
  return pop_sec_ctx();
692
0
}
693
694
/****************************************************************************
695
 Utility functions used by become_xxx/unbecome_xxx.
696
****************************************************************************/
697
698
static void push_conn_ctx(void)
699
0
{
700
0
  struct conn_ctx *ctx_p;
701
0
  extern userdom_struct current_user_info;
702
703
  /* Check we don't overflow our stack */
704
705
0
  if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
706
0
    DEBUG(0, ("Connection context stack overflow!\n"));
707
0
    smb_panic("Connection context stack overflow!\n");
708
0
  }
709
710
  /* Store previous user context */
711
0
  ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
712
713
0
  ctx_p->conn = current_user.conn;
714
0
  ctx_p->vuid = current_user.vuid;
715
0
  ctx_p->user_info = current_user_info;
716
717
0
  DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
718
0
    (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
719
720
0
  conn_ctx_stack_ndx++;
721
0
}
722
723
static void pop_conn_ctx(void)
724
0
{
725
0
  struct conn_ctx *ctx_p;
726
727
  /* Check for stack underflow. */
728
729
0
  if (conn_ctx_stack_ndx == 0) {
730
0
    DEBUG(0, ("Connection context stack underflow!\n"));
731
0
    smb_panic("Connection context stack underflow!\n");
732
0
  }
733
734
0
  conn_ctx_stack_ndx--;
735
0
  ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
736
737
0
  set_current_user_info(ctx_p->user_info.smb_name,
738
0
            ctx_p->user_info.unix_name,
739
0
            ctx_p->user_info.domain);
740
741
0
  current_user.conn = ctx_p->conn;
742
0
  current_user.vuid = ctx_p->vuid;
743
744
0
  *ctx_p = (struct conn_ctx) {
745
0
    .vuid = UID_FIELD_INVALID,
746
0
  };
747
0
}
748
749
/****************************************************************************
750
 Temporarily become a root user.  Must match with unbecome_root(). Saves and
751
 restores the connection context.
752
****************************************************************************/
753
754
void smbd_become_root(void)
755
0
{
756
   /*
757
    * no good way to handle push_sec_ctx() failing without changing
758
    * the prototype of become_root()
759
    */
760
0
  if (!push_sec_ctx()) {
761
0
    smb_panic("become_root: push_sec_ctx failed");
762
0
  }
763
0
  push_conn_ctx();
764
0
  set_root_sec_ctx();
765
0
}
766
767
/* Unbecome the root user */
768
769
void smbd_unbecome_root(void)
770
0
{
771
0
  pop_sec_ctx();
772
0
  pop_conn_ctx();
773
0
}
774
775
/****************************************************************************
776
 Push the current security context then force a change via change_to_user().
777
 Saves and restores the connection context.
778
****************************************************************************/
779
780
bool become_user_without_service(connection_struct *conn, uint64_t vuid)
781
0
{
782
0
  struct auth_session_info *session_info = NULL;
783
0
  int snum = SNUM(conn);
784
0
  NTSTATUS status;
785
0
  bool ok;
786
787
0
  if (conn == NULL) {
788
0
    DBG_WARNING("Connection not open\n");
789
0
    return false;
790
0
  }
791
792
0
  status = smbXsrv_session_info_lookup(conn->sconn->client,
793
0
               vuid,
794
0
               &session_info);
795
0
  if (!NT_STATUS_IS_OK(status)) {
796
    /* Invalid vuid sent */
797
0
    DBG_WARNING("Invalid vuid %llu used on share %s.\n",
798
0
          (unsigned long long)vuid,
799
0
          lp_const_servicename(snum));
800
0
    return false;
801
0
  }
802
803
0
  ok = push_sec_ctx();
804
0
  if (!ok) {
805
0
    return false;
806
0
  }
807
808
0
  push_conn_ctx();
809
810
0
  ok = change_to_user_impersonate(conn, session_info, vuid);
811
0
  if (!ok) {
812
0
    pop_sec_ctx();
813
0
    pop_conn_ctx();
814
0
    return false;
815
0
  }
816
817
0
  return true;
818
0
}
819
820
bool become_user_without_service_by_fsp(struct files_struct *fsp)
821
0
{
822
0
  return become_user_without_service(fsp->conn, fsp->vuid);
823
0
}
824
825
bool become_user_without_service_by_session(connection_struct *conn,
826
          const struct auth_session_info *session_info)
827
0
{
828
0
  bool ok;
829
830
0
  SMB_ASSERT(conn != NULL);
831
0
  SMB_ASSERT(session_info != NULL);
832
833
0
  ok = push_sec_ctx();
834
0
  if (!ok) {
835
0
    return false;
836
0
  }
837
838
0
  push_conn_ctx();
839
840
0
  ok = change_to_user_impersonate(conn, session_info, UID_FIELD_INVALID);
841
0
  if (!ok) {
842
0
    pop_sec_ctx();
843
0
    pop_conn_ctx();
844
0
    return false;
845
0
  }
846
847
0
  return true;
848
0
}
849
850
bool unbecome_user_without_service(void)
851
0
{
852
0
  pop_sec_ctx();
853
0
  pop_conn_ctx();
854
0
  return True;
855
0
}
856
857
/****************************************************************************
858
 Return the current user we are running effectively as on this connection.
859
 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
860
 doesn't alter this value.
861
****************************************************************************/
862
863
uid_t get_current_uid(connection_struct *conn)
864
0
{
865
0
  return current_user.ut.uid;
866
0
}
867
868
/****************************************************************************
869
 Return the current group we are running effectively as on this connection.
870
 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
871
 doesn't alter this value.
872
****************************************************************************/
873
874
gid_t get_current_gid(connection_struct *conn)
875
0
{
876
0
  return current_user.ut.gid;
877
0
}
878
879
/****************************************************************************
880
 Return the UNIX token we are running effectively as on this connection.
881
 I'd like to make this return &conn->session_info->unix_token-> but become_root()
882
 doesn't alter this value.
883
****************************************************************************/
884
885
const struct security_unix_token *get_current_utok(connection_struct *conn)
886
0
{
887
0
  return &current_user.ut;
888
0
}
889
890
/****************************************************************************
891
 Return the Windows token we are running effectively as on this connection.
892
 If this is currently a NULL token as we're inside become_root() - a temporary
893
 UNIX security override, then we search up the stack for the previous active
894
 token.
895
****************************************************************************/
896
897
const struct security_token *get_current_nttok(connection_struct *conn)
898
0
{
899
0
  if (current_user.nt_user_token) {
900
0
    return current_user.nt_user_token;
901
0
  }
902
0
  return sec_ctx_active_token();
903
0
}