~lefteris-nikoltsios/+junk/samba-lp1016895

« back to all changes in this revision

Viewing changes to source4/dsdb/samdb/ldb_modules/ridalloc.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "dsdb/samdb/samdb.h"
 
33
#include "dsdb/samdb/ldb_modules/util.h"
 
34
#include "lib/messaging/irpc.h"
 
35
#include "param/param.h"
 
36
#include "librpc/gen_ndr/ndr_misc.h"
 
37
 
 
38
/*
 
39
  Note: the RID allocation attributes in AD are very badly named. Here
 
40
  is what we think they really do:
 
41
 
 
42
  in RID Set object:
 
43
    - rIDPreviousAllocationPool: the pool which a DC is currently
 
44
      pulling RIDs from. Managed by client DC
 
45
 
 
46
    - rIDAllocationPool: the pool that the DC will switch to next,
 
47
      when rIDPreviousAllocationPool is exhausted. Managed by RID Manager.
 
48
 
 
49
    - rIDNextRID: the last RID allocated by this DC. Managed by client DC
 
50
 
 
51
  in RID Manager object:
 
52
    - rIDAvailablePool: the pool where the RID Manager gets new rID
 
53
      pools from when it gets a EXOP_RID_ALLOC getncchanges call (or
 
54
      locally when the DC is the RID Manager)
 
55
 */
 
56
 
 
57
 
 
58
/*
 
59
  make a IRPC call to the drepl task to ask it to get the RID
 
60
  Manager to give us another RID pool.
 
61
 
 
62
  This function just sends the message to the drepl task then
 
63
  returns immediately. It should be called well before we
 
64
  completely run out of RIDs
 
65
 */
 
66
static void ridalloc_poke_rid_manager(struct ldb_module *module)
 
67
{
 
68
        struct messaging_context *msg;
 
69
        struct server_id *server;
 
70
        struct ldb_context *ldb = ldb_module_get_ctx(module);
 
71
        struct loadparm_context *lp_ctx =
 
72
                (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
 
73
        TALLOC_CTX *tmp_ctx = talloc_new(module);
 
74
 
 
75
        msg = messaging_client_init(tmp_ctx, lpcfg_messaging_path(tmp_ctx, lp_ctx),
 
76
                                    ldb_get_event_context(ldb));
 
77
        if (!msg) {
 
78
                DEBUG(3,(__location__ ": Failed to create messaging context\n"));
 
79
                talloc_free(tmp_ctx);
 
80
                return;
 
81
        }
 
82
 
 
83
        server = irpc_servers_byname(msg, msg, "dreplsrv");
 
84
        if (!server) {
 
85
                /* this means the drepl service is not running */
 
86
                talloc_free(tmp_ctx);
 
87
                return;
 
88
        }
 
89
 
 
90
        messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);
 
91
 
 
92
        /* we don't care if the message got through */
 
93
        talloc_free(tmp_ctx);
 
94
}
 
95
 
 
96
 
 
97
static const char * const ridalloc_ridset_attrs[] = {
 
98
        "rIDAllocationPool",
 
99
        "rIDPreviousAllocationPool",
 
100
        "rIDNextRID",
 
101
        "rIDUsedPool",
 
102
        NULL
 
103
};
 
104
 
 
105
struct ridalloc_ridset_values {
 
106
        uint64_t alloc_pool;
 
107
        uint64_t prev_pool;
 
108
        uint32_t next_rid;
 
109
        uint32_t used_pool;
 
110
};
 
111
 
 
112
static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v)
 
113
{
 
114
        v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX);
 
115
        v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX);
 
116
        v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX);
 
117
        v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX);
 
118
}
 
119
 
 
120
static int ridalloc_set_ridset_values(struct ldb_module *module,
 
121
                                      struct ldb_message *msg,
 
122
                                      const struct ridalloc_ridset_values *o,
 
123
                                      const struct ridalloc_ridset_values *n)
 
124
{
 
125
        const uint32_t *o32, *n32;
 
126
        const uint64_t *o64, *n64;
 
127
        int ret;
 
128
 
 
129
#define SETUP_PTRS(field, optr, nptr, max) do { \
 
130
        optr = &o->field; \
 
131
        nptr = &n->field; \
 
132
        if (o->field == max) { \
 
133
                optr = NULL; \
 
134
        } \
 
135
        if (n->field == max) { \
 
136
                nptr = NULL; \
 
137
        } \
 
138
        if (o->field == n->field) { \
 
139
                optr = NULL; \
 
140
                nptr = NULL; \
 
141
        } \
 
142
} while(0)
 
