Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/auth/server_info.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Authentication utility functions
4
   Copyright (C) Volker Lendecke 2010
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 "auth.h"
22
#include "lib/util_unixsids.h"
23
#include "../librpc/gen_ndr/netlogon.h"
24
#include "../libcli/security/security.h"
25
#include "rpc_client/util_netlogon.h"
26
#include "nsswitch/libwbclient/wbclient.h"
27
#include "lib/winbind_util.h"
28
#include "passdb.h"
29
30
#undef DBGC_CLASS
31
0
#define DBGC_CLASS DBGC_AUTH
32
33
/***************************************************************************
34
 Make a server_info struct. Free with TALLOC_FREE().
35
***************************************************************************/
36
37
struct auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
38
0
{
39
0
  struct auth_serversupplied_info *result;
40
41
0
  result = talloc_zero(mem_ctx, struct auth_serversupplied_info);
42
0
  if (result == NULL) {
43
0
    DEBUG(0, ("talloc failed\n"));
44
0
    return NULL;
45
0
  }
46
47
  /* Initialise the uid and gid values to something non-zero
48
     which may save us from giving away root access if there
49
     is a bug in allocating these fields. */
50
51
0
  result->utok.uid = -1;
52
0
  result->utok.gid = -1;
53
54
0
  return result;
55
0
}
56
57
/****************************************************************************
58
 inits a netr_SamInfo2 structure from an auth_serversupplied_info. sam2 must
59
 already be initialized and is used as the talloc parent for its members.
60
*****************************************************************************/
61
62
NTSTATUS serverinfo_to_SamInfo2(struct auth_serversupplied_info *server_info,
63
        struct netr_SamInfo2 *sam2)
64
0
{
65
0
  struct netr_SamInfo3 *info3 = NULL;
66
0
  NTSTATUS status;
67
68
0
  status = copy_netr_SamInfo3(sam2,
69
0
            server_info->info3,
70
0
            &info3);
71
0
  if (!NT_STATUS_IS_OK(status)) {
72
0
    return status;
73
0
  }
74
75
0
  if (server_info->session_key.length) {
76
0
    memcpy(info3->base.key.key,
77
0
           server_info->session_key.data,
78
0
           MIN(sizeof(info3->base.key.key),
79
0
         server_info->session_key.length));
80
0
  }
81
0
  if (server_info->lm_session_key.length) {
82
0
    memcpy(info3->base.LMSessKey.key,
83
0
           server_info->lm_session_key.data,
84
0
           MIN(sizeof(info3->base.LMSessKey.key),
85
0
         server_info->lm_session_key.length));
86
0
  }
87
88
0
  sam2->base = info3->base;
89
90
0
  return NT_STATUS_OK;
91
0
}
92
93
/****************************************************************************
94
 inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
95
 already be initialized and is used as the talloc parent for its members.
96
*****************************************************************************/
97
98
NTSTATUS serverinfo_to_SamInfo3(const struct auth_serversupplied_info *server_info,
99
        struct netr_SamInfo3 *sam3)
100
0
{
101
0
  struct netr_SamInfo3 *info3 = NULL;
102
0
  NTSTATUS status;
103
104
0
  status = copy_netr_SamInfo3(sam3,
105
0
            server_info->info3,
106
0
            &info3);
107
0
  if (!NT_STATUS_IS_OK(status)) {
108
0
    return status;
109
0
  }
110
111
0
  if (server_info->session_key.length) {
112
0
    memcpy(info3->base.key.key,
113
0
           server_info->session_key.data,
114
0
           MIN(sizeof(info3->base.key.key),
115
0
         server_info->session_key.length));
116
0
  }
117
0
  if (server_info->lm_session_key.length) {
118
0
    memcpy(info3->base.LMSessKey.key,
119
0
           server_info->lm_session_key.data,
120
0
           MIN(sizeof(info3->base.LMSessKey.key),
121
0
         server_info->lm_session_key.length));
122
0
  }
123
124
0
  sam3->base = info3->base;
125
126
0
  sam3->sidcount    = 0;
127
0
  sam3->sids    = NULL;
128
129
0
  return NT_STATUS_OK;
130
0
}
131
132
/****************************************************************************
133
 inits a netr_SamInfo6 structure from an auth_serversupplied_info. sam6 must
134
 already be initialized and is used as the talloc parent for its members.
135
*****************************************************************************/
136
137
NTSTATUS serverinfo_to_SamInfo6(struct auth_serversupplied_info *server_info,
138
        struct netr_SamInfo6 *sam6)
