Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/winbind/idmap.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   Map SIDs to unixids and back
5
6
   Copyright (C) Kai Blin 2008
7
   Copyright (C) Andrew Bartlett 2012
8
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
#include "includes.h"
24
#include "auth/auth.h"
25
#include "librpc/gen_ndr/ndr_security.h"
26
#include "lib/util_unixsids.h"
27
#include <ldb.h>
28
#include "ldb_wrap.h"
29
#include "param/param.h"
30
#include "winbind/idmap.h"
31
#include "libcli/security/security.h"
32
#include "libcli/ldap/ldap_ndr.h"
33
#include "dsdb/samdb/samdb.h"
34
#include "../libds/common/flags.h"
35
36
/**
37
 * Get uid/gid bounds from idmap database
38
 *
39
 * \param idmap_ctx idmap context to use
40
 * \param low lower uid/gid bound is stored here
41
 * \param high upper uid/gid bound is stored here
42
 * \return 0 on success, nonzero on failure
43
 */
44
static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low,
45
    uint32_t *high)
46
0
{
47
0
  int ret = -1;
48
0
  struct ldb_context *ldb = idmap_ctx->ldb_ctx;
49
0
  struct ldb_dn *dn;
50
0
  struct ldb_result *res = NULL;
51
0
  TALLOC_CTX *tmp_ctx = talloc_new(idmap_ctx);
52
0
  uint32_t lower_bound = (uint32_t) -1;
53
0
  uint32_t upper_bound = (uint32_t) -1;
54
55
0
  dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
56
0
  if (dn == NULL) goto failed;
57
58
0
  ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
59
0
  if (ret != LDB_SUCCESS) goto failed;
60
61
0
  if (res->count != 1) {
62
0
    ret = -1;
63
0
    goto failed;
64
0
  }
65
66
0
  lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1);
67
0
  if (lower_bound != (uint32_t) -1) {
68
0
    ret = LDB_SUCCESS;
69
0
  } else {
70
0
    ret = -1;
71
0
    goto failed;
72
0
  }
73
74
0
  upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1);
75
0
  if (upper_bound != (uint32_t) -1) {
76
0
    ret = LDB_SUCCESS;
77
0
  } else {
78
0
    ret = -1;
79
0
  }
80
81
0
failed:
82
0
  talloc_free(tmp_ctx);
83
0
  *low  = lower_bound;
84
0
  *high = upper_bound;
85
0
  return ret;
86
0
}
87
88
/**
89
 * Add a dom_sid structure to a ldb_message
90
 * \param idmap_ctx idmap context to use
91
 * \param mem_ctx talloc context to use
92
 * \param ldb_message ldb message to add dom_sid to
93
 * \param attr_name name of the attribute to store the dom_sid in
94
 * \param sid dom_sid to store
95
 * \return 0 on success, an ldb error code on failure.
96
 */
97
static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx,
98
    TALLOC_CTX *mem_ctx, struct ldb_message *msg,
99
    const char *attr_name, const struct dom_sid *sid)
100
0
{
101
0
  struct ldb_val val;
102
0
  enum ndr_err_code ndr_err;
103
104
0
  ndr_err = ndr_push_struct_blob(&val, mem_ctx, sid,
105
0
               (ndr_push_flags_fn_t)ndr_push_dom_sid);
106
107
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
108
0
    return -1;
109
0
  }
110
111
0
  return ldb_msg_add_value(msg, attr_name, &val, NULL);
112
0
}
113
114
/**
115
 * Get a dom_sid structure from a ldb message.
116
 *
117
 * \param mem_ctx talloc context to allocate dom_sid memory in
118
 * \param msg ldb_message to get dom_sid from
119
 * \param attr_name key that has the dom_sid as data
120
 * \return dom_sid structure on success, NULL on failure
121
 */
122
static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx,
123
    struct ldb_message *msg, const char *attr_name)