143
 
 
144
        SETUP_PTRS(alloc_pool, o64, n64, UINT64_MAX);
 
145
        ret = dsdb_msg_constrainted_update_uint64(module, msg,
 
146
                                                  "rIDAllocationPool",
 
147
                                                  o64, n64);
 
148
        if (ret != LDB_SUCCESS) {
 
149
                return ret;
 
150
        }
 
151
 
 
152
        SETUP_PTRS(prev_pool, o64, n64, UINT64_MAX);
 
153
        ret = dsdb_msg_constrainted_update_uint64(module, msg,
 
154
                                                  "rIDPreviousAllocationPool",
 
155
                                                  o64, n64);
 
156
        if (ret != LDB_SUCCESS) {
 
157
                return ret;
 
158
        }
 
159
 
 
160
        SETUP_PTRS(next_rid, o32, n32, UINT32_MAX);
 
161
        ret = dsdb_msg_constrainted_update_uint32(module, msg,
 
162
                                                  "rIDNextRID",
 
163
                                                  o32, n32);
 
164
        if (ret != LDB_SUCCESS) {
 
165
                return ret;
 
166
        }
 
167
 
 
168
        SETUP_PTRS(used_pool, o32, n32, UINT32_MAX);
 
169
        ret = dsdb_msg_constrainted_update_uint32(module, msg,
 
170
                                                  "rIDUsedPool",
 
171
                                                  o32, n32);
 
172
        if (ret != LDB_SUCCESS) {
 
173
                return ret;
 
174
        }
 
175
#undef SETUP_PTRS
 
176
 
 
177
        return LDB_SUCCESS;
 
178
}
 
179
 
 
180
/*
 
181
  allocate a new range of RIDs in the RID Manager object
 
182
 */
 
183
static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
 
184
                                         struct ldb_request *parent)
 
185
{
 
186
        int ret;
 
187
        TALLOC_CTX *tmp_ctx = talloc_new(module);
 
188
        const char *attrs[] = { "rIDAvailablePool", NULL };
 
189
        uint64_t rid_pool, new_rid_pool, dc_pool;
 
190
        uint32_t rid_pool_lo, rid_pool_hi;
 
191
        struct ldb_result *res;
 
192
        struct ldb_context *ldb = ldb_module_get_ctx(module);
 
193
        const unsigned alloc_size = 500;
 
194
 
 
195
        ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
 
196
                                    attrs, DSDB_FLAG_NEXT_MODULE, parent);
 
197
        if (ret != LDB_SUCCESS) {
 
198
                ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
 
199
                                       ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
 
200
                talloc_free(tmp_ctx);
 
201
                return ret;
 
202
        }
 
203
 
 
204
        rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
 
205
        rid_pool_lo = rid_pool & 0xFFFFFFFF;
 
206
        rid_pool_hi = rid_pool >> 32;
 
207
        if (rid_pool_lo >= rid_pool_hi) {
 
208
                ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
 
209
                                       rid_pool_lo, rid_pool_hi);
 
210
                talloc_free(tmp_ctx);
 
211
                return ret;
 
212
        }
 
213
 
 
214
        /* lower part of new pool is the low part of the rIDAvailablePool */
 
215
        dc_pool = rid_pool_lo;
 
216
 
 
217
        /* allocate 500 RIDs to this DC */
 
218
        rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);
 
219
 
 
220
        /* work out upper part of new pool */
 
221
        dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);
 
222
 
 
223
        /* and new rIDAvailablePool value */
 
224
        new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);
 
225
 
 
226
        ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
 
227
                                                     &rid_pool, &new_rid_pool, parent);
 
228
        if (ret != LDB_SUCCESS) {
 
229
                ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
 
230
                                       ldb_errstring(ldb));
 
231
                talloc_free(tmp_ctx);
 
232
                return ret;
 
233
        }
 
234
 
 
235
        (*new_pool) = dc_pool;
 
236
        talloc_free(tmp_ctx);
 
237
        return LDB_SUCCESS;
 
238
}
 
239
 
 
240
/*
 
241
  create a RID Set object for the specified DC
 
242
 */
 
243
static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
 
244
                                        struct ldb_dn *rid_manager_dn,
 