139
0
{
140
0
  struct pdb_domain_info *dominfo;
141
0
  struct netr_SamInfo3 *info3 = NULL;
142
0
  NTSTATUS status;
143
144
0
  if ((pdb_capabilities() & PDB_CAP_ADS) == 0) {
145
0
    DEBUG(10,("Not adding validation info level 6 "
146
0
         "without ADS passdb backend\n"));
147
0
    return NT_STATUS_INVALID_INFO_CLASS;
148
0
  }
149
150
0
  dominfo = pdb_get_domain_info(sam6);
151
0
  if (dominfo == NULL) {
152
0
    return NT_STATUS_NO_MEMORY;
153
0
  }
154
155
0
  status = copy_netr_SamInfo3(sam6,
156
0
            server_info->info3,
157
0
            &info3);
158
0
  if (!NT_STATUS_IS_OK(status)) {
159
0
    return status;
160
0
  }
161
162
0
  if (server_info->session_key.length) {
163
0
    memcpy(info3->base.key.key,
164
0
           server_info->session_key.data,
165
0
           MIN(sizeof(info3->base.key.key),
166
0
         server_info->session_key.length));
167
0
  }
168
0
  if (server_info->lm_session_key.length) {
169
0
    memcpy(info3->base.LMSessKey.key,
170
0
           server_info->lm_session_key.data,
171
0
           MIN(sizeof(info3->base.LMSessKey.key),
172
0
         server_info->lm_session_key.length));
173
0
  }
174
175
0
  sam6->base = info3->base;
176
177
0
  sam6->sidcount    = 0;
178
0
  sam6->sids    = NULL;
179
180
0
  sam6->dns_domainname.string = talloc_strdup(sam6, dominfo->dns_domain);
181
0
  if (sam6->dns_domainname.string == NULL) {
182
0
    return NT_STATUS_NO_MEMORY;
183
0
  }
184
185
0
  sam6->principal_name.string = talloc_asprintf(
186
0
    sam6, "%s@%s", sam6->base.account_name.string,
187
0
    sam6->dns_domainname.string);
188
0
  if (sam6->principal_name.string == NULL) {
189
0
    return NT_STATUS_NO_MEMORY;
190
0
  }
191
192
0
  return NT_STATUS_OK;
193
0
}
194
195
static NTSTATUS append_netr_SidAttr(TALLOC_CTX *mem_ctx,
196
            struct netr_SidAttr **sids,
197
            uint32_t *count,
198
            const struct dom_sid2 *asid,
199
            uint32_t attributes)
200
0
{
201
0
  uint32_t t = *count;
202
203
0
  *sids = talloc_realloc(mem_ctx, *sids, struct netr_SidAttr, t + 1);
204
0
  if (*sids == NULL) {
205
0
    return NT_STATUS_NO_MEMORY;
206
0
  }
207
0
  (*sids)[t].sid = dom_sid_dup(*sids, asid);
208
0
  if ((*sids)[t].sid == NULL) {
209
0
    return NT_STATUS_NO_MEMORY;
210
0
  }
211
0
  (*sids)[t].attributes = attributes;
212
0
  *count = t + 1;
213
214
0
  return NT_STATUS_OK;
215
0
}
216
217
/* Fills the samr_RidWithAttributeArray with the provided sids.
218
 * If it happens that we have additional groups that do not belong
219
 * to the domain, add their sids as extra sids */
