Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/dsdb/samdb/ldb_modules/ridalloc.c
Line
Count
Source
1
/*
2
   RID allocation helper functions
3
4
   Copyright (C) Andrew Bartlett 2010
5
   Copyright (C) Andrew Tridgell 2010
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
21
/*
22
 *  Name: ldb
23
 *
24
 *  Component: RID allocation logic
25
 *
26
 *  Description: manage RID Set and RID Manager objects
27
 *
28
 */
29
30
#include "includes.h"
31
#include "ldb_module.h"
32
#include "lib/util/server_id.h"
33
#include "dsdb/samdb/samdb.h"
34
#include "dsdb/samdb/ldb_modules/util.h"
35
#include "lib/messaging/irpc.h"
36
#include "param/param.h"
37
#include "librpc/gen_ndr/ndr_misc.h"
38
#include "dsdb/samdb/ldb_modules/ridalloc.h"
39
40
/*
41
  Note: the RID allocation attributes in AD are very badly named. Here
42
  is what we think they really do:
43
44
  in RID Set object:
45
    - rIDPreviousAllocationPool: the pool which a DC is currently
46
      pulling RIDs from. Managed by client DC
47
48
    - rIDAllocationPool: the pool that the DC will switch to next,
49
      when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
50
51
    - rIDNextRID: the last RID allocated by this DC. Managed by client DC
52
53
  in RID Manager object:
54
    - rIDAvailablePool: the pool where the RID Manager gets new rID
55
      pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
56
      locally when the DC is the RID Manager)
57
 */
58
59
60
/*
61
  make a IRPC call to the drepl task to ask it to get the RID
62
  Manager to give us another RID pool.
63
64
  This function just sends the message to the drepl task then
65
  returns immediately. It should be called well before we
66
  completely run out of RIDs
67
 */