245
                                        struct ldb_dn *ntds_dn, struct ldb_dn **dn,
 
246
                                        struct ldb_request *parent)
 
247
{
 
248
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 
249
        struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
 
250
        int ret;
 
251
        struct ldb_message *msg;
 
252
        struct ldb_context *ldb = ldb_module_get_ctx(module);
 
253
        static const struct ridalloc_ridset_values o = {
 
254
                .alloc_pool     = UINT64_MAX,
 
255
                .prev_pool      = UINT64_MAX,
 
256
                .next_rid       = UINT32_MAX,
 
257
                .used_pool      = UINT32_MAX,
 
258
        };
 
259
        struct ridalloc_ridset_values n = {
 
260
                .alloc_pool     = 0,
 
261
                .prev_pool      = 0,
 
262
                .next_rid       = 0,
 
263
                .used_pool      = 0,
 
264
        };
 
265
 
 
266
        /*
 
267
          steps:
 
268
 
 
269
          find the machine object for the DC
 
270
          construct the RID Set DN
 
271
          load rIDAvailablePool to find next available set
 
272
          modify RID Manager object to update rIDAvailablePool
 
273
          add the RID Set object
 
274
          link to the RID Set object in machine object
 
275
         */
 
276
 
 
277
        server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
 
278
        if (!server_dn) {
 
279
                talloc_free(tmp_ctx);
 
280
                return ldb_module_oom(module);
 
281
        }
 
282
 
 
283
        ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
 
284
        if (ret != LDB_SUCCESS) {
 
285
                ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
 
286
                                       ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
 
287
                talloc_free(tmp_ctx);
 
288
                return ret;
 
289
        }
 
290
 
 
291
        rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
 
292
        if (rid_set_dn == NULL) {
 
293
                talloc_free(tmp_ctx);
 
294
                return ldb_module_oom(module);
 
295
        }
 
296
 
 
297
        if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
 
298
                talloc_free(tmp_ctx);
 
299
                return ldb_module_oom(module);
 
300
        }
 
301
 
 
302
        /* grab a pool from the RID Manager object */
 
303
        ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
 
304
        if (ret != LDB_SUCCESS) {
 
305
                talloc_free(tmp_ctx);
 
306
                return ret;
 
307
        }
 
308
 
 
309
        /* create the RID Set object */
 
310
        msg = ldb_msg_new(tmp_ctx);
 
311
        msg->dn = rid_set_dn;
 
312
 
 
313
        ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
 
314
        if (ret != LDB_SUCCESS) {
 
315
                talloc_free(tmp_ctx);
 
316
                return ret;
 
317
        }
 
318
 
 
319
        ret = ridalloc_set_ridset_values(module, msg, &o, &n);
 
320
        if (ret != LDB_SUCCESS) {
 
321
                talloc_free(tmp_ctx);
 
322
                return ret;
 
323
        }
 
324
 
 
325
        /* we need this to go all the way to the top of the module
 
326
         * stack, as we need all the extra attributes added (including
 
327
         * complex ones like ntsecuritydescriptor) */
 
328
        ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX, parent);
 
329
        if (ret != LDB_SUCCESS) {
 
330
                ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
 
331
                                       ldb_dn_get_linearized(msg->dn),
 
332
                                       ldb_errstring(ldb));
 
333
                talloc_free(tmp_ctx);
 
334
                return ret;
 
335
        }
 
336
 
 
337
        /* add the rIDSetReferences link */
 
338
        msg = ldb_msg_new(tmp_ctx);
 
339
        msg->dn = machine_dn;
 
340
 
 
341
        ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_linearized(rid_set_dn));
 
342
        if (ret != LDB_SUCCESS) {
 
343
                talloc_free(tmp_ctx);
 
344
                return ret;
 
345
        }
 
346
        msg->elements[0].flags = LDB_FLAG_MOD_ADD;
 
347
 
 
348
        ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
 
349
        if (ret != LDB_SUCCESS) {
 
350
                ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
 
351
                                       ldb_dn_get_linearized(msg->dn),
 
352
                                       ldb_errstring(ldb));
 
353
                talloc_free(tmp_ctx);
 
354
                return ret;
 
355
        }
 
356
 
 
357
        (*dn) = talloc_steal(mem_ctx, rid_set_dn);
 
358
 
 
359
        talloc_free(tmp_ctx);
 
360
        return LDB_SUCCESS;
 
361
}
 