124
0
{
125
0
  struct dom_sid *sid;
126
0
  const struct ldb_val *val;
127
0
  enum ndr_err_code ndr_err;
128
129
0
  val = ldb_msg_find_ldb_val(msg, attr_name);
130
0
  if (val == NULL) {
131
0
    return NULL;
132
0
  }
133
134
0
  sid = talloc(mem_ctx, struct dom_sid);
135
0
  if (sid == NULL) {
136
0
    return NULL;
137
0
  }
138
139
0
  ndr_err = ndr_pull_struct_blob(val, sid, sid,
140
0
               (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
141
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
142
0
    talloc_free(sid);
143
0
    return NULL;
144
0
  }
145
146
0
  return sid;
147
0
}
148
149
/**
150
 * Initialize idmap context
151
 *
152
 * talloc_free to close.
153
 *
154
 * \param mem_ctx talloc context to use.
155
 * \return allocated idmap_context on success, NULL on error
156
 */
157
struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
158
         struct tevent_context *ev_ctx,
159
         struct loadparm_context *lp_ctx)
160
0
{
161
0
  struct idmap_context *idmap_ctx;
162
163
0
  idmap_ctx = talloc(mem_ctx, struct idmap_context);
164
0
  if (idmap_ctx == NULL) {
165
0
    return NULL;
166
0
  }
167
168
0
  idmap_ctx->lp_ctx = lp_ctx;
169
170
0
  idmap_ctx->ldb_ctx = ldb_wrap_connect(idmap_ctx, ev_ctx, lp_ctx,
171
0
                "idmap.ldb",
172
0
                system_session(lp_ctx),
173
0
                NULL, 0);
174
0
  if (idmap_ctx->ldb_ctx == NULL) {
175
0
    goto fail;
176
0
  }
177
178
0
  idmap_ctx->samdb = samdb_connect(idmap_ctx,
179
0
           ev_ctx,
180
0
           lp_ctx,
181
0
           system_session(lp_ctx),
182
0
           NULL,
183
0
           0);
184
0
  if (idmap_ctx->samdb == NULL) {
185
0
    DEBUG(0, ("Failed to load sam.ldb in idmap_init\n"));
186
0
    goto fail;
187
0
  }
188
189
0
  return idmap_ctx;
190
0
fail:
191
0
  TALLOC_FREE(idmap_ctx);
192
0
  return NULL;
193
0
}
194
195
/**
196
 * Convert an unixid to the corresponding SID
197
 *
198
 * \param idmap_ctx idmap context to use
199
 * \param mem_ctx talloc context the memory for the struct dom_sid is allocated
200
 * from.
201
 * \param unixid pointer to a unixid struct to convert
202
 * \param sid pointer that will take the struct dom_sid pointer if the mapping
203
 * succeeds.
204
 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not
205
 * possible or some other NTSTATUS that is more descriptive on failure.
206
 */
207
208
static NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx,
209
         TALLOC_CTX *mem_ctx,
210
         struct unixid *unixid,
211
         struct dom_sid **sid)
212
0
{
213
0
  int ret;
214
0
  NTSTATUS status;
215
0
  struct ldb_context *ldb = idmap_ctx->ldb_ctx;
216
0
  struct ldb_result *res = NULL;
217
0
  struct ldb_message *msg;
218
0
  const struct dom_sid *unix_sid;
219
0
  struct dom_sid *new_sid;
220
0
  TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
221
0
  const char *id_type;
222
223
0
  const char *sam_attrs[] = {"objectSid", NULL};
224
  
225
  /* 
226
   * First check against our local DB, to see if this user has a
227
   * mapping there.  This means that the Samba4 AD DC behaves
228
   * much like a winbindd member server running idmap_ad
229
   */
230
  
231
0
  switch (unixid->type) {
232
0
    case ID_TYPE_UID:
233
0
      if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
234
0
        ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &msg,
235
0
                  ldb_get_default_basedn(idmap_ctx->samdb),
236
0
                  LDB_SCOPE_SUBTREE,
237
0
                  sam_attrs, 0,
238
0
                  "(&(|(sAMaccountType=%u)(sAMaccountType=%u)(sAMaccountType=%u))"
239
0
                  "(uidNumber=%u)(objectSid=*))",
240
0
                  ATYPE_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST, unixid->id);
241
0
      } else {
242
        /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
243
0
        ret = LDB_ERR_NO_SUCH_OBJECT;
244
0
      }