68
static int ridalloc_poke_rid_manager(struct ldb_module *module)
69
0
{
70
0
  struct imessaging_context *msg;
71
0
  unsigned num_servers;
72
0
  struct server_id *servers;
73
0
  struct ldb_context *ldb = ldb_module_get_ctx(module);
74
0
  struct loadparm_context *lp_ctx =
75
0
    (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
76
0
  TALLOC_CTX *tmp_ctx = talloc_new(module);
77
0
  NTSTATUS status;
78
79
0
  msg = imessaging_client_init(tmp_ctx, lp_ctx,
80
0
            ldb_get_event_context(ldb));
81
0
  if (!msg) {
82
0
    ldb_asprintf_errstring(ldb_module_get_ctx(module),
83
0
        "Failed to send MSG_DREPL_ALLOCATE_RID, "
84
0
        "unable init client messaging context");
85
0
    DEBUG(3,(__location__ ": Failed to create messaging context\n"));
86
0
    talloc_free(tmp_ctx);
87
0
    return LDB_ERR_UNWILLING_TO_PERFORM;
88
0
  }
89
90
0
  status = irpc_servers_byname(msg, msg, "dreplsrv",
91
0
             &num_servers, &servers);
92
0
  if (!NT_STATUS_IS_OK(status)) {
93
0
    ldb_asprintf_errstring(ldb_module_get_ctx(module),
94
0
        "Failed to send MSG_DREPL_ALLOCATE_RID, "
95
0
        "unable to locate dreplsrv");
96
    /* this means the drepl service is not running */
97
0
    talloc_free(tmp_ctx);
98
0
    return LDB_ERR_UNWILLING_TO_PERFORM;
99
0
  }
100
101
0
  status = imessaging_send(msg, servers[0], MSG_DREPL_ALLOCATE_RID, NULL);
102
103
  /* Only error out if an error happened, not on STATUS_MORE_ENTRIES, ie a delayed message */
104
0
  if (NT_STATUS_IS_ERR(status)) {
105
0
    struct server_id_buf idbuf;
106
0
    ldb_asprintf_errstring(ldb_module_get_ctx(module),
107
0
        "Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s",
108
0
        server_id_str_buf(*servers, &idbuf),
109
0
        nt_errstr(status));
110
0
    talloc_free(tmp_ctx);
111
0
    return LDB_ERR_UNWILLING_TO_PERFORM;
112
0
  }
113
114
0
  talloc_free(tmp_ctx);
115
0
  return LDB_SUCCESS;
116
0
}
117
118
119
static const char * const ridalloc_ridset_attrs[] = {
120
  "rIDAllocationPool",
121
  "rIDPreviousAllocationPool",
122
  "rIDNextRID",
123
  "rIDUsedPool",
124
  NULL
125
};
126
127
struct ridalloc_ridset_values {
128
  uint64_t alloc_pool;
129
  uint64_t prev_pool;
130
  uint32_t next_rid;
131
  uint32_t used_pool;
132
};
133
134
static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
135
0
{
136
0
  v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
137
0
  v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
138
0
  v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
139
0
  v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
140
0
}
141
142
static int ridalloc_set_ridset_values(struct ldb_module *module,
143
              struct ldb_message *msg,
144
              const struct ridalloc_ridset_values *o,
145
              const struct ridalloc_ridset_values *n)
146
0
{
147
0
  const uint32_t *o32, *n32;
148
0
  const uint64_t *o64, *n64;
149
0
  int ret;
150
151
0
#define SETUP_PTRS(field, optr, nptr, max) do { \
152
0
  optr = &o->field; \
153
0
  nptr = &n->field; \
154
0
  if (o->field == max) { \
155
0
    optr = NULL; \
156
0
  } \
157
0
  if (n->field == max) { \
158
0
    nptr = NULL; \
159
0
  } \
160
0
  if (o->field == n->field) { \
161
0
    optr = NULL; \
162
0
    nptr = NULL; \
163
0
  } \
164
0
} while(0)
165
166
0
  SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
167
0
  ret = dsdb_msg_constrainted_update_uint64(module, msg,
168
0
              "rIDAllocationPool",
169
0
              o64, n64);
170
0
  if (ret != LDB_SUCCESS) {
171
0
    return ret;
172
0
  }
173
174
0
  SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
175
0
  ret = dsdb_msg_constrainted_update_uint64(module, msg,
176
0
              "rIDPreviousAllocationPool",
177
0
              o64, n64);
178
0
  if (ret != LDB_SUCCESS) {
179
0
    return ret;
180
0
  }
181
182
0
  SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
183
0
  ret = dsdb_msg_constrainted_update_uint32(module, msg,
184
0
              "rIDNextRID",
185
0
              o32, n32);
186
0
  if (ret != LDB_SUCCESS) {
187
0
    return ret;
188
0
  }
189
190
0
  SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
191
0
  ret = dsdb_msg_constrainted_update_uint32(module, msg,
192
0
              "rIDUsedPool",
193
0
              o32, n32);
194
0
  if (ret != LDB_SUCCESS) {
195
0
    return ret;
196
0
  }
197
0
#undef SETUP_PTRS
198
199
0
  return LDB_SUCCESS;
200
0
}
201
202
/*
203
  allocate a new range of RIDs in the RID Manager object
204
 */
205
static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
206
           struct ldb_request *parent)
207
0
{
208
0
  int ret;
209
0
  TALLOC_CTX *tmp_ctx = talloc_new(module);
210
0
  const char *attrs[] = { "rIDAvailablePool", NULL };
211
0
  uint64_t rid_pool, new_rid_pool, dc_pool;
212
0
  uint32_t rid_pool_lo, rid_pool_hi;
213
0
  struct ldb_result *res;
214
0
  struct ldb_context *ldb = ldb_module_get_ctx(module);
215
0
  const unsigned alloc_size = 500;
216
217
0
  ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
218
0
                              attrs, DSDB_FLAG_NEXT_MODULE, parent);
219
0
  if (ret != LDB_SUCCESS) {
220
0
    ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
221
0
               ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
222
0
    talloc_free(tmp_ctx);
223
0
    return ret;
224
0
  }
225
226
0
  rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
227
0
  rid_pool_lo = rid_pool & 0xFFFFFFFF;
228
0
  rid_pool_hi = rid_pool >> 32;
229
0
  if (rid_pool_lo >= rid_pool_hi) {
230
0
    ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
231
0
               rid_pool_lo, rid_pool_hi);