220
static NTSTATUS group_sids_to_info3(struct netr_SamInfo3 *info3,
221
            const struct dom_sid *sids,
222
            size_t num_sids)
223
0
{
224
0
  uint32_t attributes = SE_GROUP_DEFAULT_FLAGS;
225
0
  struct samr_RidWithAttributeArray *groups;
226
0
  struct dom_sid *domain_sid;
227
0
  unsigned int i;
228
0
  NTSTATUS status;
229
0
  uint32_t rid;
230
0
  bool ok;
231
232
0
  domain_sid = info3->base.domain_sid;
233
0
  groups = &info3->base.groups;
234
235
0
  groups->rids = talloc_array(info3,
236
0
            struct samr_RidWithAttribute, num_sids);
237
0
  if (!groups->rids) {
238
0
    return NT_STATUS_NO_MEMORY;
239
0
  }
240
241
0
  for (i = 0; i < num_sids; i++) {
242
0
    ok = sid_peek_check_rid(domain_sid, &sids[i], &rid);
243
0
    if (ok) {
244
      /* store domain group rid */
245
0
      groups->rids[groups->count].rid = rid;
246
0
      groups->rids[groups->count].attributes = attributes;
247
0
      groups->count++;
248
0
      continue;
249
0
    }
250
251
    /* if this wasn't a domain sid, add it as extra sid */
252
0
    status = append_netr_SidAttr(info3, &info3->sids,
253
0
               &info3->sidcount,
254
0
               &sids[i], attributes);
255
0
    if (!NT_STATUS_IS_OK(status)) {
256
0
      return status;
257
0
    }
258
0
  }
259
260
0
  return NT_STATUS_OK;
261
0
}
262
263
/*
264
 * Merge resource SIDs, if any, into the passed in info3 structure.
265
 */
266
267
static NTSTATUS merge_resource_sids(const struct PAC_LOGON_INFO *logon_info,
268
        struct netr_SamInfo3 *info3)
269
0
{
270
0
  uint32_t i = 0;
271
0
  const struct PAC_DOMAIN_GROUP_MEMBERSHIP *rg = NULL;
272
273
0
  if (logon_info->info3.base.user_flags & NETLOGON_RESOURCE_GROUPS) {
274
0
    rg = &logon_info->resource_groups;
275
0
  }
276
277
0
  if (rg == NULL) {
278
0
    return NT_STATUS_OK;
279
0
  }
280
281
0
  if (rg->domain_sid == NULL) {
282
0
    DEBUG(10, ("Missing Resource Group Domain SID\n"));
283
0
    return NT_STATUS_INVALID_PARAMETER;
284
0
  }
285
286
  /* The IDL layer would be a better place to check this, but to
287
   * guard the integer addition below, we double-check */
288
0
  if (rg->groups.count > 65535) {
289
0
    DEBUG(10, ("Too much Resource Group RIDs %u\n",
290
0
        (unsigned)rg->groups.count));
291
0
    return NT_STATUS_INVALID_PARAMETER;
292
0
  }
293
294
  /*
295
   * If there are any resource groups (SID Compression) add
296
   * them to the extra sids portion of the info3 in the PAC.
297
   *
298
   * This makes the info3 look like it would if we got the info
299
   * from the DC rather than the PAC.
300
   */
301
302
  /*
303
   * Construct a SID for each RID in the list and then append it
304
   * to the info3.
305
   */
306
0
  for (i = 0; i < rg->groups.count; i++) {
307
0
    NTSTATUS status;
308
0
    struct dom_sid new_sid;
309
0
    uint32_t attributes = rg->groups.rids[i].attributes;
310
0
    struct dom_sid_buf buf;
311
312
0
    sid_compose(&new_sid,
313
0
          rg->domain_sid,
314
0
          rg->groups.rids[i].rid);
315
316
0
    DEBUG(10, ("Adding SID %s to extra SIDS\n",
317
0
         dom_sid_str_buf(&new_sid, &buf)));
318
319
0
    status = append_netr_SidAttr(info3, &info3->sids,
320
0
          &info3->sidcount,
321
0
          &new_sid,
322
0
          attributes);
323
0
    if (!NT_STATUS_IS_OK(status)) {
324
0
      DEBUG(1, ("failed to append SID %s to extra SIDS: %s\n",
325
0
        dom_sid_str_buf(&new_sid, &buf),
326
0
        nt_errstr(status)));
327
0
      return status;
328
0
    }
329
0
  }
330
331
0
  return NT_STATUS_OK;
332
0
}
333
334
/*
335
 * Create a copy of an info3 struct from the struct PAC_LOGON_INFO,
336
 * then merge resource SIDs, if any, into it. If successful return
337
 * the created info3 struct.
338
 */