245
246
0
      if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
247
0
        DEBUG(1, ("Search for uidNumber=%lu gave duplicate results, failing to map to a SID!\n",
248
0
            (unsigned long)unixid->id));
249
0
        status = NT_STATUS_NONE_MAPPED;
250
0
        goto failed;
251
0
      } else if (ret == LDB_SUCCESS) {
252
0
        *sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
253
0
        if (*sid == NULL) {
254
0
          DEBUG(1, ("Search for uidNumber=%lu did not return an objectSid!\n",
255
0
              (unsigned long)unixid->id));
256
0
          status = NT_STATUS_NONE_MAPPED;
257
0
          goto failed;
258
0
        }
259
0
        talloc_free(tmp_ctx);
260
0
        return NT_STATUS_OK;
261
0
      } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
262
0
        DEBUG(1, ("Search for uidNumber=%lu gave '%s', failing to map to a SID!\n",
263
0
            (unsigned long)unixid->id, ldb_errstring(idmap_ctx->samdb)));
264
0
        status = NT_STATUS_NONE_MAPPED;
265
0
        goto failed;
266
0
      }
267
268
0
      id_type = "ID_TYPE_UID";
269
0
      break;
270
0
    case ID_TYPE_GID:
271
0
      if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
272
0
        ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &msg,
273
0
                  ldb_get_default_basedn(idmap_ctx->samdb),
274
0
                  LDB_SCOPE_SUBTREE,
275
0
                  sam_attrs, 0,
276
0
                  "(&(|(sAMaccountType=%u)(sAMaccountType=%u))(gidNumber=%u))",
277
0
                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
278
0
                  unixid->id);
279
0
      } else {
280
        /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
281
0
        ret = LDB_ERR_NO_SUCH_OBJECT;
282
0
      }
283
0
      if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
284
0
        DEBUG(1, ("Search for gidNumber=%lu gave duplicate results, failing to map to a SID!\n",
285
0
            (unsigned long)unixid->id));
286
0
        status = NT_STATUS_NONE_MAPPED;
287
0
        goto failed;
288
0
      } else if (ret == LDB_SUCCESS) {
289
0
        *sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
290
0
        if (*sid == NULL) {
291
0
          DEBUG(1, ("Search for gidNumber=%lu did not return an objectSid!\n",
292
0
              (unsigned long)unixid->id));
293
0
          status = NT_STATUS_NONE_MAPPED;
294
0
          goto failed;
295
0
        }
296
0
        talloc_free(tmp_ctx);
297
0
        return NT_STATUS_OK;
298
0
      } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
299
0
        DEBUG(1, ("Search for gidNumber=%lu gave '%s', failing to map to a SID!\n",
300
0
            (unsigned long)unixid->id, ldb_errstring(idmap_ctx->samdb)));
301
0
        status = NT_STATUS_NONE_MAPPED;
302
0
        goto failed;
303
0
      }
304
305
0
      id_type = "ID_TYPE_GID";
306
0
      break;
307
0
    default:
308
0
      DEBUG(1, ("unixid->type must be type gid or uid (got %u) for lookup with id %lu\n",
309
0
          (unsigned)unixid->type, (unsigned long)unixid->id));
310
0
      status = NT_STATUS_NONE_MAPPED;
311
0
      goto failed;
312
0
  }
313
314
0
  ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
315
0
         NULL, "(&(|(type=ID_TYPE_BOTH)(type=%s))"
316
0
         "(xidNumber=%u))", id_type, unixid->id);
317
0
  if (ret != LDB_SUCCESS) {
318
0
    DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
319
0
    status = NT_STATUS_NONE_MAPPED;
320
0
    goto failed;
321
0
  }
322
323
0
  if (res->count == 1) {
324
0
    const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
325
0
                     "type", NULL);
326
327
0
    *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0],
328
0
               "objectSid");
329
0
    if (*sid == NULL) {
330
0
      DEBUG(1, ("Failed to get sid from db: %u\n", ret));
331
0
      status = NT_STATUS_NONE_MAPPED;
332
0
      goto failed;
333
0
    }
