Coverage Report

Created: 2026-02-14 07:07

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
static void print_impersonation_info(connection_struct *conn)
449
0
{
450
0
  struct smb_filename *cwdfname = NULL;
451
452
0
  if (!CHECK_DEBUGLVL(DBGLVL_INFO)) {
453
0
    return;
454
0
  }
455
456
0
  if (conn->tcon_done) {
457
0
    cwdfname = vfs_GetWd(talloc_tos(), conn);
458
0
  }
459
460
0
  DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
461
0
     (int)getuid(),
462
0
     (int)geteuid(),
463
0
     (int)getgid(),
464
0
     (int)getegid(),
465
0
     cwdfname ? cwdfname->base_name : "no cwd");
466
0
  TALLOC_FREE(cwdfname);
467
0
}
468
469
/****************************************************************************
470
 Become the user of a connection number without changing the security context
471
 stack, but modify the current_user entries.
472
****************************************************************************/
473
474
static bool change_to_user_impersonate(connection_struct *conn,
475
               const struct auth_session_info *session_info,
476
               uint64_t vuid)
477
0
{
478
0
  const struct loadparm_substitution *lp_sub =
479
0
    loadparm_s3_global_substitution();
480
0
  int snum;
481
0
  gid_t gid;
482
0
  uid_t uid;
483
0
  const char *force_group_name;
484
0
  char group_c;
485
0
  int num_groups = 0;
486
0
  gid_t *group_list = NULL;
487
0
  bool ok;
488
489
0
  if ((current_user.conn == conn) &&
490
0
      (current_user.vuid == vuid) &&
491
0
      (current_user.ut.uid == session_info->unix_token->uid))
492
0
  {
493
0
    DBG_INFO("Skipping user change - already user\n");
494
0
    return true;
495
0
  }
496
497
0
  set_current_user_info(session_info->unix_info->sanitized_username,
498
0
            session_info->unix_info->unix_name,
499
0
            session_info->info->domain_name);
500
501
0
  snum = SNUM(conn);
502
503
0
  ok = check_user_ok(conn, vuid, session_info, snum);
504
0
  if (!ok) {
505
0
    DBG_WARNING("SMB user %s (unix user %s) "
506
0
       "not permitted access to share %s.\n",
507
0
       session_info->unix_info->sanitized_username,
508
0
       session_info->unix_info->unix_name,
509
0
       lp_const_servicename(snum));
510
0
    return false;
511
0
  }
512
513
0
  uid = conn->session_info->unix_token->uid;
514
0
  gid = conn->session_info->unix_token->gid;
515
0
  num_groups = conn->session_info->unix_token->ngroups;
516
0
  group_list  = conn->session_info->unix_token->groups;
517
518
  /*
519
   * See if we should force group for this service. If so this overrides
520
   * any group set in the force user code.
521
   */
522
0
  force_group_name = lp_force_group(talloc_tos(), lp_sub, snum);
523
0
  group_c = *force_group_name;
524
525
0
  if ((group_c != '\0') && (conn->force_group_gid == (gid_t)-1)) {
526
    /*
527
     * This can happen if "force group" is added to a
528
     * share definition whilst an existing connection
529
     * to that share exists. In that case, don't change
530
     * the existing credentials for force group, only
531
     * do so for new connections.
532
     *
533
     * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
534
     */
535
0
    DBG_INFO("Not forcing group %s on existing connection to "
536
0
      "share %s for SMB user %s (unix user %s)\n",
537
0
      force_group_name,
538
0
      lp_const_servicename(snum),
539
0
      session_info->unix_info->sanitized_username,
540
0
      session_info->unix_info->unix_name);
541
0
  }
542
543
0
  if((group_c != '\0') && (conn->force_group_gid != (gid_t)-1)) {
544
    /*
545
     * Only force group for connections where
546
     * conn->force_group_gid has already been set
547
     * to the correct value (i.e. the connection
548
     * happened after the 'force group' definition
549
     * was added to the share definition. Connections
550
     * that were made before force group was added
551
     * should stay with their existing credentials.
552
     *
553
     * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
554
     */
555
556
0
    if (group_c == '+') {
557
0
      int i;
558
559
      /*
560
       * Only force group if the user is a member of the
561
       * service group. Check the group memberships for this
562
       * user (we already have this) to see if we should force
563
       * the group.
564
       */
565
0
      for (i = 0; i < num_groups; i++) {
566
0
        if (group_list[i] == conn->force_group_gid) {
567
0
          conn->session_info->unix_token->gid =
568
0
            conn->force_group_gid;
569
0
          gid = conn->force_group_gid;
570
0
          gid_to_sid(&conn->session_info->security_token
571
0
               ->sids[1], gid);
572
0
          break;
573
0
        }
574
0
      }
575
0
    } else {
576
0
      conn->session_info->unix_token->gid = conn->force_group_gid;
577
0
      gid = conn->force_group_gid;
578
0
      gid_to_sid(&conn->session_info->security_token->sids[1],
579
0
           gid);
580
0
    }
581
0
  }
582
583
0
  set_sec_ctx(uid,
584
0
        gid,
585
0
        num_groups,
586
0
        group_list,
587
0
        conn->session_info->security_token);
588
589
0
  current_user.conn = conn;
590
0
  current_user.vuid = vuid;
591
0
  return true;
592
0
}
593
594
/**
595
 * Impersonate user and change directory to service
596
 *
597
 * change_to_user_and_service() is used to impersonate the user associated with
598
 * the given vuid and to change the working directory of the process to the
599
 * service base directory.
600
 **/