339
340
NTSTATUS create_info3_from_pac_logon_info(TALLOC_CTX *mem_ctx,
341
          const struct PAC_LOGON_INFO *logon_info,
342
          struct netr_SamInfo3 **pp_info3)
343
0
{
344
0
  NTSTATUS status;
345
0
  struct netr_SamInfo3 *info3 = NULL;
346
347
0
  status = copy_netr_SamInfo3(mem_ctx,
348
0
            &logon_info->info3,
349
0
            &info3);
350
0
  if (!NT_STATUS_IS_OK(status)) {
351
0
    return status;
352
0
  }
353
354
0
  status = merge_resource_sids(logon_info, info3);
355
0
  if (!NT_STATUS_IS_OK(status)) {
356
0
    TALLOC_FREE(info3);
357
0
    return status;
358
0
  }
359
0
  *pp_info3 = info3;
360
0
  return NT_STATUS_OK;
361
0
}
362
363
/*
364
 * Create a copy of an info6 struct from the PAC_UPN_DNS_INFO and PAC_LOGON_INFO
365
 * then merge resource SIDs, if any, into it. If successful return the created
366
 * info6 struct.
367
 */
368
NTSTATUS create_info6_from_pac(TALLOC_CTX *mem_ctx,
369
             const struct PAC_LOGON_INFO *logon_info,
370
             const struct PAC_UPN_DNS_INFO *upn_dns_info,
371
             struct netr_SamInfo6 **pp_info6)
372
0
{
373
0
  NTSTATUS status;
374
0
  struct netr_SamInfo6 *info6 = NULL;
375
0
  struct netr_SamInfo3 *info3 = NULL;
376
377
0
  info6 = talloc_zero(mem_ctx, struct netr_SamInfo6);
378
0
  if (info6 == NULL) {
379
0
    return NT_STATUS_NO_MEMORY;
380
0
  }
381
382
0
  status = copy_netr_SamInfo3(info6,
383
0
            &logon_info->info3,
384
0
            &info3);
385
0
  if (!NT_STATUS_IS_OK(status)) {
386
0
    TALLOC_FREE(info6);
387
0
    return status;
388
0
  }
389
390
0
  status = merge_resource_sids(logon_info, info3);
391
0
  if (!NT_STATUS_IS_OK(status)) {
392
0
    TALLOC_FREE(info6);
393
0
    return status;
394
0
  }
395
396
0
  info6->base = info3->base;
397
0
  info6->sids = info3->sids;
398
0
  info6->sidcount = info3->sidcount;
399
400
0
  if (upn_dns_info != NULL) {
401
0
    info6->dns_domainname.string = talloc_strdup(info6,
402
0
        upn_dns_info->dns_domain_name);
403
0
    if (info6->dns_domainname.string == NULL) {
404
0
      TALLOC_FREE(info6);
405
0
      return NT_STATUS_NO_MEMORY;
406
0
    }
407
0
    info6->principal_name.string = talloc_strdup(info6,
408
0
        upn_dns_info->upn_name);
409
0
    if (info6->principal_name.string == NULL) {
410
0
      TALLOC_FREE(info6);
411
0
      return NT_STATUS_NO_MEMORY;
412
0
    }
413
0
  }
414
415
0
  *pp_info6 = info6;
416
0
  return NT_STATUS_OK;
417
0
}
418
419
/*
420
 * Check if this is a "Unix Users" domain user, or a
421
 * "Unix Groups" domain group, we need to handle it
422
 * in a special way if that's the case.
423
 */