334
335
0
    if (type == NULL) {
336
0
      DEBUG(1, ("Invalid type for mapping entry.\n"));
337
0
      talloc_free(tmp_ctx);
338
0
      return NT_STATUS_NONE_MAPPED;
339
0
    }
340
341
0
    if (strcmp(type, "ID_TYPE_BOTH") == 0) {
342
0
      unixid->type = ID_TYPE_BOTH;
343
0
    } else if (strcmp(type, "ID_TYPE_UID") == 0) {
344
0
      unixid->type = ID_TYPE_UID;
345
0
    } else {
346
0
      unixid->type = ID_TYPE_GID;
347
0
    }
348
349
0
    talloc_free(tmp_ctx);
350
0
    return NT_STATUS_OK;
351
0
  }
352
353
0
  DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n"));
354
355
  /* For local users/groups , we just create a rid = uid/gid */
356
0
  if (unixid->type == ID_TYPE_UID) {
357
0
    unix_sid = &global_sid_Unix_Users;
358
0
  } else {
359
0
    unix_sid = &global_sid_Unix_Groups;
360
0
  }
361
362
0
  new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id);
363
0
  if (new_sid == NULL) {
364
0
    status = NT_STATUS_NO_MEMORY;
365
0
    goto failed;
366
0
  }
367
368
0
  *sid = new_sid;
369
0
  talloc_free(tmp_ctx);
370
0
  return NT_STATUS_OK;
371
372
0
failed:
373
0
  talloc_free(tmp_ctx);
374
0
  return status;
375
0
}
376
377
378
/**
379
 * Map a SID to an unixid struct.
380
 *
381
 * If no mapping exists, a new mapping will be created.
382
 *
383
 * \param idmap_ctx idmap context to use
384
 * \param mem_ctx talloc context to use
385
 * \param sid SID to map to an unixid struct
386
 * \param unixid pointer to a unixid struct
387
 * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from
388
 * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the
389
 * mapping failed.
390
 */
391
static NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx,
392
         TALLOC_CTX *mem_ctx,
393
         const struct dom_sid *sid,
394
         struct unixid *unixid)
395
0
{
396
0
  int ret;
397
0
  NTSTATUS status;
398
0
  struct ldb_context *ldb = idmap_ctx->ldb_ctx;
399
0
  struct ldb_dn *dn;
400
0
  struct ldb_message *hwm_msg, *map_msg, *sam_msg;
401
0
  struct ldb_result *res = NULL;
402
0
  int trans = -1;
403
0
  uint32_t low, high, hwm, new_xid;
404
0
  struct dom_sid_buf sid_string;
405
0
  char *unixid_string, *hwm_string;
406
0
  bool hwm_entry_exists;
407
0
  TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
408
0
  const char *sam_attrs[] = {"uidNumber", "gidNumber", "samAccountType", NULL};
409
410
0
  if (sid_check_is_in_unix_users(sid)) {
411
0
    uint32_t rid;
412
0
    DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
413
0
    status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
414
0
    if (!NT_STATUS_IS_OK(status)) {
415
0
      talloc_free(tmp_ctx);
416
0
      return status;
417
0
    }
418
419
0
    unixid->id = rid;
420
0
    unixid->type = ID_TYPE_UID;
421
422
0
    talloc_free(tmp_ctx);
423
0
    return NT_STATUS_OK;
424
0
  }
425
426
0
  if (sid_check_is_in_unix_groups(sid)) {
427
0
    uint32_t rid;
428
0
    DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
429
0
    status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
430
0
    if (!NT_STATUS_IS_OK(status)) {
431
0
      talloc_free(tmp_ctx);
432
0
      return status;
433
0
    }
434
435
0
    unixid->id = rid;
436
0
    unixid->type = ID_TYPE_GID;
437
438
0
    talloc_free(tmp_ctx);
439
0
    return NT_STATUS_OK;
440
0
  }
441
442
  /* 
443
   * First check against our local DB, to see if this user has a
444
   * mapping there.  This means that the Samba4 AD DC behaves
445
   * much like a winbindd member server running idmap_ad
446
   */
447
  
448
0
  if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
449
0
    struct dom_sid_buf buf;
450
0
    ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &sam_msg,
451
0
              ldb_get_default_basedn(idmap_ctx->samdb),
452
0
              LDB_SCOPE_SUBTREE, sam_attrs, 0,
453
0
              "(&(objectSid=%s)"
454
0
              "(|(sAMaccountType=%u)(sAMaccountType=%u)(sAMaccountType=%u)"
455
0
              "(sAMaccountType=%u)(sAMaccountType=%u))"
456
0
              "(|(uidNumber=*)(gidNumber=*)))",
457
0
              dom_sid_str_buf(sid, &buf),
458
0
              ATYPE_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
459
0
              ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
460
0
  } else {
461
    /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
462
0
    ret = LDB_ERR_NO_SUCH_OBJECT;
463
0
  }