601
bool change_to_user_and_service(connection_struct *conn, uint64_t vuid)
602
0
{
603
0
  int snum = SNUM(conn);
604
0
  struct auth_session_info *si = NULL;
605
0
  NTSTATUS status;
606
0
  bool ok;
607
608
0
  if (conn == NULL) {
609
0
    DBG_WARNING("Connection not open\n");
610
0
    return false;
611
0
  }
612
613
0
  status = smbXsrv_session_info_lookup(conn->sconn->client,
614
0
               vuid,
615
0
               &si);
616
0
  if (!NT_STATUS_IS_OK(status)) {
617
0
    DBG_WARNING("Invalid vuid %llu used on share %s.\n",
618
0
          (unsigned long long)vuid,
619
0
          lp_const_servicename(snum));
620
0
    return false;
621
0
  }
622
623
0
  ok = change_to_user_impersonate(conn, si, vuid);
624
0
  if (!ok) {
625
0
    return false;
626
0
  }
627
628
0
  if (conn->tcon_done) {
629
0
    ok = chdir_current_service(conn);
630
0
    if (!ok) {
631
0
      return false;
632
0
    }
633
0
  }
634
635
0
  print_impersonation_info(conn);
636
0
  return true;
637
0
}
638
639
/**
640
 * Impersonate user and change directory to service
641
 *
642
 * change_to_user_and_service_by_fsp() is used to impersonate the user
643
 * associated with the given vuid and to change the working directory of the
644
 * process to the service base directory.
645
 **/