424
425
static NTSTATUS SamInfo3_handle_sids(const char *username,
426
      const struct dom_sid *user_sid,
427
      const struct dom_sid *group_sid,
428
      struct netr_SamInfo3 *info3,
429
      struct dom_sid *domain_sid,
430
      struct extra_auth_info *extra)
431
0
{
432
0
  struct dom_sid_buf buf;
433
434
0
  if (sid_check_is_in_unix_users(user_sid)) {
435
    /* in info3 you can only set rids for the user and the
436
     * primary group, and the domain sid must be that of
437
     * the sam domain.
438
     *
439
     * Store a completely bogus value here.
440
     * The real SID is stored in the extra sids.
441
     * Other code will know to look there if (-1) is found
442
     */
443
0
    info3->base.rid = (uint32_t)(-1);
444
0
    sid_copy(&extra->user_sid, user_sid);
445
446
0
    DEBUG(10, ("Unix User found. Rid marked as "
447
0
      "special and sid (%s) saved as extra sid\n",
448
0
      dom_sid_str_buf(user_sid, &buf)));
449
0
  } else {
450
0
    sid_copy(domain_sid, user_sid);
451
0
    sid_split_rid(domain_sid, &info3->base.rid);
452
0
  }
453
454
0
  if (is_null_sid(domain_sid)) {
455
0
    sid_copy(domain_sid, get_global_sam_sid());
456
0
  }
457
458
  /* check if this is a "Unix Groups" domain group,
459
   * if so we need special handling */
460
0
  if (sid_check_is_in_unix_groups(group_sid)) {
461
    /* in info3 you can only set rids for the user and the
462
     * primary group, and the domain sid must be that of
463
     * the sam domain.
464
     *
465
     * Store a completely bogus value here.
466
     * The real SID is stored in the extra sids.
467
     * Other code will know to look there if (-1) is found
468
     */
469
0
    info3->base.primary_gid = (uint32_t)(-1);
470
0
    sid_copy(&extra->pgid_sid, group_sid);
471
472
0
    DEBUG(10, ("Unix Group found. Rid marked as "
473
0
      "special and sid (%s) saved as extra sid\n",
474
0
      dom_sid_str_buf(group_sid, &buf)));
475
0
  } else {
476
0
    bool ok = sid_peek_check_rid(domain_sid, group_sid,
477
0
          &info3->base.primary_gid);
478
0
    if (!ok) {
479
0
      struct dom_sid_buf buf2, buf3;
480
0
      DEBUG(1, ("The primary group domain sid(%s) does not "
481
0
        "match the domain sid(%s) for %s(%s)\n",
482
0
        dom_sid_str_buf(group_sid, &buf),
483
0
        dom_sid_str_buf(domain_sid, &buf2),
484
0
        username,
485
0
        dom_sid_str_buf(user_sid, &buf3)));
486
0
      return NT_STATUS_INVALID_SID;
487
0
    }
488
0
  }
489
0
  return NT_STATUS_OK;
490
0
}
491
492
0
#define RET_NOMEM(ptr) do { \
493
0
  if (!ptr) { \
494
0
    TALLOC_FREE(info3); \
495
0
    return NT_STATUS_NO_MEMORY; \
496
0
  } } while(0)
497
498
NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
499
        struct samu *samu,
500
        const char *login_server,
501
        struct netr_SamInfo3 **_info3,
502
        struct extra_auth_info *extra)