464
465
0
  if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
466
0
    struct dom_sid_buf buf;
467
0
    DEBUG(1, ("Search for objectSid=%s gave duplicate results, failing to map to a unix ID!\n",
468
0
        dom_sid_str_buf(sid, &buf)));
469
0
    status = NT_STATUS_NONE_MAPPED;
470
0
    goto failed;
471
0
  } else if (ret == LDB_SUCCESS) {
472
0
    uint32_t account_type = ldb_msg_find_attr_as_uint(sam_msg, "sAMaccountType", 0);
473
0
    if ((account_type == ATYPE_ACCOUNT) ||
474
0
        (account_type == ATYPE_WORKSTATION_TRUST ) ||
475
0
        (account_type == ATYPE_INTERDOMAIN_TRUST ))
476
0
    {
477
0
      const struct ldb_val *v = ldb_msg_find_ldb_val(sam_msg, "uidNumber");
478
0
      if (v) {
479
0
        unixid->type = ID_TYPE_UID;
480
0
        unixid->id = ldb_msg_find_attr_as_uint(sam_msg, "uidNumber", -1);
481
0
        talloc_free(tmp_ctx);
482
0
        return NT_STATUS_OK;
483
0
      }
484
485
0
    } else if ((account_type == ATYPE_SECURITY_GLOBAL_GROUP) ||
486
0
         (account_type == ATYPE_SECURITY_LOCAL_GROUP))
487
0
    {
488
0
      const struct ldb_val *v = ldb_msg_find_ldb_val(sam_msg, "gidNumber");
489
0
      if (v) {
490
0
        unixid->type = ID_TYPE_GID;
491
0
        unixid->id = ldb_msg_find_attr_as_uint(sam_msg, "gidNumber", -1);
492
0
        talloc_free(tmp_ctx);
493
0
        return NT_STATUS_OK;
494
0
      }
495
0
    }
496
0
  } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
497
0
    struct dom_sid_buf buf;
498
0
    DEBUG(1, ("Search for objectSid=%s gave '%s', failing to map to a SID!\n",
499
0
        dom_sid_str_buf(sid, &buf),
500
0
        ldb_errstring(idmap_ctx->samdb)));
501
502
0
    status = NT_STATUS_NONE_MAPPED;
503
0
    goto failed;
504
0
  }
505
506
0
  ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
507
0
         NULL, "(&(objectClass=sidMap)(objectSid=%s))",
508
0
         ldap_encode_ndr_dom_sid(tmp_ctx, sid));
509
0
  if (ret != LDB_SUCCESS) {
510
0
    DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
511
0
    talloc_free(tmp_ctx);
512
0
    return NT_STATUS_NONE_MAPPED;
513
0
  }
514
515
0
  if (res->count == 1) {
516
0
    const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
517
0
                     "type", NULL);
518
0
    new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber",
519
0
                -1);
520
0
    if (new_xid == (uint32_t) -1) {
521
0
      DEBUG(1, ("Invalid xid mapping.\n"));
522
0
      talloc_free(tmp_ctx);
523
0
      return NT_STATUS_NONE_MAPPED;
524
0
    }
525
526
0
    if (type == NULL) {
527
0
      DEBUG(1, ("Invalid type for mapping entry.\n"));
528
0
      talloc_free(tmp_ctx);
529
0
      return NT_STATUS_NONE_MAPPED;
530
0
    }