232
0
    talloc_free(tmp_ctx);
233
0
    return ret;
234
0
  }
235
236
  /* lower part of new pool is the low part of the rIDAvailablePool */
237
0
  dc_pool = rid_pool_lo;
238
239
  /* allocate 500 RIDs to this DC */
240
0
  rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
241
242
  /* work out upper part of new pool */
243
0
  dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
244
245
  /* and new rIDAvailablePool value */
246
0
  new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
247
248
0
  ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
249
0
                 &rid_pool, &new_rid_pool, parent);
250
0
  if (ret != LDB_SUCCESS) {
251
0
    ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
252
0
               ldb_errstring(ldb));
253
0
    talloc_free(tmp_ctx);
254
0
    return ret;
255
0
  }
256
257
0
  (*new_pool) = dc_pool;
258
0
  talloc_free(tmp_ctx);
259
0
  return LDB_SUCCESS;
260
0
}
261
262
/*
263
  create a RID Set object for the specified DC
264
 */
265
static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
266
          struct ldb_dn *rid_manager_dn,
267
          struct ldb_dn *ntds_dn, struct ldb_dn **dn,
268
          struct ldb_request *parent)
269
0
{
270
0
  TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
271
0
  struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
272
0
  int ret;
273
0
  struct ldb_message *msg;
274
0
  struct ldb_context *ldb = ldb_module_get_ctx(module);
275
0
  static const struct ridalloc_ridset_values o = {
276
0
    .alloc_pool = UINT64_MAX,
277
0
    .prev_pool  = UINT64_MAX,
278
0
    .next_rid = UINT32_MAX,
279
0
    .used_pool  = UINT32_MAX,
280
0
  };
281
0
  struct ridalloc_ridset_values n = {
282
0
    .alloc_pool = 0,
283
0
    .prev_pool  = 0,
284
0
    .next_rid = 0,
285
0
    .used_pool  = 0,
286
0
  };
287
0
  const char *no_attrs[] = { NULL };
288
0
  struct ldb_result *res;
289
290
  /*
291
    steps:
292
293
    find the machine object for the DC
294
    construct the RID Set DN
295
    load rIDAvailablePool to find next available set
296
    modify RID Manager object to update rIDAvailablePool
297
    add the RID Set object
298
    link to the RID Set object in machine object
299
   */
300
301
0
  server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
302
0
  if (!server_dn) {
303
0
    talloc_free(tmp_ctx);
304
0
    return ldb_module_oom(module);
305
0
  }
306
307
0
  ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
308
0
  if (ret != LDB_SUCCESS) {
309
0
    ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
310
0
               ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
311
0
    talloc_free(tmp_ctx);
312
0
    return ret;
313
0
  }
314
315
0
  rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
316
0
  if (rid_set_dn == NULL) {
317
0
    talloc_free(tmp_ctx);
318
0
    return ldb_module_oom(module);
319
0
  }
320
321
0
  if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
322
0
    talloc_free(tmp_ctx);
323
0
    return ldb_module_oom(module);
324
0
  }
325
326
  /* grab a pool from the RID Manager object */
327
0
  ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
328
0
  if (ret != LDB_SUCCESS) {
329
0
    talloc_free(tmp_ctx);
330
0
    return ret;
331
0
  }
332
333
  /* create the RID Set object */
334
0
  msg = ldb_msg_new(tmp_ctx);
335
0
  msg->dn = rid_set_dn;
336
337
0
  ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
338
0
  if (ret != LDB_SUCCESS) {
339
0
    talloc_free(tmp_ctx);
340
0
    return ret;
341
0
  }
342
343
0
  ret = ridalloc_set_ridset_values(module, msg, &o, &n);
344
0
  if (ret != LDB_SUCCESS) {
345
0
    talloc_free(tmp_ctx);
346
0
    return ret;
347
0
  }
348
349
  /* we need this to go all the way to the top of the module
350
   * stack, as we need all the extra attributes added (including
351
   * complex ones like ntsecuritydescriptor).  We must do this
352
   * as system, otherwise a user might end up owning the RID
353
   * set, and that would be bad... */