646
bool change_to_user_and_service_by_fsp(struct files_struct *fsp)
647
0
{
648
0
  return change_to_user_and_service(fsp->conn, fsp->vuid);
649
0
}
650
651
/****************************************************************************
652
 Go back to being root without changing the security context stack,
653
 but modify the current_user entries.
654
****************************************************************************/
655
656
bool smbd_change_to_root_user(void)
657
0
{
658
0
  set_root_sec_ctx();
659
660
0
  DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
661
0
    (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
662
663
0
  current_user.conn = NULL;
664
0
  current_user.vuid = UID_FIELD_INVALID;
665
666
0
  return(True);
667
0
}
668
669
/****************************************************************************
670
 Become the user of an authenticated connected named pipe.
671
 When this is called we are currently running as the connection
672
 user. Doesn't modify current_user.
673
****************************************************************************/
674
675
bool smbd_become_authenticated_pipe_user(struct auth_session_info *session_info)
676
0
{
677
0
  if (!push_sec_ctx())
678
0
    return False;
679
680
0
  set_current_user_info(session_info->unix_info->sanitized_username,
681
0
            session_info->unix_info->unix_name,
682
0
            session_info->info->domain_name);
683
684
0
  set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
685
0
        session_info->unix_token->ngroups, session_info->unix_token->groups,
686
0
        session_info->security_token);
687
688
0
  DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
689
0
     (int)getuid(),
690
0
     (int)geteuid(),
691
0
     (int)getgid(),
692
0
     (int)getegid()));
693
694
0
  return True;
695
0
}
696
697
/****************************************************************************
698
 Unbecome the user of an authenticated connected named pipe.
699
 When this is called we are running as the authenticated pipe
700
 user and need to go back to being the connection user. Doesn't modify
701
 current_user.
702
****************************************************************************/
703
704
bool smbd_unbecome_authenticated_pipe_user(void)
705
0
{
706
0
  return pop_sec_ctx();
707
0
}
708
709
/****************************************************************************
710
 Utility functions used by become_xxx/unbecome_xxx.
711
****************************************************************************/
712
713
static void push_conn_ctx(void)
714
0
{
715
0
  struct conn_ctx *ctx_p;
716
0
  extern userdom_struct current_user_info;
717
718
  /* Check we don't overflow our stack */
719
720
0
  if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
721
0
    DEBUG(0, ("Connection context stack overflow!\n"));
722
0
    smb_panic("Connection context stack overflow!\n");
723
0
  }
724
725
  /* Store previous user context */
726
0
  ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
727
728
0
  ctx_p->conn = current_user.conn;
729
0
  ctx_p->vuid = current_user.vuid;
730
0
  ctx_p->user_info = current_user_info;
731
732
0
  DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
733
0
    (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
734
735
0
  conn_ctx_stack_ndx++;
736
0
}
737
738
static void pop_conn_ctx(void)
739
0
{
740
0
  struct conn_ctx *ctx_p;
741
742
  /* Check for stack underflow. */
743
744
0
  if (conn_ctx_stack_ndx == 0) {
745
0
    DEBUG(0, ("Connection context stack underflow!\n"));
746
0
    smb_panic("Connection context stack underflow!\n");
747
0
  }
748
749
0
  conn_ctx_stack_ndx--;
750
0
  ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
751
752
0
  set_current_user_info(ctx_p->user_info.smb_name,
753
0
            ctx_p->user_info.unix_name,
754
0
            ctx_p->user_info.domain);
755
756
0
  current_user.conn = ctx_p->conn;
757
0
  current_user.vuid = ctx_p->vuid;
758
759
0
  *ctx_p = (struct conn_ctx) {
760
0
    .vuid = UID_FIELD_INVALID,
761
0
  };
762
0
}
763
764
/****************************************************************************
765
 Temporarily become a root user.  Must match with unbecome_root(). Saves and
766
 restores the connection context.
767
****************************************************************************/
768
769
void smbd_become_root(void)
770
0
{
771
   /*
772
    * no good way to handle push_sec_ctx() failing without changing
773
    * the prototype of become_root()
774
    */
775
0
  if (!push_sec_ctx()) {
776
0
    smb_panic("become_root: push_sec_ctx failed");
777
0
  }
778
0
  push_conn_ctx();
779
0
  set_root_sec_ctx();
780
0
}
781
782
/* Unbecome the root user */
783
784
void smbd_unbecome_root(void)
785
0
{
786
0
  pop_sec_ctx();
787
0
  pop_conn_ctx();
788
0
}
789
790
/****************************************************************************
791
 Push the current security context then force a change via change_to_user().
792
 Saves and restores the connection context.
793
****************************************************************************/
794
795
bool become_user_without_service(connection_struct *conn, uint64_t vuid)
796
0
{
797
0
  struct auth_session_info *session_info = NULL;
798
0
  int snum = SNUM(conn);
799
0
  NTSTATUS status;
800
0
  bool ok;
801
802
0
  if (conn == NULL) {
803
0
    DBG_WARNING("Connection not open\n");
804
0
    return false;
805
0
  }
806
807
0
  status = smbXsrv_session_info_lookup(conn->sconn->client,
808
0
               vuid,
809
0
               &session_info);
810
0
  if (!NT_STATUS_IS_OK(status)) {
811
    /* Invalid vuid sent */
812
0
    DBG_WARNING("Invalid vuid %llu used on share %s.\n",
813
0
          (unsigned long long)vuid,
814
0
          lp_const_servicename(snum));
815
0
    return false;
816
0
  }
817
818
0
  ok = push_sec_ctx();
819
0
  if (!ok) {
820
0
    return false;
821
0
  }
822
823
0
  push_conn_ctx();
824
825
0
  ok = change_to_user_impersonate(conn, session_info, vuid);
826
0
  if (!ok) {
827
0
    pop_sec_ctx();
828
0
    pop_conn_ctx();
829
0
    return false;
830
0
  }
831
832
0
  return true;
833
0
}
834
835
bool become_user_without_service_by_fsp(struct files_struct *fsp)
836
0
{
837
0
  return become_user_without_service(fsp->conn, fsp->vuid);
838
0
}
839
840
bool become_user_without_service_by_session(connection_struct *conn,
841
          const struct auth_session_info *session_info)