362
 
 
363
 
 
364
/*
 
365
  create a RID Set object for this DC
 
366
 */
 
367
static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
 
368
                                       struct ldb_dn **dn, struct ldb_request *parent)
 
369
{
 
370
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 
371
        struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
 
372
        int ret;
 
373
        struct ldb_context *ldb = ldb_module_get_ctx(module);
 
374
 
 
375
        /* work out who is the RID Manager */
 
376
        ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
 
377
        if (ret != LDB_SUCCESS) {
 
378
                ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
 
379
                                       ldb_errstring(ldb));
 
380
                talloc_free(tmp_ctx);
 
381
                return ret;
 
382
        }
 
383
 
 
384
        /* find the DN of the RID Manager */
 
385
        ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
 
386
        if (ret != LDB_SUCCESS) {
 
387
                ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
 
388
                                       ldb_errstring(ldb));
 
389
                talloc_free(tmp_ctx);
 
390
                return ret;
 
391
        }
 
392
 
 
393
        if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
 
394
                ridalloc_poke_rid_manager(module);
 
395
                ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
 
396
                talloc_free(tmp_ctx);
 
397
                return LDB_ERR_UNWILLING_TO_PERFORM;
 
398
        }
 
399
 
 
400
        ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
 
401
        talloc_free(tmp_ctx);
 
402
        return ret;
 
403
}
 
404
 
 
405
/*
 
406
  get a new RID pool for ourselves
 
407
  also returns the first rid for the new pool
 
408
 */
 
409
static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent)
 
410
{
 
411
        TALLOC_CTX *tmp_ctx = talloc_new(module);
 
412
        struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
 
413
        int ret;
 
414
        struct ldb_context *ldb = ldb_module_get_ctx(module);
 
415
 
 
416
        /* work out who is the RID Manager */
 
417
        ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
 
418
        if (ret != LDB_SUCCESS) {
 
419
                ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
 
420
                                       ldb_errstring(ldb));
 
421
                talloc_free(tmp_ctx);
 
422
                return ret;
 
423
        }
 
424
 
 
425
        /* find the DN of the RID Manager */
 
426
        ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
 
427
        if (ret != LDB_SUCCESS) {
 
428
                ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
 
429
                                       ldb_errstring(ldb));
 
430
                talloc_free(tmp_ctx);
 
431
                return ret;
 
432
        }
 
433
 
 
434
        if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) {
 
435
                ridalloc_poke_rid_manager(module);
 
436
                ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh");
 
437
                talloc_free(tmp_ctx);
 
438
                return LDB_ERR_UNWILLING_TO_PERFORM;
 
439
        }
 
440
 
 
441
        /* grab a pool from the RID Manager object */
 
442
        ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent);
 
443
        if (ret != LDB_SUCCESS) {
 
444
                talloc_free(tmp_ctx);
 
445
                return ret;
 
446
        }
 
447
 
 
448
        talloc_free(tmp_ctx);
 
449
        return ret;
 
450
}
 
451
 
 
452
 
 
453
/* allocate a RID using our RID Set
 
454
   If we run out of RIDs then allocate a new pool
 
455
   either locally or by contacting the RID Manager
 
456
*/
 
457
int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
 
458
{
 
459
        struct ldb_context *ldb;
 
460
        int ret;
 
461
        struct ldb_dn *rid_set_dn;
 
462
        struct ldb_result *res;
 
463
        struct ldb_message *msg;
 
464
        struct ridalloc_ridset_values oridset;
 
465
        struct ridalloc_ridset_values nridset;
 
466
        uint32_t prev_pool_lo, prev_pool_hi;
 
467
        TALLOC_CTX *tmp_ctx = talloc_new(module);
 
468
 
 
469
        (*rid) = 0;
 
470
        ldb = ldb_module_get_ctx(module);
 
471
 
 
472
        ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
 
473
        if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
 
474
                ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
 
475
        }
 
476
        if (ret != LDB_SUCCESS) {
 
477
                ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
 
478
                                       ldb_errstring(ldb));
 
479
                talloc_free(tmp_ctx);
 
480
                return ret;
 
481
        }
 
482
 
 
483
        ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
 
484
                                    ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
 
485
        if (ret != LDB_SUCCESS) {
 
486
                ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
 
487
                                       ldb_dn_get_linearized(rid_set_dn));
 
488
                talloc_free(tmp_ctx);
 
489
                return ret;
 
490
        }
 