354
0
  ret = dsdb_module_add(module, msg,
355
0
            DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM
356
0
            | DSDB_MODIFY_RELAX, parent);
357
0
  if (ret != LDB_SUCCESS) {
358
0
    ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
359
0
               ldb_dn_get_linearized(msg->dn),
360
0
               ldb_errstring(ldb));
361
0
    talloc_free(tmp_ctx);
362
0
    return ret;
363
0
  }
364
365
  /* add the rIDSetReferences link */
366
0
  msg = ldb_msg_new(tmp_ctx);
367
0
  msg->dn = machine_dn;
368
369
  /* we need the extended DN of the RID Set object for
370
   * rIDSetReferences */
371
0
  ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs,
372
0
            DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent);
373
0
  if (ret != LDB_SUCCESS) {
374
0
    ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s",
375
0
               ldb_dn_get_linearized(msg->dn),
376
0
               ldb_errstring(ldb));
377
0
    talloc_free(tmp_ctx);
378
0
    return ret;
379
0
  }
380
0
  rid_set_dn = res->msgs[0]->dn;
381
382
383
0
  ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
384
0
  if (ret != LDB_SUCCESS) {
385
0
    talloc_free(tmp_ctx);
386
0
    return ret;
387
0
  }
388
0
  msg->elements[0].flags = LDB_FLAG_MOD_ADD;
389
390
0
  ret = dsdb_module_modify(module, msg,
391
0
         DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM,
392
0
         parent);
393
0
  if (ret != LDB_SUCCESS) {
394
0
    ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
395
0
               ldb_dn_get_linearized(msg->dn),
396
0
               ldb_errstring(ldb));
397
0
    talloc_free(tmp_ctx);
398
0
    return ret;
399
0
  }
400
401
0
  (*dn) = talloc_steal(mem_ctx, rid_set_dn);
402
403
0
  talloc_free(tmp_ctx);
404
0
  return LDB_SUCCESS;
405
0
}
406
407
408
/*
409
  create a RID Set object for this DC
410
 */
411
int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
412
        struct ldb_dn **dn, struct ldb_request *parent)
413
0
{
414
0
  TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
415
0
  struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
416
0
  int ret;
417
0
  struct ldb_context *ldb = ldb_module_get_ctx(module);
418
0
  struct GUID fsmo_role_guid;
419
0
  const struct GUID *our_ntds_guid;
420
0
  NTSTATUS status;
421
422
  /* work out who is the RID Manager */
423
0
  ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
424
0
  if (ret != LDB_SUCCESS) {
425
0
    ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
426
0
               ldb_errstring(ldb));
427
0
    talloc_free(tmp_ctx);
428
0
    return ret;
429
0
  }
430
431
  /* find the DN of the RID Manager */
432
0
  ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
433
0
  if (ret != LDB_SUCCESS) {
434
0
    ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
435
0
               ldb_errstring(ldb));
436
0
    talloc_free(tmp_ctx);
437
0
    return ret;
438
0
  }
439
440
0
  status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
441
0
  if (!NT_STATUS_IS_OK(status)) {
442
0
    talloc_free(tmp_ctx);
443
0
    return ldb_operr(ldb_module_get_ctx(module));
444
0
  }
445
446
  /* clear the cache so we don't get an old ntds_guid */
447
0
  if (ldb_set_opaque(ldb, "cache.ntds_guid", NULL) != LDB_SUCCESS) {
448
0
    talloc_free(tmp_ctx);
449
0
    return ldb_operr(ldb_module_get_ctx(module));
450
0
  }
451
452
0
  our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
453
0
  if (!our_ntds_guid) {
454
0
    talloc_free(tmp_ctx);
455
0
    return ldb_operr(ldb_module_get_ctx(module));
456
0
  }
457
458
0
  if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
459
0
    ret = ridalloc_poke_rid_manager(module);
460
0
    if (ret != LDB_SUCCESS) {
461
0
      ldb_asprintf_errstring(ldb,
462
0
          "Request for remote creation of "
463
0
          "RID Set for this DC failed: %s",
464
0
          ldb_errstring(ldb));
465
0
    } else {
466
0
      ldb_asprintf_errstring(ldb,
467
0
          "Remote RID Set creation needed");
468
0
    }