842
0
{
843
0
  bool ok;
844
845
0
  SMB_ASSERT(conn != NULL);
846
0
  SMB_ASSERT(session_info != NULL);
847
848
0
  ok = push_sec_ctx();
849
0
  if (!ok) {
850
0
    return false;
851
0
  }
852
853
0
  push_conn_ctx();
854
855
0
  ok = change_to_user_impersonate(conn, session_info, UID_FIELD_INVALID);
856
0
  if (!ok) {
857
0
    pop_sec_ctx();
858
0
    pop_conn_ctx();
859
0
    return false;
860
0
  }
861
862
0
  return true;
863
0
}
864
865
bool unbecome_user_without_service(void)
866
0
{
867
0
  pop_sec_ctx();
868
0
  pop_conn_ctx();
869
0
  return True;
870
0
}
871
872
/****************************************************************************
873
 Return the current user we are running effectively as on this connection.
874
 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
875
 doesn't alter this value.
876
****************************************************************************/
877
878
uid_t get_current_uid(connection_struct *conn)
879
0
{
880
0
  return current_user.ut.uid;
881
0
}
882
883
/****************************************************************************
884
 Return the current group we are running effectively as on this connection.
885
 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
886
 doesn't alter this value.
887
****************************************************************************/
888
889
gid_t get_current_gid(connection_struct *conn)
890
0
{
891
0
  return current_user.ut.gid;
892
0
}
893
894
/****************************************************************************
895
 Return the UNIX token we are running effectively as on this connection.
896
 I'd like to make this return &conn->session_info->unix_token-> but become_root()
897
 doesn't alter this value.
898
****************************************************************************/
899
900
const struct security_unix_token *get_current_utok(connection_struct *conn)
901
0
{
902
0
  return &current_user.ut;
903
0
}
904
905
/****************************************************************************
906
 Return the Windows token we are running effectively as on this connection.
907
 If this is currently a NULL token as we're inside become_root() - a temporary
908
 UNIX security override, then we search up the stack for the previous active
909
 token.
910
****************************************************************************/
911
912
const struct security_token *get_current_nttok(connection_struct *conn)
913
0
{
914
0
  if (current_user.nt_user_token) {
915
0
    return current_user.nt_user_token;
916
0
  }
917
0
  return sec_ctx_active_token();
918
0
}