531
532
0
    unixid->id = new_xid;
533
534
0
    if (strcmp(type, "ID_TYPE_BOTH") == 0) {
535
0
      unixid->type = ID_TYPE_BOTH;
536
0
    } else if (strcmp(type, "ID_TYPE_UID") == 0) {
537
0
      unixid->type = ID_TYPE_UID;
538
0
    } else {
539
0
      unixid->type = ID_TYPE_GID;
540
0
    }
541
542
0
    talloc_free(tmp_ctx);
543
0
    return NT_STATUS_OK;
544
0
  }
545
546
0
  DEBUG(6, ("No existing mapping found, attempting to create one.\n"));
547
548
0
  trans = ldb_transaction_start(ldb);
549
0
  if (trans != LDB_SUCCESS) {
550
0
    status = NT_STATUS_NONE_MAPPED;
551
0
    goto failed;
552
0
  }
553
554
  /* Redo the search to make sure no one changed the mapping while we
555
   * weren't looking */
556
0
  ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
557
0
         NULL, "(&(objectClass=sidMap)(objectSid=%s))",
558
0
         ldap_encode_ndr_dom_sid(tmp_ctx, sid));
559
0
  if (ret != LDB_SUCCESS) {
560
0
    DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
561
0
    status = NT_STATUS_NONE_MAPPED;
562
0
    goto failed;
563
0
  }
564
565
0
  if (res->count > 0) {
566
0
    DEBUG(1, ("Database changed while trying to add a sidmap.\n"));
567
0
    status = NT_STATUS_RETRY;
568
0
    goto failed;
569
0
  }
570
571
0
  ret = idmap_get_bounds(idmap_ctx, &low, &high);
572
0
  if (ret != LDB_SUCCESS) {
573
0
    status = NT_STATUS_NONE_MAPPED;
574
0
    goto failed;
575
0
  }
576
577
0
  dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
578
0
  if (dn == NULL) {
579
0
    status = NT_STATUS_NO_MEMORY;
580
0
    goto failed;
581
0
  }
582
583
0
  ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
584
0
  if (ret != LDB_SUCCESS) {
585
0
    DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
586
0
    status = NT_STATUS_NONE_MAPPED;
587
0
    goto failed;
588
0
  }
589
590
0
  if (res->count != 1) {
591
0
    DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n"));
592
0
    status = NT_STATUS_NONE_MAPPED;
593
0
    goto failed;
594
0
  }
595
596
0
  hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1);
597
0
  if (hwm == (uint32_t)-1) {
598
0
    hwm = low;
599
0
    hwm_entry_exists = false;
600
0
  } else {
601
0
    hwm_entry_exists = true;
602
0
  }
603
604
0
  if (hwm > high) {
605
0
    DEBUG(1, ("Out of xids to allocate.\n"));
606
0
    status = NT_STATUS_NONE_MAPPED;
607
0
    goto failed;
608
0
  }
609
610
0
  hwm_msg = ldb_msg_new(tmp_ctx);
611
0
  if (hwm_msg == NULL) {
612
0
    DEBUG(1, ("Out of memory when creating ldb_message\n"));
613
0
    status = NT_STATUS_NO_MEMORY;
614
0
    goto failed;
615
0
  }
616
617
0
  hwm_msg->dn = dn;
618
619
0
  new_xid = hwm;
620
0
  hwm++;
621
622
0
  hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm);
623
0
  if (hwm_string == NULL) {
624
0
    status = NT_STATUS_NO_MEMORY;
625
0
    goto failed;
626
0
  }
627
628
0
  dom_sid_str_buf(sid, &sid_string);
629
630
0
  unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid);
631
0
  if (unixid_string == NULL) {
632
0
    status = NT_STATUS_NO_MEMORY;
633
0
    goto failed;
634
0
  }