469
0
    talloc_free(tmp_ctx);
470
0
    return LDB_ERR_UNWILLING_TO_PERFORM;
471
0
  }
472
473
0
  ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
474
0
  talloc_free(tmp_ctx);
475
0
  return ret;
476
0
}
477
478
/*
479
  get a new RID pool for ourselves
480
  also returns the first rid for the new pool
481
 */
482
483
int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
484
0
{
485
0
  TALLOC_CTX *tmp_ctx = talloc_new(module);
486
0
  struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
487
0
  int ret;
488
0
  struct ldb_context *ldb = ldb_module_get_ctx(module);
489
0
  bool is_us;
490
491
  /* work out who is the RID Manager */
492
0
  ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
493
0
  if (ret != LDB_SUCCESS) {
494
0
    ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
495
0
               ldb_errstring(ldb));
496
0
    talloc_free(tmp_ctx);
497
0
    return ret;
498
0
  }
499
500
  /* find the DN of the RID Manager */
501
0
  ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
502
0
  if (ret != LDB_SUCCESS) {
503
0
    ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
504
0
               ldb_errstring(ldb));
505
0
    talloc_free(tmp_ctx);
506
0
    return ret;
507
0
  }
508
509
0
  ret = samdb_dn_is_our_ntdsa(ldb, fsmo_role_dn, &is_us);
510
0
  if (ret != LDB_SUCCESS) {
511
0
    ldb_asprintf_errstring(ldb, "Failed to confirm if our ntdsDsa is %s: %s",
512
0
               ldb_dn_get_linearized(fsmo_role_dn), ldb_errstring(ldb));
513
0
    talloc_free(tmp_ctx);
514
0
    return ret;
515
0
  }
516
  
517
0
  if (!is_us) {
518
0
    ret = ridalloc_poke_rid_manager(module);
519
0
    if (ret != LDB_SUCCESS) {
520
0
      ldb_asprintf_errstring(ldb, "Request for remote refresh of RID Set allocation failed: %s",
521
0
                 ldb_errstring(ldb));
522
0
    } else {
523
0
      ldb_asprintf_errstring(ldb, "Remote RID Set refresh needed");
524
0
    }
525
0
    talloc_free(tmp_ctx);
526
0
    return LDB_ERR_UNWILLING_TO_PERFORM;
527
0
  }
528
529
  /* grab a pool from the RID Manager object */
530
0
  ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
531
0
  if (ret != LDB_SUCCESS) {
532
0
    talloc_free(tmp_ctx);
533
0
    return ret;
534
0
  }
535
536
0
  talloc_free(tmp_ctx);
537
0
  return ret;
538
0
}
539
540
541
/* allocate a RID using our RID Set
542
   If we run out of RIDs then allocate a new pool
543
   either locally or by contacting the RID Manager
544
*/
545
int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
546
0
{
547
0
  struct ldb_context *ldb;
548
0
  int ret;
549
0
  struct ldb_dn *rid_set_dn;
550
0
  struct ldb_result *res;
551
0
  struct ldb_message *msg;
552
0
  struct ridalloc_ridset_values oridset;
553
0
  struct ridalloc_ridset_values nridset;
554
0
  uint32_t prev_pool_lo, prev_pool_hi;
555
0
  TALLOC_CTX *tmp_ctx = talloc_new(module);
556
557
0
  (*rid) = 0;
558
0
  ldb = ldb_module_get_ctx(module);
559
560
0
  ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
561
0
  if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
562
0
    ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
563
0
  }
564
0
  if (ret != LDB_SUCCESS) {
565
0
    ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
566
0
               ldb_errstring(ldb));
567
0
    talloc_free(tmp_ctx);
568
0
    return ret;
569
0
  }
570
571
0
  ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
572
0
            ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
573
0
  if (ret != LDB_SUCCESS) {
574
0
    ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
575
0
               ldb_dn_get_linearized(rid_set_dn));
576
0
    talloc_free(tmp_ctx);
577
0
    return ret;
578
0
  }
579
580
0
  ridalloc_get_ridset_values(res->msgs[0], &oridset);
