docs-xml: Fix rid idmap backend documentation
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blobfb195367da6bc2e06a6af54988c9cec2e23221a0
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
7 * Copyright (C) Christian Ambach, 2010-2012
8 * Copyright (C) Atul Kulkarni, 2013
9 * Copyright (C) Michael Adam, 2012-2013
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.
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.
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/>.
26 #include "idmap_autorid_tdb.h"
27 #include "../libcli/security/dom_sid.h"
28 #include "lib/util/string_wrappers.h"
30 /**
31 * Build the database keystring for getting a range
32 * belonging to a domain sid and a range index.
34 static void idmap_autorid_build_keystr(const char *domsid,
35 uint32_t domain_range_index,
36 fstring keystr)
38 if (domain_range_index > 0) {
39 fstr_sprintf(keystr, "%s#%"PRIu32,
40 domsid, domain_range_index);
41 } else {
42 fstrcpy(keystr, domsid);
46 static char *idmap_autorid_build_keystr_talloc(TALLOC_CTX *mem_ctx,
47 const char *domsid,
48 uint32_t domain_range_index)
50 char *keystr;
52 if (domain_range_index > 0) {
53 keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
54 domain_range_index);
55 } else {
56 keystr = talloc_strdup(mem_ctx, domsid);
59 return keystr;
63 static bool idmap_autorid_validate_sid(const char *sid)
65 struct dom_sid ignore;
66 if (sid == NULL) {
67 return false;
70 if (strcmp(sid, ALLOC_RANGE) == 0) {
71 return true;
74 return dom_sid_parse(sid, &ignore);
77 struct idmap_autorid_addrange_ctx {
78 struct autorid_range_config *range;
79 bool acquire;
82 static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
83 void *private_data)
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 struct autorid_global_config globalcfg = {0};
93 fstring keystr;
94 uint32_t increment;
95 TALLOC_CTX *mem_ctx = NULL;
97 ctx = (struct idmap_autorid_addrange_ctx *)private_data;
98 range = ctx->range;
99 acquire = ctx->acquire;
100 requested_rangenum = range->rangenum;
102 if (db == NULL) {
103 DEBUG(3, ("Invalid database argument: NULL"));
104 return NT_STATUS_INVALID_PARAMETER;
107 if (range == NULL) {
108 DEBUG(3, ("Invalid range argument: NULL"));
109 return NT_STATUS_INVALID_PARAMETER;
112 DEBUG(10, ("Adding new range for domain %s "
113 "(domain_range_index=%"PRIu32")\n",
114 range->domsid, range->domain_range_index));
116 if (!idmap_autorid_validate_sid(range->domsid)) {
117 DEBUG(3, ("Invalid SID: %s\n", range->domsid));
118 return NT_STATUS_INVALID_PARAMETER;
121 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
122 keystr);
124 ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
126 if (NT_STATUS_IS_OK(ret)) {
127 /* entry is already present*/
128 if (acquire) {
129 DEBUG(10, ("domain range already allocated - "
130 "Not adding!\n"));
132 ret = idmap_autorid_loadconfig(db, &globalcfg);
133 if (!NT_STATUS_IS_OK(ret)) {
134 DEBUG(1, ("Fatal error while fetching "
135 "configuration: %s\n",
136 nt_errstr(ret)));
137 goto error;
140 range->rangenum = stored_rangenum;
141 range->low_id = globalcfg.minvalue
142 + range->rangenum * globalcfg.rangesize;
143 range->high_id =
144 range->low_id + globalcfg.rangesize - 1;
146 return NT_STATUS_OK;
149 if (stored_rangenum != requested_rangenum) {
150 DEBUG(1, ("Error: requested rangenumber (%u) differs "
151 "from stored one (%u).\n",
152 requested_rangenum, stored_rangenum));
153 return NT_STATUS_UNSUCCESSFUL;
156 DEBUG(10, ("Note: stored range agrees with requested "
157 "one - ok\n"));
158 return NT_STATUS_OK;
161 /* fetch the current HWM */
162 ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
163 if (!NT_STATUS_IS_OK(ret)) {
164 DEBUG(1, ("Fatal error while fetching current "
165 "HWM value: %s\n", nt_errstr(ret)));
166 return NT_STATUS_INTERNAL_ERROR;
169 mem_ctx = talloc_stackframe();
171 ret = idmap_autorid_loadconfig(db, &globalcfg);
172 if (!NT_STATUS_IS_OK(ret)) {
173 DEBUG(1, ("Fatal error while fetching configuration: %s\n",
174 nt_errstr(ret)));
175 goto error;
178 if (acquire) {
180 * automatically acquire the next range
182 requested_rangenum = hwm;
185 if (requested_rangenum >= globalcfg.maxranges) {
186 DBG_WARNING("Not enough ranges available: New range %u can't "
187 "be allocated. Consider increasing the range "
188 "[%u-%u] by %u.\n",
189 requested_rangenum,
190 globalcfg.minvalue,
191 globalcfg.minvalue +
192 (globalcfg.maxranges * globalcfg.rangesize),
193 globalcfg.rangesize);
194 ret = NT_STATUS_NO_MEMORY;
195 goto error;
199 * Check that it is not yet taken.
200 * If the range is requested and < HWM, we need
201 * to check anyways, and otherwise, we also better
202 * check in order to prevent further corruption
203 * in case the db has been externally modified.
206 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
207 if (!numstr) {
208 DEBUG(1, ("Talloc failed!\n"));
209 ret = NT_STATUS_NO_MEMORY;
210 goto error;
213 if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
214 DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
216 if (requested_rangenum < hwm) {
217 ret = NT_STATUS_INVALID_PARAMETER;
218 } else {
219 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
222 goto error;
225 if (requested_rangenum >= hwm) {
227 * requested or automatic range >= HWM:
228 * increment the HWM.
231 /* HWM always contains current max range + 1 */
232 increment = requested_rangenum + 1 - hwm;
234 /* increase the HWM */
235 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
236 increment);
237 if (!NT_STATUS_IS_OK(ret)) {
238 DEBUG(1, ("Fatal error while incrementing the HWM "
239 "value in the database: %s\n",
240 nt_errstr(ret)));
241 goto error;
246 * store away the new mapping in both directions
249 ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
250 if (!NT_STATUS_IS_OK(ret)) {
251 DEBUG(1, ("Fatal error while storing new "
252 "domain->range assignment: %s\n", nt_errstr(ret)));
253 goto error;
256 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
257 if (!numstr) {
258 ret = NT_STATUS_NO_MEMORY;
259 goto error;
262 ret = dbwrap_store_bystring(db, numstr,
263 string_term_tdb_data(keystr), TDB_INSERT);
265 if (!NT_STATUS_IS_OK(ret)) {
266 DEBUG(1, ("Fatal error while storing new "
267 "domain->range assignment: %s\n", nt_errstr(ret)));
268 goto error;
271 DEBUG(5, ("%s new range #%d for domain %s "
272 "(domain_range_index=%"PRIu32")\n",
273 (acquire?"Acquired":"Stored"),
274 requested_rangenum, keystr,
275 range->domain_range_index));
277 range->rangenum = requested_rangenum;
279 range->low_id = globalcfg.minvalue
280 + range->rangenum * globalcfg.rangesize;
281 range->high_id = range->low_id + globalcfg.rangesize - 1;
283 ret = NT_STATUS_OK;
285 error:
286 talloc_free(mem_ctx);
287 return ret;
290 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
291 struct autorid_range_config *range,
292 bool acquire)
294 NTSTATUS status;
295 struct idmap_autorid_addrange_ctx ctx;
297 ctx.acquire = acquire;
298 ctx.range = range;
300 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
301 return status;
304 NTSTATUS idmap_autorid_setrange(struct db_context *db,
305 const char *domsid,
306 uint32_t domain_range_index,
307 uint32_t rangenum)
309 NTSTATUS status;
310 struct autorid_range_config range;
312 ZERO_STRUCT(range);
313 fstrcpy(range.domsid, domsid);
314 range.domain_range_index = domain_range_index;
315 range.rangenum = rangenum;
317 status = idmap_autorid_addrange(db, &range, false);
318 return status;
321 NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
322 struct autorid_range_config *range)
324 return idmap_autorid_addrange(db, range, true);
327 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
328 struct autorid_range_config *range)
330 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
331 struct autorid_global_config globalcfg = {0};
332 fstring keystr;
334 if (db == NULL || range == NULL) {
335 DEBUG(3, ("Invalid arguments received\n"));
336 goto done;
339 if (!idmap_autorid_validate_sid(range->domsid)) {
340 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
341 status = NT_STATUS_INVALID_PARAMETER;
342 goto done;
345 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
346 keystr);
348 DEBUG(10, ("reading domain range for key %s\n", keystr));
349 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(1, ("Failed to read database record for key '%s': %s\n",
352 keystr, nt_errstr(status)));
353 goto done;
356 status = idmap_autorid_loadconfig(db, &globalcfg);
357 if (!NT_STATUS_IS_OK(status)) {
358 DEBUG(1, ("Failed to read global configuration"));
359 goto done;
361 range->low_id = globalcfg.minvalue
362 + range->rangenum * globalcfg.rangesize;
363 range->high_id = range->low_id + globalcfg.rangesize - 1;
364 done:
365 return status;
368 NTSTATUS idmap_autorid_getrange(struct db_context *db,
369 const char *domsid,
370 uint32_t domain_range_index,
371 uint32_t *rangenum,
372 uint32_t *low_id)
374 NTSTATUS status;
375 struct autorid_range_config range;
377 if (rangenum == NULL) {
378 return NT_STATUS_INVALID_PARAMETER;
381 ZERO_STRUCT(range);
382 fstrcpy(range.domsid, domsid);
383 range.domain_range_index = domain_range_index;
385 status = idmap_autorid_getrange_int(db, &range);
386 if (!NT_STATUS_IS_OK(status)) {
387 return status;
390 *rangenum = range.rangenum;
392 if (low_id != NULL) {
393 *low_id = range.low_id;
396 return NT_STATUS_OK;
399 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
400 struct autorid_range_config *range,
401 bool read_only)
403 NTSTATUS ret;
405 ret = idmap_autorid_getrange_int(db, range);
406 if (!NT_STATUS_IS_OK(ret)) {
407 DEBUG(10, ("Failed to read range config for '%s': %s\n",
408 range->domsid, nt_errstr(ret)));
409 if (read_only) {
410 DEBUG(10, ("Not allocating new range for '%s' because "
411 "read-only is enabled.\n", range->domsid));
412 return NT_STATUS_NOT_FOUND;
415 ret = idmap_autorid_acquire_range(db, range);
418 DEBUG(10, ("Using range #%d for domain %s "
419 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
420 range->rangenum, range->domsid, range->domain_range_index,
421 range->low_id));
423 return ret;
426 /* initialize the given HWM to 0 if it does not exist yet */
427 static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
428 void *private_data)
430 NTSTATUS status;
431 uint32_t hwmval;
432 const char *hwm;
434 hwm = (char *)private_data;
436 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
437 if (NT_STATUS_IS_OK(status)) {
438 DEBUG(1, ("HWM (%s) already initialized in autorid database "
439 "(value %"PRIu32").\n", hwm, hwmval));
440 return NT_STATUS_OK;
442 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
443 DEBUG(0, ("Error fetching HWM (%s) from autorid "
444 "database: %s\n", hwm, nt_errstr(status)));
445 return status;
448 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
449 if (!NT_STATUS_IS_OK(status)) {
450 DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
451 hwm, nt_errstr(status)));
452 return status;
455 return NT_STATUS_OK;
458 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
460 NTSTATUS status;
461 uint32_t hwmval;
463 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
464 if (NT_STATUS_IS_OK(status)) {
465 DEBUG(1, ("HWM (%s) already initialized in autorid database "
466 "(value %"PRIu32").\n", hwm, hwmval));
467 return NT_STATUS_OK;
469 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
470 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
471 "database: %s\n", hwm, nt_errstr(status)));
472 return status;
475 status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
476 discard_const(hwm));
477 if (!NT_STATUS_IS_OK(status)) {
478 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
479 "%s\n", hwm, nt_errstr(status)));
480 return NT_STATUS_INTERNAL_DB_ERROR;
483 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
485 return NT_STATUS_OK;
489 * Delete a domain#index <-> range mapping from the database.
490 * The mapping is specified by the sid and index.
491 * If force == true, invalid mapping records are deleted as far
492 * as possible, otherwise they are left untouched.
495 struct idmap_autorid_delete_range_by_sid_ctx {
496 const char *domsid;
497 uint32_t domain_range_index;
498 bool force;
501 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
502 void *private_data)
504 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
505 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
506 const char *domsid;
507 uint32_t domain_range_index;
508 uint32_t rangenum;
509 char *keystr;
510 char *range_keystr;
511 TDB_DATA data;
512 NTSTATUS status;
513 TALLOC_CTX *frame = talloc_stackframe();
514 bool is_valid_range_mapping = true;
515 bool force;
517 domsid = ctx->domsid;
518 domain_range_index = ctx->domain_range_index;
519 force = ctx->force;
521 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
522 domain_range_index);
523 if (keystr == NULL) {
524 status = NT_STATUS_NO_MEMORY;
525 goto done;
528 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
529 if (!NT_STATUS_IS_OK(status)) {
530 goto done;
533 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
534 if (range_keystr == NULL) {
535 status = NT_STATUS_NO_MEMORY;
536 goto done;
539 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
540 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
541 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
542 keystr, range_keystr));
543 is_valid_range_mapping = false;
544 } else if (!NT_STATUS_IS_OK(status)) {
545 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
546 keystr, range_keystr, nt_errstr(status)));
547 goto done;
548 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
549 != 0)
551 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
552 keystr, range_keystr, (const char *)data.dptr));
553 is_valid_range_mapping = false;
556 if (!is_valid_range_mapping && !force) {
557 DEBUG(10, ("Not deleting invalid mapping, since not in force "
558 "mode.\n"));
559 status = NT_STATUS_FILE_INVALID;
560 goto done;
563 status = dbwrap_delete_bystring(db, keystr);
564 if (!NT_STATUS_IS_OK(status)) {
565 DEBUG(1, ("Deletion of '%s' failed: %s\n",
566 keystr, nt_errstr(status)));
567 goto done;
570 if (!is_valid_range_mapping) {
571 goto done;
574 status = dbwrap_delete_bystring(db, range_keystr);
575 if (!NT_STATUS_IS_OK(status)) {
576 DEBUG(1, ("Deletion of '%s' failed: %s\n",
577 range_keystr, nt_errstr(status)));
578 goto done;
581 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
582 range_keystr));
584 done:
585 TALLOC_FREE(frame);
586 return status;
589 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
590 const char *domsid,
591 uint32_t domain_range_index,
592 bool force)
594 NTSTATUS status;
595 struct idmap_autorid_delete_range_by_sid_ctx ctx;
597 ctx.domain_range_index = domain_range_index;
598 ctx.domsid = domsid;
599 ctx.force = force;
601 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
602 &ctx);
603 return status;
607 * Delete a domain#index <-> range mapping from the database.
608 * The mapping is specified by the range number.
609 * If force == true, invalid mapping records are deleted as far
610 * as possible, otherwise they are left untouched.
612 struct idmap_autorid_delete_range_by_num_ctx {
613 uint32_t rangenum;
614 bool force;
617 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
618 void *private_data)
620 struct idmap_autorid_delete_range_by_num_ctx *ctx =
621 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
622 uint32_t rangenum;
623 char *keystr = NULL;
624 char *range_keystr;
625 TDB_DATA val;
626 NTSTATUS status;
627 TALLOC_CTX *frame = talloc_stackframe();
628 bool is_valid_range_mapping = true;
629 bool force;
631 rangenum = ctx->rangenum;
632 force = ctx->force;
634 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
635 if (range_keystr == NULL) {
636 status = NT_STATUS_NO_MEMORY;
637 goto done;
640 ZERO_STRUCT(val);
642 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
643 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
644 DEBUG(10, ("Did not find range '%s' in database.\n",
645 range_keystr));
646 goto done;
647 } else if (!NT_STATUS_IS_OK(status)) {
648 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
649 goto done;
652 if (val.dptr == NULL) {
653 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
654 range_keystr));
655 is_valid_range_mapping = false;
656 } else {
657 uint32_t reverse_rangenum = 0;
659 keystr = (char *)val.dptr;
661 status = dbwrap_fetch_uint32_bystring(db, keystr,
662 &reverse_rangenum);
663 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
664 DEBUG(1, ("Incomplete mapping %s -> %s: "
665 "no backward mapping\n",
666 range_keystr, keystr));
667 is_valid_range_mapping = false;
668 } else if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(1, ("Error fetching reverse mapping for "
670 "%s -> %s: %s\n",
671 range_keystr, keystr, nt_errstr(status)));
672 goto done;
673 } else if (rangenum != reverse_rangenum) {
674 is_valid_range_mapping = false;
678 if (!is_valid_range_mapping && !force) {
679 DEBUG(10, ("Not deleting invalid mapping, since not in force "
680 "mode.\n"));
681 status = NT_STATUS_FILE_INVALID;
682 goto done;
685 status = dbwrap_delete_bystring(db, range_keystr);
686 if (!NT_STATUS_IS_OK(status)) {
687 DEBUG(1, ("Deletion of '%s' failed: %s\n",
688 range_keystr, nt_errstr(status)));
689 goto done;
692 if (!is_valid_range_mapping) {
693 goto done;
696 status = dbwrap_delete_bystring(db, keystr);
697 if (!NT_STATUS_IS_OK(status)) {
698 DEBUG(1, ("Deletion of '%s' failed: %s\n",
699 keystr, nt_errstr(status)));
700 goto done;
703 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
704 keystr));
706 done:
707 talloc_free(frame);
708 return status;
711 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
712 uint32_t rangenum,
713 bool force)
715 NTSTATUS status;
716 struct idmap_autorid_delete_range_by_num_ctx ctx;
718 ctx.rangenum = rangenum;
719 ctx.force = force;
721 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
722 &ctx);
723 return status;
727 * Open and possibly create the database.
729 NTSTATUS idmap_autorid_db_open(const char *path,
730 TALLOC_CTX *mem_ctx,
731 struct db_context **db)
733 if (*db != NULL) {
734 /* its already open */
735 return NT_STATUS_OK;
738 /* Open idmap repository */
739 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
740 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
742 if (*db == NULL) {
743 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
744 return NT_STATUS_UNSUCCESSFUL;
747 return NT_STATUS_OK;
751 * Initialize the high watermark records in the database.
753 NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
755 NTSTATUS status;
757 status = idmap_autorid_init_hwm(db, HWM);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
762 status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
763 if (!NT_STATUS_IS_OK(status)) {
764 return status;
767 status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
769 return status;
772 NTSTATUS idmap_autorid_db_init(const char *path,
773 TALLOC_CTX *mem_ctx,
774 struct db_context **db)
776 NTSTATUS status;
778 status = idmap_autorid_db_open(path, mem_ctx, db);
779 if (!NT_STATUS_IS_OK(status)) {
780 return status;
783 status = idmap_autorid_init_hwms(*db);
784 return status;
789 struct idmap_autorid_fetch_config_state {
790 TALLOC_CTX *mem_ctx;
791 char *configstr;
794 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
795 void *private_data)
797 struct idmap_autorid_fetch_config_state *state;
799 state = (struct idmap_autorid_fetch_config_state *)private_data;
802 * strndup because we have non-nullterminated strings in the db
804 state->configstr = talloc_strndup(
805 state->mem_ctx, (const char *)value.dptr, value.dsize);
808 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
809 char **result)
811 TDB_DATA key;
812 NTSTATUS status;
813 struct idmap_autorid_fetch_config_state state;
815 if (result == NULL) {
816 return NT_STATUS_INVALID_PARAMETER;
819 key = string_term_tdb_data(CONFIGKEY);
821 state.mem_ctx = mem_ctx;
822 state.configstr = NULL;
824 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
825 &state);
826 if (!NT_STATUS_IS_OK(status)) {
827 DEBUG(1, ("Error while retrieving config: %s\n",
828 nt_errstr(status)));
829 return status;
832 if (state.configstr == NULL) {
833 DEBUG(1, ("Error while retrieving config\n"));
834 return NT_STATUS_NO_MEMORY;
837 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
839 *result = state.configstr;
840 return NT_STATUS_OK;
843 bool idmap_autorid_parse_configstr(const char *configstr,
844 struct autorid_global_config *cfg)
846 unsigned long minvalue, rangesize, maxranges;
848 if (sscanf(configstr,
849 "minvalue:%lu rangesize:%lu maxranges:%lu",
850 &minvalue, &rangesize, &maxranges) != 3) {
851 DEBUG(1,
852 ("Found invalid configuration data. "
853 "Creating new config\n"));
854 return false;
857 cfg->minvalue = minvalue;
858 cfg->rangesize = rangesize;
859 cfg->maxranges = maxranges;
861 return true;
864 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
865 struct autorid_global_config *result)
867 struct autorid_global_config cfg = {0};
868 NTSTATUS status;
869 bool ok;
870 char *configstr = NULL;
872 if (result == NULL) {
873 return NT_STATUS_INVALID_PARAMETER;
876 status = idmap_autorid_getconfigstr(db, db, &configstr);
877 if (!NT_STATUS_IS_OK(status)) {
878 return status;
881 ok = idmap_autorid_parse_configstr(configstr, &cfg);
882 TALLOC_FREE(configstr);
883 if (!ok) {
884 return NT_STATUS_INVALID_PARAMETER;
887 DEBUG(10, ("Loaded previously stored configuration "
888 "minvalue:%d rangesize:%d\n",
889 cfg.minvalue, cfg.rangesize));
891 *result = cfg;
893 return NT_STATUS_OK;
896 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
897 struct autorid_global_config *cfg)
900 struct autorid_global_config storedconfig = {0};
901 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
902 TDB_DATA data;
903 char *cfgstr;
904 uint32_t hwm;
905 TALLOC_CTX *frame = talloc_stackframe();
907 DEBUG(10, ("New configuration provided for storing is "
908 "minvalue:%d rangesize:%d maxranges:%d\n",
909 cfg->minvalue, cfg->rangesize, cfg->maxranges));
911 if (cfg->rangesize < 2000) {
912 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
913 goto done;
916 if (cfg->maxranges == 0) {
917 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
918 "Must have at least one range available.\n"));
919 goto done;
922 status = idmap_autorid_loadconfig(db, &storedconfig);
923 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
924 DEBUG(5, ("No configuration found. Storing initial "
925 "configuration.\n"));
926 storedconfig = *cfg;
927 } else if (!NT_STATUS_IS_OK(status)) {
928 DEBUG(1, ("Error loading configuration: %s\n",
929 nt_errstr(status)));
930 goto done;
933 /* did the minimum value or rangesize change? */
934 if ((storedconfig.minvalue != cfg->minvalue) ||
935 (storedconfig.rangesize != cfg->rangesize))
937 DEBUG(1, ("New configuration values for rangesize or "
938 "minimum uid value conflict with previously "
939 "used values! Not storing new config.\n"));
940 status = NT_STATUS_INVALID_PARAMETER;
941 goto done;
944 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
945 if (!NT_STATUS_IS_OK(status)) {
946 DEBUG(1, ("Fatal error while fetching current "
947 "HWM value: %s\n", nt_errstr(status)));
948 status = NT_STATUS_INTERNAL_ERROR;
949 goto done;
953 * has the highest uid value been reduced to setting that is not
954 * sufficient any more for already existing ranges?
956 if (hwm > cfg->maxranges) {
957 DEBUG(1, ("New upper uid limit is too low to cover "
958 "existing mappings! Not storing new config.\n"));
959 status = NT_STATUS_INVALID_PARAMETER;
960 goto done;
963 cfgstr =
964 talloc_asprintf(frame,
965 "minvalue:%u rangesize:%u maxranges:%u",
966 cfg->minvalue, cfg->rangesize, cfg->maxranges);
968 if (cfgstr == NULL) {
969 status = NT_STATUS_NO_MEMORY;
970 goto done;
973 data = string_tdb_data(cfgstr);
975 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
977 done:
978 TALLOC_FREE(frame);
979 return status;
982 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
983 const char *configstr)
985 bool ok;
986 NTSTATUS status;
987 struct autorid_global_config cfg;
989 ok = idmap_autorid_parse_configstr(configstr, &cfg);
990 if (!ok) {
991 return NT_STATUS_INVALID_PARAMETER;
994 status = idmap_autorid_saveconfig(db, &cfg);
995 return status;
1000 * iteration: Work on all range mappings for a given domain
1003 struct domain_range_visitor_ctx {
1004 const char *domsid;
1005 NTSTATUS (*fn)(struct db_context *db,
1006 const char *domsid,
1007 uint32_t index,
1008 uint32_t rangenum,
1009 void *private_data);
1010 void *private_data;
1011 int count; /* number of records worked on */
1014 static int idmap_autorid_visit_domain_range(struct db_record *rec,
1015 void *private_data)
1017 struct domain_range_visitor_ctx *vi;
1018 char *domsid;
1019 char *sep;
1020 uint32_t range_index = 0;
1021 uint32_t rangenum = 0;
1022 TDB_DATA key, value;
1023 NTSTATUS status;
1024 int ret = 0;
1025 struct db_context *db;
1027 vi = talloc_get_type_abort(private_data,
1028 struct domain_range_visitor_ctx);
1030 key = dbwrap_record_get_key(rec);
1033 * split string "<sid>[#<index>]" into sid string and index number
1036 domsid = (char *)key.dptr;
1038 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1039 domsid));
1041 sep = strrchr(domsid, '#');
1042 if (sep != NULL) {
1043 char *index_str;
1044 *sep = '\0';
1045 index_str = sep+1;
1046 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1047 DEBUG(10, ("Found separator '#' but '%s' is not a "
1048 "valid range index. Skipping record\n",
1049 index_str));
1050 goto done;
1054 if (!idmap_autorid_validate_sid(domsid)) {
1055 DEBUG(10, ("String '%s' is not a valid sid. "
1056 "Skipping record.\n", domsid));
1057 goto done;
1060 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1061 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1062 domsid, vi->domsid));
1063 goto done;
1066 value = dbwrap_record_get_value(rec);
1068 if (value.dsize != sizeof(uint32_t)) {
1069 /* it might be a mapping of a well known sid */
1070 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1071 "skipping.\n", (unsigned)value.dsize, vi->domsid));
1072 goto done;
1075 rangenum = IVAL(value.dptr, 0);
1077 db = dbwrap_record_get_db(rec);
1079 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1080 if (!NT_STATUS_IS_OK(status)) {
1081 ret = -1;
1082 goto done;
1085 vi->count++;
1086 ret = 0;
1088 done:
1089 return ret;
1092 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1093 const char *domsid,
1094 NTSTATUS (*fn)(struct db_context *db,
1095 const char *domsid,
1096 uint32_t index,
1097 uint32_t rangnum,
1098 void *private_data),
1099 void *private_data,
1100 int *count,
1101 NTSTATUS (*traverse)(struct db_context *db,
1102 int (*f)(struct db_record *, void *),
1103 void *private_data,
1104 int *count))
1106 NTSTATUS status;
1107 struct domain_range_visitor_ctx *vi;
1108 TALLOC_CTX *frame = talloc_stackframe();
1110 if (domsid == NULL) {
1111 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1114 if (fn == NULL) {
1115 DEBUG(1, ("Error: missing visitor callback\n"));
1116 status = NT_STATUS_INVALID_PARAMETER;
1117 goto done;
1120 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1121 if (vi == NULL) {
1122 status = NT_STATUS_NO_MEMORY;
1123 goto done;
1126 vi->domsid = domsid;
1127 vi->fn = fn;
1128 vi->private_data = private_data;
1130 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 goto done;
1135 if (count != NULL) {
1136 *count = vi->count;
1139 done:
1140 talloc_free(frame);
1141 return status;
1144 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1145 const char *domsid,
1146 NTSTATUS (*fn)(struct db_context *db,
1147 const char *domsid,
1148 uint32_t index,
1149 uint32_t rangenum,
1150 void *private_data),
1151 void *private_data,
1152 int *count)
1154 NTSTATUS status;
1156 status = idmap_autorid_iterate_domain_ranges_int(db,
1157 domsid,
1159 private_data,
1160 count,
1161 dbwrap_traverse);
1163 return status;
1167 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1168 const char *domsid,
1169 NTSTATUS (*fn)(struct db_context *db,
1170 const char *domsid,
1171 uint32_t index,
1172 uint32_t rangenum,
1173 void *count),
1174 void *private_data,
1175 int *count)
1177 NTSTATUS status;
1179 status = idmap_autorid_iterate_domain_ranges_int(db,
1180 domsid,
1182 private_data,
1183 count,
1184 dbwrap_traverse_read);
1186 return status;
1191 * Delete all ranges configured for a given domain
1194 struct delete_domain_ranges_visitor_ctx {
1195 bool force;
1198 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1199 struct db_context *db,
1200 const char *domsid,
1201 uint32_t domain_range_index,
1202 uint32_t rangenum,
1203 void *private_data)
1205 struct delete_domain_ranges_visitor_ctx *ctx;
1206 NTSTATUS status;
1208 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1210 status = idmap_autorid_delete_range_by_sid(
1211 db, domsid, domain_range_index, ctx->force);
1212 return status;
1215 struct idmap_autorid_delete_domain_ranges_ctx {
1216 const char *domsid;
1217 bool force;
1218 int count; /* output: count records operated on */
1221 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1222 void *private_data)
1224 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1225 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1226 int count;
1227 NTSTATUS status;
1229 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1231 ZERO_STRUCT(visitor_ctx);
1232 visitor_ctx.force = ctx->force;
1234 status = idmap_autorid_iterate_domain_ranges(db,
1235 ctx->domsid,
1236 idmap_autorid_delete_domain_ranges_visitor,
1237 &visitor_ctx,
1238 &count);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 return status;
1243 ctx->count = count;
1245 return NT_STATUS_OK;
1248 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1249 const char *domsid,
1250 bool force,
1251 int *count)
1253 NTSTATUS status;
1254 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1256 ZERO_STRUCT(ctx);
1257 ctx.domsid = domsid;
1258 ctx.force = force;
1260 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1261 &ctx);
1262 if (!NT_STATUS_IS_OK(status)) {
1263 return status;
1266 *count = ctx.count;
1268 return NT_STATUS_OK;