491
 
 
492
        ridalloc_get_ridset_values(res->msgs[0], &oridset);
 
493
        if (oridset.alloc_pool == UINT64_MAX) {
 
494
                ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
 
495
                                       ldb_dn_get_linearized(rid_set_dn));
 
496
                talloc_free(tmp_ctx);
 
497
                return LDB_ERR_OPERATIONS_ERROR;
 
498
        }
 
499
 
 
500
        nridset = oridset;
 
501
 
 
502
        /*
 
503
         * If we never used a pool, setup out first pool
 
504
         */
 
505
        if (nridset.prev_pool == UINT64_MAX ||
 
506
            nridset.next_rid == UINT32_MAX) {
 
507
                nridset.prev_pool = nridset.alloc_pool;
 
508
                nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
 
509
        }
 
510
 
 
511
        /*
 
512
         * Now check if our current pool is still usable
 
513
         */
 
514
        nridset.next_rid += 1;
 
515
        prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
 
516
        prev_pool_hi = nridset.prev_pool >> 32;
 
517
        if (nridset.next_rid > prev_pool_hi) {
 
518
                /*
 
519
                 * We need a new pool, check if we already have a new one
 
520
                 * Otherwise we need to get a new pool.
 
521
                 */
 
522
                if (nridset.alloc_pool == nridset.prev_pool) {
 
523
                        /*
 
524
                         * if we are the RID Manager,
 
525
                         * we can get a new pool localy.
 
526
                         * Otherwise we fail the operation and
 
527
                         * ask async for a new pool.
 
528
                         */
 
529
                        ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
 
530
                        if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
 
531
                                ridalloc_poke_rid_manager(module);
 
532
                                talloc_free(tmp_ctx);
 
533
                                return ret;
 
534
                        }
 
535
                        if (ret != LDB_SUCCESS) {
 
536
                                talloc_free(tmp_ctx);
 
537
                                return ret;
 
538
                        }
 
539
                }
 
540
 
 
541
                /*
 
542
                 * increment the rIDUsedPool attribute
 
543
                 *
 
544
                 * Note: w2k8r2 doesn't update this attribute,
 
545
                 *       at least if it's itself the rid master.
 
546
                 */
 
547
                nridset.used_pool += 1;
 
548
 
 
549
                /* now use the new pool */
 
550
                nridset.prev_pool = nridset.alloc_pool;
 
551
                prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
 
552
                prev_pool_hi = nridset.prev_pool >> 32;
 
553
                nridset.next_rid = prev_pool_lo;
 
554
        }
 
555
 
 
556
        if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
 
557
                ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
 
558
                                       (unsigned)nridset.next_rid,
 
559
                                       (unsigned)prev_pool_lo,
 
560
                                       (unsigned)prev_pool_hi);
 
561
                talloc_free(tmp_ctx);
 
562
                return LDB_ERR_OPERATIONS_ERROR;
 
563
        }
 
564
 
 
565
        /*
 
566
         * if we are half-exhausted then try to get a new pool.
 
567
         */
 
568
        if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) {
 
569
                /*
 
570
                 * if we are the RID Manager,
 
571
                 * we can get a new pool localy.
 
572
                 * Otherwise we fail the operation and
 
573
                 * ask async for a new pool.
 
574
                 */
 
575
                ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
 
576
                if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
 
577
                        ridalloc_poke_rid_manager(module);
 
578
                        ret = LDB_SUCCESS;
 
579
                }
 
580
                if (ret != LDB_SUCCESS) {
 
581
                        talloc_free(tmp_ctx);
 
582
                        return ret;
 
583
                }
 
584
        }
 
585
 
 
586
        /*
 
587
         * update the values
 
588
         */
 
589
        msg = ldb_msg_new(tmp_ctx);
 
590
        if (msg == NULL) {
 
591
                return ldb_module_oom(module);
 
592
        }
 
593
        msg->dn = rid_set_dn;
 
594
 
 
595
        ret = ridalloc_set_ridset_values(module, msg,
 
596
                                         &oridset, &nridset);
 
597
        if (ret != LDB_SUCCESS) {
 
598
                talloc_free(tmp_ctx);
 
599
                return ret;
 
600
        }
 
601
 
 
602
        ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
 
603
        if (ret != LDB_SUCCESS) {
 
604
                talloc_free(tmp_ctx);
 
605
                return ret;
 
606
        }
 
607
 
 
608
        talloc_free(tmp_ctx);
 