635
636
0
  if (hwm_entry_exists) {
637
0
    struct ldb_message_element *els;
638
0
    struct ldb_val *vals;
639
640
    /* We're modifying the entry, not just adding a new one. */
641
0
    els = talloc_array(tmp_ctx, struct ldb_message_element, 2);
642
0
    if (els == NULL) {
643
0
      status = NT_STATUS_NO_MEMORY;
644
0
      goto failed;
645
0
    }
646
647
0
    vals = talloc_array(tmp_ctx, struct ldb_val, 2);
648
0
    if (vals == NULL) {
649
0
      status = NT_STATUS_NO_MEMORY;
650
0
      goto failed;
651
0
    }
652
653
0
    hwm_msg->num_elements = 2;
654
0
    hwm_msg->elements = els;
655
656
0
    els[0].num_values = 1;
657
0
    els[0].values = &vals[0];
658
0
    els[0].flags = LDB_FLAG_MOD_DELETE;
659
0
    els[0].name = talloc_strdup(tmp_ctx, "xidNumber");
660
0
    if (els[0].name == NULL) {
661
0
      status = NT_STATUS_NO_MEMORY;
662
0
      goto failed;
663
0
    }
664
665
0
    els[1].num_values = 1;
666
0
    els[1].values = &vals[1];
667
0
    els[1].flags = LDB_FLAG_MOD_ADD;
668
0
    els[1].name = els[0].name;
669
670
0
    vals[0].data = (uint8_t *)unixid_string;
671
0
    vals[0].length = strlen(unixid_string);
672
0
    vals[1].data = (uint8_t *)hwm_string;
673
0
    vals[1].length = strlen(hwm_string);
674
0
  } else {
675
0
    ret = ldb_msg_append_string(hwm_msg, "xidNumber", hwm_string,
676
0
              LDB_FLAG_MOD_ADD);
677
0
    if (ret != LDB_SUCCESS)
678
0
    {
679
0
      status = NT_STATUS_NONE_MAPPED;
680
0
      goto failed;
681
0
    }
682
0
  }
683
684
0
  ret = ldb_modify(ldb, hwm_msg);
685
0
  if (ret != LDB_SUCCESS) {
686
0
    DEBUG(1, ("Updating the xid high water mark failed: %s\n",
687
0
        ldb_errstring(ldb)));
688
0
    status = NT_STATUS_NONE_MAPPED;
689
0
    goto failed;
690
0
  }
691
692
0
  map_msg = ldb_msg_new(tmp_ctx);
693
0
  if (map_msg == NULL) {
694
0
    status = NT_STATUS_NO_MEMORY;
695
0
    goto failed;
696
0
  }
697
698
0
  map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string.buf);
699
0
  if (map_msg->dn == NULL) {
700
0
    status = NT_STATUS_NO_MEMORY;
701
0
    goto failed;
702
0
  }
703
704
0
  ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string);
705
0
  if (ret != LDB_SUCCESS) {
706
0
    status = NT_STATUS_NONE_MAPPED;
707
0
    goto failed;
708
0
  }
709
710
0
  ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid",
711
0
      sid);
712
0
  if (ret != LDB_SUCCESS) {
713
0
    status = NT_STATUS_NONE_MAPPED;
714
0
    goto failed;
715
0
  }
716
717
0
  ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap");
718
0
  if (ret != LDB_SUCCESS) {
719
0
    status = NT_STATUS_NONE_MAPPED;
720
0
    goto failed;
721
0
  }
722
723
0
  ret = ldb_msg_add_string(map_msg, "type", "ID_TYPE_BOTH");
724
0
  if (ret != LDB_SUCCESS) {
725
0
    status = NT_STATUS_NONE_MAPPED;
726
0
    goto failed;
727
0
  }
728
729
0
  ret = ldb_msg_add_string(map_msg, "cn", sid_string.buf);
730
0
  if (ret != LDB_SUCCESS) {
731
0
    status = NT_STATUS_NONE_MAPPED;
732
0
    goto failed;
733
0
  }
734
735
0
  ret = ldb_add(ldb, map_msg);
736
0
  if (ret != LDB_SUCCESS) {
737
0
    DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb)));
738
0
    status = NT_STATUS_NONE_MAPPED;
739
0
    goto failed;
740
0
  }
741
742
0
  trans = ldb_transaction_commit(ldb);
743
0
  if (trans != LDB_SUCCESS) {
744
0
    DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb)));
745
0
    status = NT_STATUS_NONE_MAPPED;