581
0
  if (oridset.alloc_pool == UINT64_MAX) {
582
0
    ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
583
0
               ldb_dn_get_linearized(rid_set_dn));
584
0
    talloc_free(tmp_ctx);
585
0
    return LDB_ERR_OPERATIONS_ERROR;
586
0
  }
587
588
0
  nridset = oridset;
589
590
  /*
591
   * If we never used a pool, setup out first pool
592
   */
593
0
  if (nridset.prev_pool == UINT64_MAX ||
594
0
      nridset.next_rid == UINT32_MAX) {
595
0
    nridset.prev_pool = nridset.alloc_pool;
596
0
    nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
597
0
  } else {
598
0
    nridset.next_rid += 1;
599
0
  }
600
601
  /*
602
   * Now check if our current pool is still usable
603
   */
604
0
  prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
605
0
  prev_pool_hi = nridset.prev_pool >> 32;
606
0
  if (nridset.next_rid > prev_pool_hi) {
607
    /*
608
     * We need a new pool, check if we already have a new one
609
     * Otherwise we need to get a new pool.
610
     */
611
0
    if (nridset.alloc_pool == nridset.prev_pool) {
612
      /*
613
       * if we are the RID Manager,
614
       * we can get a new pool locally.
615
       * Otherwise we fail the operation and
616
       * ask async for a new pool.
617
       */
618
0
      ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
619
0
      if (ret != LDB_SUCCESS) {
620
0
        ldb_asprintf_errstring(ldb, "NO RID values available: %s",
621
0
                   ldb_errstring(ldb));
622
0
        talloc_free(tmp_ctx);
623
0
        return ret;
624
0
      }
625
0
    }
626
627
    /*
628
     * increment the rIDUsedPool attribute
629
     *
630
     * Note: w2k8r2 doesn't update this attribute,
631
     *       at least if it's itself the rid master.
632
     */
633
0
    nridset.used_pool += 1;
634
635
    /* now use the new pool */
636
0
    nridset.prev_pool = nridset.alloc_pool;
637
0
    prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
638
0
    prev_pool_hi = nridset.prev_pool >> 32;
639
0
    nridset.next_rid = prev_pool_lo;
640
0
  }
641
642
0
  if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
643
0
    ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
644
0
               (unsigned)nridset.next_rid,
645
0
               (unsigned)prev_pool_lo,
646
0
               (unsigned)prev_pool_hi);
647
0
    talloc_free(tmp_ctx);
648
0
    return LDB_ERR_OPERATIONS_ERROR;
649
0
  }
650
651
  /*
652
   * if we are half-exhausted then try to get a new pool.
653
   */
654
0
  if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2 &&
655
0
      nridset.alloc_pool == nridset.prev_pool) {
656
    /*
657
     * if we are the RID Manager,
658
     * we can get a new pool locally.
659
     * Otherwise we fail the operation and
660
     * ask async for a new pool.
661
     */
662
0
    ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
663
0
    if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
664
0
      ldb_reset_err_string(ldb);
665
0
      ret = LDB_SUCCESS;
666
0
    }
667
0
    if (ret != LDB_SUCCESS) {
668
0
      talloc_free(tmp_ctx);
669
0
      return ret;
670
0
    }
671
0
  }
672
673
  /*
674
   * update the values
675
   */
676
0
  msg = ldb_msg_new(tmp_ctx);
677
0
  if (msg == NULL) {
678
0
    return ldb_module_oom(module);
679
0
  }
680
0
  msg->dn = rid_set_dn;
681
682
0
  ret = ridalloc_set_ridset_values(module, msg,
683
0
           &oridset, &nridset);
684
0
  if (ret != LDB_SUCCESS) {
685
0
    talloc_free(tmp_ctx);
686
0
    return ret;
687
0
  }
688
689
0
  ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent);
690
0
  if (ret != LDB_SUCCESS) {
691
0
    talloc_free(tmp_ctx);
692
0
    return ret;
693
0
  }
694
695
0
  talloc_free(tmp_ctx);
696
0
  *rid = nridset.next_rid;
697
0
  return LDB_SUCCESS;
