Line data Source code
1 : /*
2 : * idmap_autorid_tdb: This file contains common code used by
3 : * idmap_autorid and net idmap autorid utilities. The common
4 : * code provides functions for performing various operations
5 : * on autorid.tdb
6 : *
7 : * Copyright (C) Christian Ambach, 2010-2012
8 : * Copyright (C) Atul Kulkarni, 2013
9 : * Copyright (C) Michael Adam, 2012-2013
10 : *
11 : * This program is free software; you can redistribute it and/or modify
12 : * it under the terms of the GNU General Public License as published by
13 : * the Free Software Foundation; either version 3 of the License, or
14 : * (at your option) any later version.
15 : *
16 : * This program is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 : *
24 : */
25 :
26 : #include "idmap_autorid_tdb.h"
27 : #include "../libcli/security/dom_sid.h"
28 : #include "lib/util/string_wrappers.h"
29 :
30 : /**
31 : * Build the database keystring for getting a range
32 : * belonging to a domain sid and a range index.
33 : */
34 0 : static void idmap_autorid_build_keystr(const char *domsid,
35 : uint32_t domain_range_index,
36 : fstring keystr)
37 : {
38 0 : if (domain_range_index > 0) {
39 0 : fstr_sprintf(keystr, "%s#%"PRIu32,
40 : domsid, domain_range_index);
41 : } else {
42 0 : fstrcpy(keystr, domsid);
43 : }
44 0 : }
45 :
46 0 : static char *idmap_autorid_build_keystr_talloc(TALLOC_CTX *mem_ctx,
47 : const char *domsid,
48 : uint32_t domain_range_index)
49 : {
50 : char *keystr;
51 :
52 0 : if (domain_range_index > 0) {
53 0 : keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
54 : domain_range_index);
55 : } else {
56 0 : keystr = talloc_strdup(mem_ctx, domsid);
57 : }
58 :
59 0 : return keystr;
60 : }
61 :
62 :
63 0 : static bool idmap_autorid_validate_sid(const char *sid)
64 : {
65 : struct dom_sid ignore;
66 0 : if (sid == NULL) {
67 0 : return false;
68 : }
69 :
70 0 : if (strcmp(sid, ALLOC_RANGE) == 0) {
71 0 : return true;
72 : }
73 :
74 0 : return dom_sid_parse(sid, &ignore);
75 : }
76 :
77 : struct idmap_autorid_addrange_ctx {
78 : struct autorid_range_config *range;
79 : bool acquire;
80 : };
81 :
82 0 : static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
83 : void *private_data)
84 : {
85 : struct idmap_autorid_addrange_ctx *ctx;
86 : uint32_t requested_rangenum, stored_rangenum;
87 : struct autorid_range_config *range;
88 : bool acquire;
89 : NTSTATUS ret;
90 : uint32_t hwm;
91 : char *numstr;
92 0 : struct autorid_global_config globalcfg = {0};
93 : fstring keystr;
94 : uint32_t increment;
95 0 : TALLOC_CTX *mem_ctx = NULL;
96 :
97 0 : ctx = (struct idmap_autorid_addrange_ctx *)private_data;
98 0 : range = ctx->range;
99 0 : acquire = ctx->acquire;
100 0 : requested_rangenum = range->rangenum;
101 :
102 0 : if (db == NULL) {
103 0 : DEBUG(3, ("Invalid database argument: NULL"));
104 0 : return NT_STATUS_INVALID_PARAMETER;
105 : }
106 :
107 0 : if (range == NULL) {
108 0 : DEBUG(3, ("Invalid range argument: NULL"));
109 0 : return NT_STATUS_INVALID_PARAMETER;
110 : }
111 :
112 0 : DEBUG(10, ("Adding new range for domain %s "
113 : "(domain_range_index=%"PRIu32")\n",
114 : range->domsid, range->domain_range_index));
115 :
116 0 : if (!idmap_autorid_validate_sid(range->domsid)) {
117 0 : DEBUG(3, ("Invalid SID: %s\n", range->domsid));
118 0 : return NT_STATUS_INVALID_PARAMETER;
119 : }
120 :
121 0 : idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
122 : keystr);
123 :
124 0 : ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
125 :
126 0 : if (NT_STATUS_IS_OK(ret)) {
127 : /* entry is already present*/
128 0 : if (acquire) {
129 0 : DEBUG(10, ("domain range already allocated - "
130 : "Not adding!\n"));
131 :
132 0 : ret = idmap_autorid_loadconfig(db, &globalcfg);
133 0 : if (!NT_STATUS_IS_OK(ret)) {
134 0 : DEBUG(1, ("Fatal error while fetching "
135 : "configuration: %s\n",
136 : nt_errstr(ret)));
137 0 : goto error;
138 : }
139 :
140 0 : range->rangenum = stored_rangenum;
141 0 : range->low_id = globalcfg.minvalue
142 0 : + range->rangenum * globalcfg.rangesize;
143 0 : range->high_id =
144 0 : range->low_id + globalcfg.rangesize - 1;
145 :
146 0 : return NT_STATUS_OK;
147 : }
148 :
149 0 : if (stored_rangenum != requested_rangenum) {
150 0 : DEBUG(1, ("Error: requested rangenumber (%u) differs "
151 : "from stored one (%u).\n",
152 : requested_rangenum, stored_rangenum));
153 0 : return NT_STATUS_UNSUCCESSFUL;
154 : }
155 :
156 0 : DEBUG(10, ("Note: stored range agrees with requested "
157 : "one - ok\n"));
158 0 : return NT_STATUS_OK;
159 : }
160 :
161 : /* fetch the current HWM */
162 0 : ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
163 0 : if (!NT_STATUS_IS_OK(ret)) {
164 0 : DEBUG(1, ("Fatal error while fetching current "
165 : "HWM value: %s\n", nt_errstr(ret)));
166 0 : return NT_STATUS_INTERNAL_ERROR;
167 : }
168 :
169 0 : mem_ctx = talloc_stackframe();
170 :
171 0 : ret = idmap_autorid_loadconfig(db, &globalcfg);
172 0 : if (!NT_STATUS_IS_OK(ret)) {
173 0 : DEBUG(1, ("Fatal error while fetching configuration: %s\n",
174 : nt_errstr(ret)));
175 0 : goto error;
176 : }
177 :
178 0 : if (acquire) {
179 : /*
180 : * automatically acquire the next range
181 : */
182 0 : requested_rangenum = hwm;
183 : }
184 :
185 0 : if (requested_rangenum >= globalcfg.maxranges) {
186 0 : DEBUG(1, ("Not enough ranges available: New range %u must be "
187 : "smaller than configured maximum number of ranges "
188 : "(%u).\n",
189 : requested_rangenum, globalcfg.maxranges));
190 0 : ret = NT_STATUS_NO_MEMORY;
191 0 : goto error;
192 : }
193 :
194 : /*
195 : * Check that it is not yet taken.
196 : * If the range is requested and < HWM, we need
197 : * to check anyways, and otherwise, we also better
198 : * check in order to prevent further corruption
199 : * in case the db has been externally modified.
200 : */
201 :
202 0 : numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
203 0 : if (!numstr) {
204 0 : DEBUG(1, ("Talloc failed!\n"));
205 0 : ret = NT_STATUS_NO_MEMORY;
206 0 : goto error;
207 : }
208 :
209 0 : if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
210 0 : DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
211 :
212 0 : if (requested_rangenum < hwm) {
213 0 : ret = NT_STATUS_INVALID_PARAMETER;
214 : } else {
215 0 : ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
216 : }
217 :
218 0 : goto error;
219 : }
220 :
221 0 : if (requested_rangenum >= hwm) {
222 : /*
223 : * requested or automatic range >= HWM:
224 : * increment the HWM.
225 : */
226 :
227 : /* HWM always contains current max range + 1 */
228 0 : increment = requested_rangenum + 1 - hwm;
229 :
230 : /* increase the HWM */
231 0 : ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
232 : increment);
233 0 : if (!NT_STATUS_IS_OK(ret)) {
234 0 : DEBUG(1, ("Fatal error while incrementing the HWM "
235 : "value in the database: %s\n",
236 : nt_errstr(ret)));
237 0 : goto error;
238 : }
239 : }
240 :
241 : /*
242 : * store away the new mapping in both directions
243 : */
244 :
245 0 : ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
246 0 : if (!NT_STATUS_IS_OK(ret)) {
247 0 : DEBUG(1, ("Fatal error while storing new "
248 : "domain->range assignment: %s\n", nt_errstr(ret)));
249 0 : goto error;
250 : }
251 :
252 0 : numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
253 0 : if (!numstr) {
254 0 : ret = NT_STATUS_NO_MEMORY;
255 0 : goto error;
256 : }
257 :
258 0 : ret = dbwrap_store_bystring(db, numstr,
259 : string_term_tdb_data(keystr), TDB_INSERT);
260 :
261 0 : if (!NT_STATUS_IS_OK(ret)) {
262 0 : DEBUG(1, ("Fatal error while storing new "
263 : "domain->range assignment: %s\n", nt_errstr(ret)));
264 0 : goto error;
265 : }
266 :
267 0 : DEBUG(5, ("%s new range #%d for domain %s "
268 : "(domain_range_index=%"PRIu32")\n",
269 : (acquire?"Acquired":"Stored"),
270 : requested_rangenum, keystr,
271 : range->domain_range_index));
272 :
273 0 : range->rangenum = requested_rangenum;
274 :
275 0 : range->low_id = globalcfg.minvalue
276 0 : + range->rangenum * globalcfg.rangesize;
277 0 : range->high_id = range->low_id + globalcfg.rangesize - 1;
278 :
279 0 : ret = NT_STATUS_OK;
280 :
281 0 : error:
282 0 : talloc_free(mem_ctx);
283 0 : return ret;
284 : }
285 :
286 0 : static NTSTATUS idmap_autorid_addrange(struct db_context *db,
287 : struct autorid_range_config *range,
288 : bool acquire)
289 : {
290 : NTSTATUS status;
291 : struct idmap_autorid_addrange_ctx ctx;
292 :
293 0 : ctx.acquire = acquire;
294 0 : ctx.range = range;
295 :
296 0 : status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
297 0 : return status;
298 : }
299 :
300 0 : NTSTATUS idmap_autorid_setrange(struct db_context *db,
301 : const char *domsid,
302 : uint32_t domain_range_index,
303 : uint32_t rangenum)
304 : {
305 : NTSTATUS status;
306 : struct autorid_range_config range;
307 :
308 0 : ZERO_STRUCT(range);
309 0 : fstrcpy(range.domsid, domsid);
310 0 : range.domain_range_index = domain_range_index;
311 0 : range.rangenum = rangenum;
312 :
313 0 : status = idmap_autorid_addrange(db, &range, false);
314 0 : return status;
315 : }
316 :
317 0 : NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
318 : struct autorid_range_config *range)
319 : {
320 0 : return idmap_autorid_addrange(db, range, true);
321 : }
322 :
323 0 : static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
324 : struct autorid_range_config *range)
325 : {
326 0 : NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
327 0 : struct autorid_global_config globalcfg = {0};
328 : fstring keystr;
329 :
330 0 : if (db == NULL || range == NULL) {
331 0 : DEBUG(3, ("Invalid arguments received\n"));
332 0 : goto done;
333 : }
334 :
335 0 : if (!idmap_autorid_validate_sid(range->domsid)) {
336 0 : DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
337 0 : status = NT_STATUS_INVALID_PARAMETER;
338 0 : goto done;
339 : }
340 :
341 0 : idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
342 : keystr);
343 :
344 0 : DEBUG(10, ("reading domain range for key %s\n", keystr));
345 0 : status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
346 0 : if (!NT_STATUS_IS_OK(status)) {
347 0 : DEBUG(1, ("Failed to read database record for key '%s': %s\n",
348 : keystr, nt_errstr(status)));
349 0 : goto done;
350 : }
351 :
352 0 : status = idmap_autorid_loadconfig(db, &globalcfg);
353 0 : if (!NT_STATUS_IS_OK(status)) {
354 0 : DEBUG(1, ("Failed to read global configuration"));
355 0 : goto done;
356 : }
357 0 : range->low_id = globalcfg.minvalue
358 0 : + range->rangenum * globalcfg.rangesize;
359 0 : range->high_id = range->low_id + globalcfg.rangesize - 1;
360 0 : done:
361 0 : return status;
362 : }
363 :
364 0 : NTSTATUS idmap_autorid_getrange(struct db_context *db,
365 : const char *domsid,
366 : uint32_t domain_range_index,
367 : uint32_t *rangenum,
368 : uint32_t *low_id)
369 : {
370 : NTSTATUS status;
371 : struct autorid_range_config range;
372 :
373 0 : if (rangenum == NULL) {
374 0 : return NT_STATUS_INVALID_PARAMETER;
375 : }
376 :
377 0 : ZERO_STRUCT(range);
378 0 : fstrcpy(range.domsid, domsid);
379 0 : range.domain_range_index = domain_range_index;
380 :
381 0 : status = idmap_autorid_getrange_int(db, &range);
382 0 : if (!NT_STATUS_IS_OK(status)) {
383 0 : return status;
384 : }
385 :
386 0 : *rangenum = range.rangenum;
387 :
388 0 : if (low_id != NULL) {
389 0 : *low_id = range.low_id;
390 : }
391 :
392 0 : return NT_STATUS_OK;
393 : }
394 :
395 0 : NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
396 : struct autorid_range_config *range,
397 : bool read_only)
398 : {
399 : NTSTATUS ret;
400 :
401 0 : ret = idmap_autorid_getrange_int(db, range);
402 0 : if (!NT_STATUS_IS_OK(ret)) {
403 0 : DEBUG(10, ("Failed to read range config for '%s': %s\n",
404 : range->domsid, nt_errstr(ret)));
405 0 : if (read_only) {
406 0 : DEBUG(10, ("Not allocating new range for '%s' because "
407 : "read-only is enabled.\n", range->domsid));
408 0 : return NT_STATUS_NOT_FOUND;
409 : }
410 :
411 0 : ret = idmap_autorid_acquire_range(db, range);
412 : }
413 :
414 0 : DEBUG(10, ("Using range #%d for domain %s "
415 : "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
416 : range->rangenum, range->domsid, range->domain_range_index,
417 : range->low_id));
418 :
419 0 : return ret;
420 : }
421 :
422 : /* initialize the given HWM to 0 if it does not exist yet */
423 0 : static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
424 : void *private_data)
425 : {
426 : NTSTATUS status;
427 : uint32_t hwmval;
428 : const char *hwm;
429 :
430 0 : hwm = (char *)private_data;
431 :
432 0 : status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
433 0 : if (NT_STATUS_IS_OK(status)) {
434 0 : DEBUG(1, ("HWM (%s) already initialized in autorid database "
435 : "(value %"PRIu32").\n", hwm, hwmval));
436 0 : return NT_STATUS_OK;
437 : }
438 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
439 0 : DEBUG(0, ("Error fetching HWM (%s) from autorid "
440 : "database: %s\n", hwm, nt_errstr(status)));
441 0 : return status;
442 : }
443 :
444 0 : status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
445 0 : if (!NT_STATUS_IS_OK(status)) {
446 0 : DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
447 : hwm, nt_errstr(status)));
448 0 : return status;
449 : }
450 :
451 0 : return NT_STATUS_OK;
452 : }
453 :
454 0 : NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
455 : {
456 : NTSTATUS status;
457 : uint32_t hwmval;
458 :
459 0 : status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
460 0 : if (NT_STATUS_IS_OK(status)) {
461 0 : DEBUG(1, ("HWM (%s) already initialized in autorid database "
462 : "(value %"PRIu32").\n", hwm, hwmval));
463 0 : return NT_STATUS_OK;
464 : }
465 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
466 0 : DEBUG(0, ("unable to fetch HWM (%s) from autorid "
467 : "database: %s\n", hwm, nt_errstr(status)));
468 0 : return status;
469 : }
470 :
471 0 : status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
472 : discard_const(hwm));
473 0 : if (!NT_STATUS_IS_OK(status)) {
474 0 : DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
475 : "%s\n", hwm, nt_errstr(status)));
476 0 : return NT_STATUS_INTERNAL_DB_ERROR;
477 : }
478 :
479 0 : DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
480 :
481 0 : return NT_STATUS_OK;
482 : }
483 :
484 : /*
485 : * Delete a domain#index <-> range mapping from the database.
486 : * The mapping is specified by the sid and index.
487 : * If force == true, invalid mapping records are deleted as far
488 : * as possible, otherwise they are left untouched.
489 : */
490 :
491 : struct idmap_autorid_delete_range_by_sid_ctx {
492 : const char *domsid;
493 : uint32_t domain_range_index;
494 : bool force;
495 : };
496 :
497 0 : static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
498 : void *private_data)
499 : {
500 0 : struct idmap_autorid_delete_range_by_sid_ctx *ctx =
501 : (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
502 : const char *domsid;
503 : uint32_t domain_range_index;
504 : uint32_t rangenum;
505 : char *keystr;
506 : char *range_keystr;
507 : TDB_DATA data;
508 : NTSTATUS status;
509 0 : TALLOC_CTX *frame = talloc_stackframe();
510 0 : bool is_valid_range_mapping = true;
511 : bool force;
512 :
513 0 : domsid = ctx->domsid;
514 0 : domain_range_index = ctx->domain_range_index;
515 0 : force = ctx->force;
516 :
517 0 : keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
518 : domain_range_index);
519 0 : if (keystr == NULL) {
520 0 : status = NT_STATUS_NO_MEMORY;
521 0 : goto done;
522 : }
523 :
524 0 : status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
525 0 : if (!NT_STATUS_IS_OK(status)) {
526 0 : goto done;
527 : }
528 :
529 0 : range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
530 0 : if (range_keystr == NULL) {
531 0 : status = NT_STATUS_NO_MEMORY;
532 0 : goto done;
533 : }
534 :
535 0 : status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
536 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
537 0 : DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
538 : keystr, range_keystr));
539 0 : is_valid_range_mapping = false;
540 0 : } else if (!NT_STATUS_IS_OK(status)) {
541 0 : DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
542 : keystr, range_keystr, nt_errstr(status)));
543 0 : goto done;
544 0 : } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
545 : != 0)
546 : {
547 0 : DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
548 : keystr, range_keystr, (const char *)data.dptr));
549 0 : is_valid_range_mapping = false;
550 : }
551 :
552 0 : if (!is_valid_range_mapping && !force) {
553 0 : DEBUG(10, ("Not deleting invalid mapping, since not in force "
554 : "mode.\n"));
555 0 : status = NT_STATUS_FILE_INVALID;
556 0 : goto done;
557 : }
558 :
559 0 : status = dbwrap_delete_bystring(db, keystr);
560 0 : if (!NT_STATUS_IS_OK(status)) {
561 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
562 : keystr, nt_errstr(status)));
563 0 : goto done;
564 : }
565 :
566 0 : if (!is_valid_range_mapping) {
567 0 : goto done;
568 : }
569 :
570 0 : status = dbwrap_delete_bystring(db, range_keystr);
571 0 : if (!NT_STATUS_IS_OK(status)) {
572 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
573 : range_keystr, nt_errstr(status)));
574 0 : goto done;
575 : }
576 :
577 0 : DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
578 : range_keystr));
579 :
580 0 : done:
581 0 : TALLOC_FREE(frame);
582 0 : return status;
583 : }
584 :
585 0 : NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
586 : const char *domsid,
587 : uint32_t domain_range_index,
588 : bool force)
589 : {
590 : NTSTATUS status;
591 : struct idmap_autorid_delete_range_by_sid_ctx ctx;
592 :
593 0 : ctx.domain_range_index = domain_range_index;
594 0 : ctx.domsid = domsid;
595 0 : ctx.force = force;
596 :
597 0 : status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
598 : &ctx);
599 0 : return status;
600 : }
601 :
602 : /*
603 : * Delete a domain#index <-> range mapping from the database.
604 : * The mapping is specified by the range number.
605 : * If force == true, invalid mapping records are deleted as far
606 : * as possible, otherwise they are left untouched.
607 : */
608 : struct idmap_autorid_delete_range_by_num_ctx {
609 : uint32_t rangenum;
610 : bool force;
611 : };
612 :
613 0 : static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
614 : void *private_data)
615 : {
616 0 : struct idmap_autorid_delete_range_by_num_ctx *ctx =
617 : (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
618 : uint32_t rangenum;
619 0 : char *keystr = NULL;
620 : char *range_keystr;
621 : TDB_DATA val;
622 : NTSTATUS status;
623 0 : TALLOC_CTX *frame = talloc_stackframe();
624 0 : bool is_valid_range_mapping = true;
625 : bool force;
626 :
627 0 : rangenum = ctx->rangenum;
628 0 : force = ctx->force;
629 :
630 0 : range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
631 0 : if (range_keystr == NULL) {
632 0 : status = NT_STATUS_NO_MEMORY;
633 0 : goto done;
634 : }
635 :
636 0 : ZERO_STRUCT(val);
637 :
638 0 : status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
639 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
640 0 : DEBUG(10, ("Did not find range '%s' in database.\n",
641 : range_keystr));
642 0 : goto done;
643 0 : } else if (!NT_STATUS_IS_OK(status)) {
644 0 : DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
645 0 : goto done;
646 : }
647 :
648 0 : if (val.dptr == NULL) {
649 0 : DEBUG(1, ("Invalid mapping: %s -> empty value\n",
650 : range_keystr));
651 0 : is_valid_range_mapping = false;
652 : } else {
653 0 : uint32_t reverse_rangenum = 0;
654 :
655 0 : keystr = (char *)val.dptr;
656 :
657 0 : status = dbwrap_fetch_uint32_bystring(db, keystr,
658 : &reverse_rangenum);
659 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
660 0 : DEBUG(1, ("Incomplete mapping %s -> %s: "
661 : "no backward mapping\n",
662 : range_keystr, keystr));
663 0 : is_valid_range_mapping = false;
664 0 : } else if (!NT_STATUS_IS_OK(status)) {
665 0 : DEBUG(1, ("Error fetching reverse mapping for "
666 : "%s -> %s: %s\n",
667 : range_keystr, keystr, nt_errstr(status)));
668 0 : goto done;
669 0 : } else if (rangenum != reverse_rangenum) {
670 0 : is_valid_range_mapping = false;
671 : }
672 : }
673 :
674 0 : if (!is_valid_range_mapping && !force) {
675 0 : DEBUG(10, ("Not deleting invalid mapping, since not in force "
676 : "mode.\n"));
677 0 : status = NT_STATUS_FILE_INVALID;
678 0 : goto done;
679 : }
680 :
681 0 : status = dbwrap_delete_bystring(db, range_keystr);
682 0 : if (!NT_STATUS_IS_OK(status)) {
683 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
684 : range_keystr, nt_errstr(status)));
685 0 : goto done;
686 : }
687 :
688 0 : if (!is_valid_range_mapping) {
689 0 : goto done;
690 : }
691 :
692 0 : status = dbwrap_delete_bystring(db, keystr);
693 0 : if (!NT_STATUS_IS_OK(status)) {
694 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
695 : keystr, nt_errstr(status)));
696 0 : goto done;
697 : }
698 :
699 0 : DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
700 : keystr));
701 :
702 0 : done:
703 0 : talloc_free(frame);
704 0 : return status;
705 : }
706 :
707 0 : NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
708 : uint32_t rangenum,
709 : bool force)
710 : {
711 : NTSTATUS status;
712 : struct idmap_autorid_delete_range_by_num_ctx ctx;
713 :
714 0 : ctx.rangenum = rangenum;
715 0 : ctx.force = force;
716 :
717 0 : status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
718 : &ctx);
719 0 : return status;
720 : }
721 :
722 : /**
723 : * Open and possibly create the database.
724 : */
725 0 : NTSTATUS idmap_autorid_db_open(const char *path,
726 : TALLOC_CTX *mem_ctx,
727 : struct db_context **db)
728 : {
729 0 : if (*db != NULL) {
730 : /* its already open */
731 0 : return NT_STATUS_OK;
732 : }
733 :
734 : /* Open idmap repository */
735 0 : *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
736 : DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
737 :
738 0 : if (*db == NULL) {
739 0 : DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
740 0 : return NT_STATUS_UNSUCCESSFUL;
741 : }
742 :
743 0 : return NT_STATUS_OK;
744 : }
745 :
746 : /**
747 : * Initialize the high watermark records in the database.
748 : */
749 0 : NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
750 : {
751 : NTSTATUS status;
752 :
753 0 : status = idmap_autorid_init_hwm(db, HWM);
754 0 : if (!NT_STATUS_IS_OK(status)) {
755 0 : return status;
756 : }
757 :
758 0 : status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
759 0 : if (!NT_STATUS_IS_OK(status)) {
760 0 : return status;
761 : }
762 :
763 0 : status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
764 :
765 0 : return status;
766 : }
767 :
768 0 : NTSTATUS idmap_autorid_db_init(const char *path,
769 : TALLOC_CTX *mem_ctx,
770 : struct db_context **db)
771 : {
772 : NTSTATUS status;
773 :
774 0 : status = idmap_autorid_db_open(path, mem_ctx, db);
775 0 : if (!NT_STATUS_IS_OK(status)) {
776 0 : return status;
777 : }
778 :
779 0 : status = idmap_autorid_init_hwms(*db);
780 0 : return status;
781 : }
782 :
783 :
784 :
785 : struct idmap_autorid_fetch_config_state {
786 : TALLOC_CTX *mem_ctx;
787 : char *configstr;
788 : };
789 :
790 0 : static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
791 : void *private_data)
792 : {
793 : struct idmap_autorid_fetch_config_state *state;
794 :
795 0 : state = (struct idmap_autorid_fetch_config_state *)private_data;
796 :
797 : /*
798 : * strndup because we have non-nullterminated strings in the db
799 : */
800 0 : state->configstr = talloc_strndup(
801 0 : state->mem_ctx, (const char *)value.dptr, value.dsize);
802 0 : }
803 :
804 0 : NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
805 : char **result)
806 : {
807 : TDB_DATA key;
808 : NTSTATUS status;
809 : struct idmap_autorid_fetch_config_state state;
810 :
811 0 : if (result == NULL) {
812 0 : return NT_STATUS_INVALID_PARAMETER;
813 : }
814 :
815 0 : key = string_term_tdb_data(CONFIGKEY);
816 :
817 0 : state.mem_ctx = mem_ctx;
818 0 : state.configstr = NULL;
819 :
820 0 : status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
821 : &state);
822 0 : if (!NT_STATUS_IS_OK(status)) {
823 0 : DEBUG(1, ("Error while retrieving config: %s\n",
824 : nt_errstr(status)));
825 0 : return status;
826 : }
827 :
828 0 : if (state.configstr == NULL) {
829 0 : DEBUG(1, ("Error while retrieving config\n"));
830 0 : return NT_STATUS_NO_MEMORY;
831 : }
832 :
833 0 : DEBUG(5, ("found CONFIG: %s\n", state.configstr));
834 :
835 0 : *result = state.configstr;
836 0 : return NT_STATUS_OK;
837 : }
838 :
839 0 : bool idmap_autorid_parse_configstr(const char *configstr,
840 : struct autorid_global_config *cfg)
841 : {
842 : unsigned long minvalue, rangesize, maxranges;
843 :
844 0 : if (sscanf(configstr,
845 : "minvalue:%lu rangesize:%lu maxranges:%lu",
846 : &minvalue, &rangesize, &maxranges) != 3) {
847 0 : DEBUG(1,
848 : ("Found invalid configuration data. "
849 : "Creating new config\n"));
850 0 : return false;
851 : }
852 :
853 0 : cfg->minvalue = minvalue;
854 0 : cfg->rangesize = rangesize;
855 0 : cfg->maxranges = maxranges;
856 :
857 0 : return true;
858 : }
859 :
860 0 : NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
861 : struct autorid_global_config *result)
862 : {
863 0 : struct autorid_global_config cfg = {0};
864 : NTSTATUS status;
865 : bool ok;
866 0 : char *configstr = NULL;
867 :
868 0 : if (result == NULL) {
869 0 : return NT_STATUS_INVALID_PARAMETER;
870 : }
871 :
872 0 : status = idmap_autorid_getconfigstr(db, db, &configstr);
873 0 : if (!NT_STATUS_IS_OK(status)) {
874 0 : return status;
875 : }
876 :
877 0 : ok = idmap_autorid_parse_configstr(configstr, &cfg);
878 0 : TALLOC_FREE(configstr);
879 0 : if (!ok) {
880 0 : return NT_STATUS_INVALID_PARAMETER;
881 : }
882 :
883 0 : DEBUG(10, ("Loaded previously stored configuration "
884 : "minvalue:%d rangesize:%d\n",
885 : cfg.minvalue, cfg.rangesize));
886 :
887 0 : *result = cfg;
888 :
889 0 : return NT_STATUS_OK;
890 : }
891 :
892 0 : NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
893 : struct autorid_global_config *cfg)
894 : {
895 :
896 0 : struct autorid_global_config storedconfig = {0};
897 0 : NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
898 : TDB_DATA data;
899 : char *cfgstr;
900 : uint32_t hwm;
901 0 : TALLOC_CTX *frame = talloc_stackframe();
902 :
903 0 : DEBUG(10, ("New configuration provided for storing is "
904 : "minvalue:%d rangesize:%d maxranges:%d\n",
905 : cfg->minvalue, cfg->rangesize, cfg->maxranges));
906 :
907 0 : if (cfg->rangesize < 2000) {
908 0 : DEBUG(1, ("autorid rangesize must be at least 2000\n"));
909 0 : goto done;
910 : }
911 :
912 0 : if (cfg->maxranges == 0) {
913 0 : DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
914 : "Must have at least one range available.\n"));
915 0 : goto done;
916 : }
917 :
918 0 : status = idmap_autorid_loadconfig(db, &storedconfig);
919 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
920 0 : DEBUG(5, ("No configuration found. Storing initial "
921 : "configuration.\n"));
922 0 : storedconfig = *cfg;
923 0 : } else if (!NT_STATUS_IS_OK(status)) {
924 0 : DEBUG(1, ("Error loading configuration: %s\n",
925 : nt_errstr(status)));
926 0 : goto done;
927 : }
928 :
929 : /* did the minimum value or rangesize change? */
930 0 : if ((storedconfig.minvalue != cfg->minvalue) ||
931 0 : (storedconfig.rangesize != cfg->rangesize))
932 : {
933 0 : DEBUG(1, ("New configuration values for rangesize or "
934 : "minimum uid value conflict with previously "
935 : "used values! Not storing new config.\n"));
936 0 : status = NT_STATUS_INVALID_PARAMETER;
937 0 : goto done;
938 : }
939 :
940 0 : status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
941 0 : if (!NT_STATUS_IS_OK(status)) {
942 0 : DEBUG(1, ("Fatal error while fetching current "
943 : "HWM value: %s\n", nt_errstr(status)));
944 0 : status = NT_STATUS_INTERNAL_ERROR;
945 0 : goto done;
946 : }
947 :
948 : /*
949 : * has the highest uid value been reduced to setting that is not
950 : * sufficient any more for already existing ranges?
951 : */
952 0 : if (hwm > cfg->maxranges) {
953 0 : DEBUG(1, ("New upper uid limit is too low to cover "
954 : "existing mappings! Not storing new config.\n"));
955 0 : status = NT_STATUS_INVALID_PARAMETER;
956 0 : goto done;
957 : }
958 :
959 0 : cfgstr =
960 0 : talloc_asprintf(frame,
961 : "minvalue:%u rangesize:%u maxranges:%u",
962 : cfg->minvalue, cfg->rangesize, cfg->maxranges);
963 :
964 0 : if (cfgstr == NULL) {
965 0 : status = NT_STATUS_NO_MEMORY;
966 0 : goto done;
967 : }
968 :
969 0 : data = string_tdb_data(cfgstr);
970 :
971 0 : status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
972 :
973 0 : done:
974 0 : TALLOC_FREE(frame);
975 0 : return status;
976 : }
977 :
978 0 : NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
979 : const char *configstr)
980 : {
981 : bool ok;
982 : NTSTATUS status;
983 : struct autorid_global_config cfg;
984 :
985 0 : ok = idmap_autorid_parse_configstr(configstr, &cfg);
986 0 : if (!ok) {
987 0 : return NT_STATUS_INVALID_PARAMETER;
988 : }
989 :
990 0 : status = idmap_autorid_saveconfig(db, &cfg);
991 0 : return status;
992 : }
993 :
994 :
995 : /*
996 : * iteration: Work on all range mappings for a given domain
997 : */
998 :
999 : struct domain_range_visitor_ctx {
1000 : const char *domsid;
1001 : NTSTATUS (*fn)(struct db_context *db,
1002 : const char *domsid,
1003 : uint32_t index,
1004 : uint32_t rangenum,
1005 : void *private_data);
1006 : void *private_data;
1007 : int count; /* number of records worked on */
1008 : };
1009 :
1010 0 : static int idmap_autorid_visit_domain_range(struct db_record *rec,
1011 : void *private_data)
1012 : {
1013 : struct domain_range_visitor_ctx *vi;
1014 : char *domsid;
1015 : char *sep;
1016 0 : uint32_t range_index = 0;
1017 0 : uint32_t rangenum = 0;
1018 : TDB_DATA key, value;
1019 : NTSTATUS status;
1020 0 : int ret = 0;
1021 : struct db_context *db;
1022 :
1023 0 : vi = talloc_get_type_abort(private_data,
1024 : struct domain_range_visitor_ctx);
1025 :
1026 0 : key = dbwrap_record_get_key(rec);
1027 :
1028 : /*
1029 : * split string "<sid>[#<index>]" into sid string and index number
1030 : */
1031 :
1032 0 : domsid = (char *)key.dptr;
1033 :
1034 0 : DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1035 : domsid));
1036 :
1037 0 : sep = strrchr(domsid, '#');
1038 0 : if (sep != NULL) {
1039 : char *index_str;
1040 0 : *sep = '\0';
1041 0 : index_str = sep+1;
1042 0 : if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1043 0 : DEBUG(10, ("Found separator '#' but '%s' is not a "
1044 : "valid range index. Skipping record\n",
1045 : index_str));
1046 0 : goto done;
1047 : }
1048 : }
1049 :
1050 0 : if (!idmap_autorid_validate_sid(domsid)) {
1051 0 : DEBUG(10, ("String '%s' is not a valid sid. "
1052 : "Skipping record.\n", domsid));
1053 0 : goto done;
1054 : }
1055 :
1056 0 : if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1057 0 : DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1058 : domsid, vi->domsid));
1059 0 : goto done;
1060 : }
1061 :
1062 0 : value = dbwrap_record_get_value(rec);
1063 :
1064 0 : if (value.dsize != sizeof(uint32_t)) {
1065 : /* it might be a mapping of a well known sid */
1066 0 : DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1067 : "skipping.\n", (unsigned)value.dsize, vi->domsid));
1068 0 : goto done;
1069 : }
1070 :
1071 0 : rangenum = IVAL(value.dptr, 0);
1072 :
1073 0 : db = dbwrap_record_get_db(rec);
1074 :
1075 0 : status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1076 0 : if (!NT_STATUS_IS_OK(status)) {
1077 0 : ret = -1;
1078 0 : goto done;
1079 : }
1080 :
1081 0 : vi->count++;
1082 0 : ret = 0;
1083 :
1084 0 : done:
1085 0 : return ret;
1086 : }
1087 :
1088 0 : static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1089 : const char *domsid,
1090 : NTSTATUS (*fn)(struct db_context *db,
1091 : const char *domsid,
1092 : uint32_t index,
1093 : uint32_t rangnum,
1094 : void *private_data),
1095 : void *private_data,
1096 : int *count,
1097 : NTSTATUS (*traverse)(struct db_context *db,
1098 : int (*f)(struct db_record *, void *),
1099 : void *private_data,
1100 : int *count))
1101 : {
1102 : NTSTATUS status;
1103 : struct domain_range_visitor_ctx *vi;
1104 0 : TALLOC_CTX *frame = talloc_stackframe();
1105 :
1106 0 : if (domsid == NULL) {
1107 0 : DEBUG(10, ("No sid provided, operating on all ranges\n"));
1108 : }
1109 :
1110 0 : if (fn == NULL) {
1111 0 : DEBUG(1, ("Error: missing visitor callback\n"));
1112 0 : status = NT_STATUS_INVALID_PARAMETER;
1113 0 : goto done;
1114 : }
1115 :
1116 0 : vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1117 0 : if (vi == NULL) {
1118 0 : status = NT_STATUS_NO_MEMORY;
1119 0 : goto done;
1120 : }
1121 :
1122 0 : vi->domsid = domsid;
1123 0 : vi->fn = fn;
1124 0 : vi->private_data = private_data;
1125 :
1126 0 : status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1127 0 : if (!NT_STATUS_IS_OK(status)) {
1128 0 : goto done;
1129 : }
1130 :
1131 0 : if (count != NULL) {
1132 0 : *count = vi->count;
1133 : }
1134 :
1135 0 : done:
1136 0 : talloc_free(frame);
1137 0 : return status;
1138 : }
1139 :
1140 0 : NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1141 : const char *domsid,
1142 : NTSTATUS (*fn)(struct db_context *db,
1143 : const char *domsid,
1144 : uint32_t index,
1145 : uint32_t rangenum,
1146 : void *private_data),
1147 : void *private_data,
1148 : int *count)
1149 : {
1150 : NTSTATUS status;
1151 :
1152 0 : status = idmap_autorid_iterate_domain_ranges_int(db,
1153 : domsid,
1154 : fn,
1155 : private_data,
1156 : count,
1157 : dbwrap_traverse);
1158 :
1159 0 : return status;
1160 : }
1161 :
1162 :
1163 0 : NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1164 : const char *domsid,
1165 : NTSTATUS (*fn)(struct db_context *db,
1166 : const char *domsid,
1167 : uint32_t index,
1168 : uint32_t rangenum,
1169 : void *count),
1170 : void *private_data,
1171 : int *count)
1172 : {
1173 : NTSTATUS status;
1174 :
1175 0 : status = idmap_autorid_iterate_domain_ranges_int(db,
1176 : domsid,
1177 : fn,
1178 : private_data,
1179 : count,
1180 : dbwrap_traverse_read);
1181 :
1182 0 : return status;
1183 : }
1184 :
1185 :
1186 : /*
1187 : * Delete all ranges configured for a given domain
1188 : */
1189 :
1190 : struct delete_domain_ranges_visitor_ctx {
1191 : bool force;
1192 : };
1193 :
1194 0 : static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1195 : struct db_context *db,
1196 : const char *domsid,
1197 : uint32_t domain_range_index,
1198 : uint32_t rangenum,
1199 : void *private_data)
1200 : {
1201 : struct delete_domain_ranges_visitor_ctx *ctx;
1202 : NTSTATUS status;
1203 :
1204 0 : ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1205 :
1206 0 : status = idmap_autorid_delete_range_by_sid(
1207 0 : db, domsid, domain_range_index, ctx->force);
1208 0 : return status;
1209 : }
1210 :
1211 : struct idmap_autorid_delete_domain_ranges_ctx {
1212 : const char *domsid;
1213 : bool force;
1214 : int count; /* output: count records operated on */
1215 : };
1216 :
1217 0 : static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1218 : void *private_data)
1219 : {
1220 : struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1221 : struct delete_domain_ranges_visitor_ctx visitor_ctx;
1222 : int count;
1223 : NTSTATUS status;
1224 :
1225 0 : ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1226 :
1227 0 : ZERO_STRUCT(visitor_ctx);
1228 0 : visitor_ctx.force = ctx->force;
1229 :
1230 0 : status = idmap_autorid_iterate_domain_ranges(db,
1231 : ctx->domsid,
1232 : idmap_autorid_delete_domain_ranges_visitor,
1233 : &visitor_ctx,
1234 : &count);
1235 0 : if (!NT_STATUS_IS_OK(status)) {
1236 0 : return status;
1237 : }
1238 :
1239 0 : ctx->count = count;
1240 :
1241 0 : return NT_STATUS_OK;
1242 : }
1243 :
1244 0 : NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1245 : const char *domsid,
1246 : bool force,
1247 : int *count)
1248 : {
1249 : NTSTATUS status;
1250 : struct idmap_autorid_delete_domain_ranges_ctx ctx;
1251 :
1252 0 : ZERO_STRUCT(ctx);
1253 0 : ctx.domsid = domsid;
1254 0 : ctx.force = force;
1255 :
1256 0 : status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1257 : &ctx);
1258 0 : if (!NT_STATUS_IS_OK(status)) {
1259 0 : return status;
1260 : }
1261 :
1262 0 : *count = ctx.count;
1263 :
1264 0 : return NT_STATUS_OK;
1265 : }
|