503
0
{
504
0
  struct netr_SamInfo3 *info3;
505
0
  const struct dom_sid *user_sid;
506
0
  const struct dom_sid *group_sid;
507
0
  struct dom_sid domain_sid = {0};
508
0
  struct dom_sid *group_sids;
509
0
  uint32_t num_group_sids = 0;
510
0
  const char *tmp;
511
0
  gid_t *gids;
512
0
  NTSTATUS status;
513
514
0
  user_sid = pdb_get_user_sid(samu);
515
0
  group_sid = pdb_get_group_sid(samu);
516
517
0
  if (!user_sid || !group_sid) {
518
0
    DEBUG(1, ("Sam account is missing sids!\n"));
519
0
    return NT_STATUS_UNSUCCESSFUL;
520
0
  }
521
522
0
  info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
523
0
  if (!info3) {
524
0
    return NT_STATUS_NO_MEMORY;
525
0
  }
526
527
0
  status = SamInfo3_handle_sids(pdb_get_username(samu),
528
0
        user_sid,
529
0
        group_sid,
530
0
        info3,
531
0
        &domain_sid,
532
0
        extra);
533
534
0
  if (!NT_STATUS_IS_OK(status)) {
535
0
    TALLOC_FREE(info3);
536
0
    return status;
537
0
  }
538
539
0
  unix_to_nt_time(&info3->base.logon_time, pdb_get_logon_time(samu));
540
0
  unix_to_nt_time(&info3->base.logoff_time, get_time_t_max());
541
0
  unix_to_nt_time(&info3->base.kickoff_time, get_time_t_max());
542
0
  unix_to_nt_time(&info3->base.last_password_change,
543
0
      pdb_get_pass_last_set_time(samu));
544
0
  unix_to_nt_time(&info3->base.allow_password_change,
545
0
      pdb_get_pass_can_change_time(samu));
546
0
  unix_to_nt_time(&info3->base.force_password_change,
547
0
      pdb_get_pass_must_change_time(samu));
548
549
0
  tmp = pdb_get_username(samu);
550
0
  if (tmp) {
551
0
    info3->base.account_name.string = talloc_strdup(info3, tmp);
552
0
    RET_NOMEM(info3->base.account_name.string);
553
0
  }
554
0
  tmp = pdb_get_fullname(samu);
555
0
  if (tmp) {
556
0
    info3->base.full_name.string = talloc_strdup(info3, tmp);
557
0
    RET_NOMEM(info3->base.full_name.string);
558
0
  }
559
0
  tmp = pdb_get_logon_script(samu);
560
0
  if (tmp) {
561
0
    info3->base.logon_script.string = talloc_strdup(info3, tmp);
562
0
    RET_NOMEM(info3->base.logon_script.string);
563
0
  }
564
0
  tmp = pdb_get_profile_path(samu);
565
0
  if (tmp) {
566
0
    info3->base.profile_path.string = talloc_strdup(info3, tmp);
567
0
    RET_NOMEM(info3->base.profile_path.string);
568
0
  }
569
0
  tmp = pdb_get_homedir(samu);
570
0
  if (tmp) {
571
0
    info3->base.home_directory.string = talloc_strdup(info3, tmp);
572
0
    RET_NOMEM(info3->base.home_directory.string);
573
0
  }
574
0
  tmp = pdb_get_dir_drive(samu);
575
0
  if (tmp) {
576
0
    info3->base.home_drive.string = talloc_strdup(info3, tmp);
577
0
    RET_NOMEM(info3->base.home_drive.string);
578
0
  }
579
580
0
  info3->base.logon_count = pdb_get_logon_count(samu);
581
0
  info3->base.bad_password_count = pdb_get_bad_password_count(samu);
582
583
0
  info3->base.logon_domain.string = talloc_strdup(info3,
584
0
              pdb_get_domain(samu));
585
0
  RET_NOMEM(info3->base.logon_domain.string);
586
587
0
  info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
588
0
  RET_NOMEM(info3->base.domain_sid);
589
590
0
  status = pdb_enum_group_memberships(mem_ctx, samu,
591
0
              &group_sids, &gids,
592
0
              &num_group_sids);
593
0
  if (!NT_STATUS_IS_OK(status)) {
594
0
    DEBUG(1, ("Failed to get groups from sam account.\n"));
595
0
    TALLOC_FREE(info3);
596
0
    return status;
597
0
  }
598
599
0
  if (num_group_sids) {
600
0
    status = group_sids_to_info3(info3, group_sids, num_group_sids);
601
0
    if (!NT_STATUS_IS_OK(status)) {
602
0
      TALLOC_FREE(info3);
603
0
      return status;
604
0
    }
605
0
  }
606
607
  /* We don't need sids and gids after the conversion */
608
0
  TALLOC_FREE(group_sids);
609
0
  TALLOC_FREE(gids);
610
0
  num_group_sids = 0;
611
612
  /* FIXME: should we add other flags ? */
613
0
  info3->base.user_flags = NETLOGON_EXTRA_SIDS;
614
615
0
  if (login_server) {
616
0
    info3->base.logon_server.string = talloc_strdup(info3, login_server);
617
0
    RET_NOMEM(info3->base.logon_server.string);
618
0
  }
619
620
0
  info3->base.acct_flags = pdb_get_acct_ctrl(samu);
621
622
0
  *_info3 = info3;
623
0
  return NT_STATUS_OK;
624
0
}
625
626
NTSTATUS passwd_to_SamInfo3(TALLOC_CTX *mem_ctx,
627
          const char *unix_username,
628
          const struct passwd *pwd,
629
          struct netr_SamInfo3 **pinfo3,
630
          struct extra_auth_info *extra)