746
0
    goto failed;
747
0
  }
748
749
0
  unixid->id = new_xid;
750
0
  unixid->type = ID_TYPE_BOTH;
751
0
  talloc_free(tmp_ctx);
752
0
  return NT_STATUS_OK;
753
754
0
failed:
755
0
  if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
756
0
  talloc_free(tmp_ctx);
757
0
  return status;
758
0
}
759
760
/**
761
 * Convert an array of unixids to the corresponding array of SIDs
762
 *
763
 * \param idmap_ctx idmap context to use
764
 * \param mem_ctx talloc context the memory for the dom_sids is allocated
765
 * from.
766
 * \param count length of id_mapping array.
767
 * \param id array of id_mappings.
768
 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
769
 * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
770
 * did not.
771
 */
772
773
NTSTATUS idmap_xids_to_sids(struct idmap_context *idmap_ctx,
774
          TALLOC_CTX *mem_ctx,
775
          struct id_map **id)
776
0
{
777
0
  unsigned int i, error_count = 0;
778
0
  NTSTATUS status;
779
780
0
  for (i = 0; id && id[i]; i++) {
781
0
    status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
782
0
            &id[i]->xid, &id[i]->sid);
783
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
784
0
      status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
785
0
              &id[i]->xid,
786
0
              &id[i]->sid);
787
0
    }
788
0
    if (!NT_STATUS_IS_OK(status)) {
789
0
      DEBUG(1, ("idmapping xid_to_sid failed for id[%d]=%lu: %s\n",
790
0
          i, (unsigned long)id[i]->xid.id, nt_errstr(status)));
791
0
      error_count++;
792
0
      id[i]->status = ID_UNMAPPED;
793
0
    } else {
794
0
      id[i]->status = ID_MAPPED;
795
0
    }
796
0
  }
797
798
0
  if (error_count == i) {
799
    /* Mapping did not work at all. */
800
0
    return NT_STATUS_NONE_MAPPED;
801
0
  } else if (error_count > 0) {
802
    /* Some mappings worked, some did not. */
803
0
    return STATUS_SOME_UNMAPPED;
804
0
  } else {
805
0
    return NT_STATUS_OK;
806
0
  }
807
0
}
808
809
/**
810
 * Convert an array of SIDs to the corresponding array of unixids
811
 *
812
 * \param idmap_ctx idmap context to use
813
 * \param mem_ctx talloc context the memory for the unixids is allocated
814
 * from.
815
 * \param count length of id_mapping array.
816
 * \param id array of id_mappings.
817
 * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
818
 * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
819
 * did not.
820
 */
821
822
NTSTATUS idmap_sids_to_xids(struct idmap_context *idmap_ctx,
823
          TALLOC_CTX *mem_ctx,
824
          struct id_map **id)
825
0
{
826
0
  unsigned int i, error_count = 0;
827
0
  NTSTATUS status;
828
829
0
  for (i = 0; id && id[i]; i++) {
830
0
    status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
831
0
            id[i]->sid, &id[i]->xid);
832
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
833
0
      status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
834
0
              id[i]->sid,
835
0
              &id[i]->xid);
836
0
    }
837
0
    if (!NT_STATUS_IS_OK(status)) {
838
0
      struct dom_sid_buf buf;
839
0
      DEBUG(1, ("idmapping sid_to_xid failed for id[%d]=%s: %s\n",
840
0
          i,
841
0
          dom_sid_str_buf(id[i]->sid, &buf),
842
0
          nt_errstr(status)));
843
0
      error_count++;
844
0
      id[i]->status = ID_UNMAPPED;
845
0
    } else {
846
0
      id[i]->status = ID_MAPPED;
847
0
    }
848
0
  }
849
850
0
  if (error_count == i) {
851
    /* Mapping did not work at all. */
852
0
    return NT_STATUS_NONE_MAPPED;
853
0
  } else if (error_count > 0) {
854
    /* Some mappings worked, some did not. */
855
0
    return STATUS_SOME_UNMAPPED;
856
0
  } else {
857
0
    return NT_STATUS_OK;
858
0
  }
859
0
}
860