609
        *rid = nridset.next_rid;
 
610
        return LDB_SUCCESS;
 
611
}
 
612
 
 
613
 
 
614
/*
 
615
  called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
 
616
 */
 
617
int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
 
618
                                    struct ldb_request *parent)
 
619
{
 
620
        struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
 
621
        struct ldb_dn *rid_manager_dn;
 
622
        TALLOC_CTX *tmp_ctx = talloc_new(module);
 
623
        int ret;
 
624
        struct ldb_context *ldb = ldb_module_get_ctx(module);
 
625
        struct ldb_result *res;
 
626
        struct ldb_message *msg;
 
627
        struct ridalloc_ridset_values oridset, nridset;
 
628
 
 
629
        ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
 
630
        if (ret != LDB_SUCCESS) {
 
631
                ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
 
632
                                       GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
 
633
                talloc_free(tmp_ctx);
 
634
                return ret;
 
635
        }
 
636
 
 
637
        server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
 
638
        if (!server_dn) {
 
639
                talloc_free(tmp_ctx);
 
640
                return ldb_module_oom(module);
 
641
        }
 
642
 
 
643
        ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
 
644
        if (ret != LDB_SUCCESS) {
 
645
                ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
 
646
                                       ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
 
647
                talloc_free(tmp_ctx);
 
648
                return ret;
 
649
        }
 
650
 
 
651
        ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
 
652
        if (ret != LDB_SUCCESS) {
 
653
                ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
 
654
                                       ldb_errstring(ldb));
 
655
                talloc_free(tmp_ctx);
 
656
                return ret;
 
657
        }
 
658
 
 
659
        ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
 
660
        if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
 
661
                ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
 
662
                talloc_free(tmp_ctx);
 
663
                return ret;
 
664
        }
 
665
 
 
666
        if (ret != LDB_SUCCESS) {
 
667
                ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
 
668
                                       ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
 
669
                talloc_free(tmp_ctx);
 
670
                return ret;
 
671
        }
 
672
 
 
673
        ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
 
674
                                    ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
 
675
        if (ret != LDB_SUCCESS) {
 
676
                ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
 
677
                                       ldb_dn_get_linearized(rid_set_dn));
 
678
                talloc_free(tmp_ctx);
 
679
                return ret;
 
680
        }
 
681
 
 
682
        ridalloc_get_ridset_values(res->msgs[0], &oridset);
 
683
        if (oridset.alloc_pool == UINT64_MAX) {
 
684
                ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
 
685
                                       ldb_dn_get_linearized(rid_set_dn));
 
686
                talloc_free(tmp_ctx);
 
687
                return LDB_ERR_OPERATIONS_ERROR;
 
688
        }
 
689
 
 
690
        nridset = oridset;
 
691
 
 
692
        if (exop->fsmo_info != 0) {
 
693
 
 
694
                if (nridset.alloc_pool != exop->fsmo_info) {
 
695
                        /* it has already been updated */
 
696
                        DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
 
697
                                 (unsigned long long)exop->fsmo_info,
 
698
                                 (unsigned long long)nridset.alloc_pool));
 
699
                        talloc_free(tmp_ctx);
 
700
                        return LDB_SUCCESS;
 
701
                }
 
702
        }
 
703
 
 
704
        /* grab a pool from the RID Manager object */
 
705
        ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
 
706
        if (ret != LDB_SUCCESS) {
 
707
                talloc_free(tmp_ctx);
 
708
                return ret;
 
709
        }
 
710
 
 
711
        /*
 
712
         * update the values
 
713
         */
 
714
        msg = ldb_msg_new(tmp_ctx);
 
715
        if (msg == NULL) {
 
716
                return ldb_module_oom(module);
 
717
        }
 
718
        msg->dn = rid_set_dn;
 
719
 
 
720
        ret = ridalloc_set_ridset_values(module, msg,
 
721
                                         &oridset, &nridset);
 
722
        if (ret != LDB_SUCCESS) {
 
723
                talloc_free(tmp_ctx);
 
724
                return ret;
 
725
        }
 
726
 
 
727
        ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
 
728
        if (ret != LDB_SUCCESS) {
 
729
                ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
 
730
                                       ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
 
731
                talloc_free(tmp_ctx);
 
732
                return ret;
 
733
        }
 
734
 
 
735
        talloc_free(tmp_ctx);
 
736
        return LDB_SUCCESS;
 
737
}