631
0
{
632
0
  struct netr_SamInfo3 *info3;
633
0
  NTSTATUS status;
634
0
  TALLOC_CTX *tmp_ctx;
635
0
  const char *domain_name = NULL;
636
0
  const char *user_name = NULL;
637
0
  struct dom_sid domain_sid;
638
0
  struct dom_sid user_sid;
639
0
  struct dom_sid group_sid;
640
0
  enum lsa_SidType type;
641
0
  uint32_t num_sids = 0;
642
0
  struct dom_sid *user_sids = NULL;
643
0
  bool is_null;
644
0
  bool ok;
645
646
0
  tmp_ctx = talloc_stackframe();
647
648
0
  ok = lookup_name_smbconf(tmp_ctx,
649
0
         unix_username,
650
0
         LOOKUP_NAME_ALL,
651
0
         &domain_name,
652
0
         &user_name,
653
0
         &user_sid,
654
0
         &type);
655
0
  if (!ok) {
656
0
    status = NT_STATUS_NO_SUCH_USER;
657
0
    goto done;
658
0
  }
659
660
0
  if (type != SID_NAME_USER) {
661
0
    status = NT_STATUS_NO_SUCH_USER;
662
0
    goto done;
663
0
  }
664
665
0
  ok = winbind_lookup_usersids(tmp_ctx,
666
0
             &user_sid,
667
0
             &num_sids,
668
0
             &user_sids);
669
  /* Check if winbind is running */
670
0
  if (ok) {
671
    /*
672
     * Winbind is running and the first element of the user_sids
673
     * is the primary group.
674
     */
675
0
    if (num_sids == 0) {
676
0
      DBG_INFO("User %s has no groups\n", unix_username);
677
0
      return NT_STATUS_NO_SUCH_USER;
678
0
    }
679
0
    group_sid = user_sids[0];
680
0
  } else {
681
    /*
682
     * Winbind is not running, try to create the group_sid from the
683
     * passwd group id.
684
     */
685
686
    /*
687
     * This can lead to a primary group of S-1-22-2-XX which
688
     * will be rejected by other Samba code.
689
     */
690
0
    gid_to_sid(&group_sid, pwd->pw_gid);
691
0
  }
692
693
  /*
694
   * If we are a unix group, or a wellknown/builtin alias,
695
   * set the group_sid to the
696
   * 'Domain Users' RID of 513 which will always resolve to a
697
   * name.
698
   */
699
0
  if (sid_check_is_in_unix_groups(&group_sid) ||
700
0
      sid_check_is_in_builtin(&group_sid) ||
701
0
      sid_check_is_in_wellknown_domain(&group_sid)) {
702
0
    if (sid_check_is_in_unix_users(&user_sid)) {
703
0
      sid_compose(&group_sid,
704
0
            get_global_sam_sid(),
705
0
            DOMAIN_RID_USERS);
706
0
    } else {
707
0
      sid_copy(&domain_sid, &user_sid);
708
0
      sid_split_rid(&domain_sid, NULL);
709
0
      sid_compose(&group_sid,
710
0
            &domain_sid,
711
0
            DOMAIN_RID_USERS);
712
0
    }
713
0
  }
714
715
  /* Make sure we have a valid group sid */
716
0
  is_null = is_null_sid(&group_sid);
717
0
  if (is_null) {
718
0
    status = NT_STATUS_NO_SUCH_USER;
719
0
    goto done;
720
0
  }
721
722
  /* Construct a netr_SamInfo3 from the information we have */
723
0
  info3 = talloc_zero(tmp_ctx, struct netr_SamInfo3);
724
0
  if (!info3) {
725
0
    status = NT_STATUS_NO_MEMORY;
726
0
    goto done;
727
0
  }
728
729
0
  info3->base.account_name.string = talloc_strdup(info3, unix_username);
730
0
  if (info3->base.account_name.string == NULL) {
731
0
    status = NT_STATUS_NO_MEMORY;
732
0
    goto done;
733
0
  }
734
735
0
  info3->base.logon_domain.string = talloc_strdup(info3, domain_name);
736
0
  if (info3->base.logon_domain.string == NULL) {
737
0
    status = NT_STATUS_NO_MEMORY;
738
0
    goto done;
739
0
  }
740
741
0
  ZERO_STRUCT(domain_sid);
742
743
0
  status = SamInfo3_handle_sids(unix_username,
744
0
        &user_sid,
745
0
        &group_sid,
746
0
        info3,
747
0
        &domain_sid,
748
0
        extra);
749
750
0
  if (!NT_STATUS_IS_OK(status)) {
751
0
    goto done;
752
0
  }
753
754
0
  info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
755
0
  if (info3->base.domain_sid == NULL) {
756
0
    status = NT_STATUS_NO_MEMORY;
757
0
    goto done;
758
0
  }
759
760
0
  ok = sid_peek_check_rid(&domain_sid, &group_sid,
761
0
        &info3->base.primary_gid);
762
0
  if (!ok) {
763
0
    struct dom_sid_buf buf1, buf2, buf3;
764
765
0
    DEBUG(1, ("The primary group domain sid(%s) does not "
766
0
        "match the domain sid(%s) for %s(%s)\n",
767
0
        dom_sid_str_buf(&group_sid, &buf1),
768
0
        dom_sid_str_buf(&domain_sid, &buf2),
769
0
        unix_username,
770
0
        dom_sid_str_buf(&user_sid, &buf3)));
771
0
    status = NT_STATUS_INVALID_SID;
772
0
    goto done;
773
0
  }
774
775
0
  info3->base.acct_flags = ACB_NORMAL;
776
777
0
  if (num_sids) {
778
0
    status = group_sids_to_info3(info3, user_sids, num_sids);
779
0
    if (!NT_STATUS_IS_OK(status)) {
780
0
      goto done;
781
0
    }
782
0
  }
783
784
0
  *pinfo3 = talloc_move(mem_ctx, &info3);
785
786
0
  status = NT_STATUS_OK;
787
0
done:
788
0
  talloc_free(tmp_ctx);
789
790
0
  return status;
791
0
}