698
0
}
699
700
701
/*
702
  called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
703
704
  This is for the DRS server to allocate a RID Pool for another server.
705
706
  Called by another server over DRS (which calls this extended
707
  operation), it runs on the RID Manager only.
708
 */
709
int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
710
            struct ldb_request *parent)
711
0
{
712
0
  struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
713
0
  struct ldb_dn *rid_manager_dn;
714
0
  TALLOC_CTX *tmp_ctx = talloc_new(module);
715
0
  int ret;
716
0
  struct ldb_context *ldb = ldb_module_get_ctx(module);
717
0
  struct ldb_result *res;
718
0
  struct ldb_message *msg;
719
0
  struct ridalloc_ridset_values oridset, nridset;
720
721
0
  ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
722
0
  if (ret != LDB_SUCCESS) {
723
0
    ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
724
0
               GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
725
0
    talloc_free(tmp_ctx);
726
0
    return ret;
727
0
  }
728
729
0
  server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
730
0
  if (!server_dn) {
731
0
    talloc_free(tmp_ctx);
732
0
    return ldb_module_oom(module);
733
0
  }
734
735
0
  ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
736
0
  if (ret != LDB_SUCCESS) {
737
0
    ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
738
0
               ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
739
0
    talloc_free(tmp_ctx);
740
0
    return ret;
741
0
  }
742
743
0
  ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
744
0
  if (ret != LDB_SUCCESS) {
745
0
    ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
746
0
               ldb_errstring(ldb));
747
0
    talloc_free(tmp_ctx);
748
0
    return ret;
749
0
  }
750
751
0
  ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
752
0
  if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
753
0
    ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
754
0
    talloc_free(tmp_ctx);
755
0
    return ret;
756
0
  }
757
758
0
  if (ret != LDB_SUCCESS) {
759
0
    ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
760
0
               ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
761
0
    talloc_free(tmp_ctx);
762
0
    return ret;
763
0
  }
764
765
0
  ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
766
0
            ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
767
0
  if (ret != LDB_SUCCESS) {
768
0
    ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
769
0
               ldb_dn_get_linearized(rid_set_dn));
770
0
    talloc_free(tmp_ctx);
771
0
    return ret;
772
0
  }
773
774
0
  ridalloc_get_ridset_values(res->msgs[0], &oridset);
775
0
  if (oridset.alloc_pool == UINT64_MAX) {
776
0
    ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
777
0
               ldb_dn_get_linearized(rid_set_dn));
778
0
    talloc_free(tmp_ctx);
779
0
    return LDB_ERR_OPERATIONS_ERROR;
780
0
  }
781
782
0
  nridset = oridset;
783
784
0
  if (exop->fsmo_info != 0) {
785
786
0
    if (nridset.alloc_pool != exop->fsmo_info) {
787
      /* it has already been updated */
788
0
      DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
789
0
         (unsigned long long)exop->fsmo_info,
790
0
         (unsigned long long)nridset.alloc_pool));
791
0
      talloc_free(tmp_ctx);
792
0
      return LDB_SUCCESS;
793
0
    }
794
0
  }
795
796
  /* grab a pool from the RID Manager object */
797
0
  ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
798
0
  if (ret != LDB_SUCCESS) {
799
0
    talloc_free(tmp_ctx);
800
0
    return ret;
801
0
  }
802
803
  /*
804
   * update the values
805
   */
806
0
  msg = ldb_msg_new(tmp_ctx);
807
0
  if (msg == NULL) {
808
0
    return ldb_module_oom(module);
809
0
  }
810
0
  msg->dn = rid_set_dn;
811
812
0
  ret = ridalloc_set_ridset_values(module, msg,
813
0
           &oridset, &nridset);
814
0
  if (ret != LDB_SUCCESS) {
815
0
    talloc_free(tmp_ctx);
816
0
    return ret;
817
0
  }
818
819
0
  ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE|DSDB_FLAG_AS_SYSTEM, parent);
820
0
  if (ret != LDB_SUCCESS) {
821
0
    ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
822
0
               ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
823
0
    talloc_free(tmp_ctx);
824
0
    return ret;
825
0
  }
826
827
0
  talloc_free(tmp_ctx);
828
0
  return LDB_SUCCESS;
829
0
}