autorid: when storing a new range, always check it does not exist.
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blob4f7861de651c1c810600b67ba91d8772c48b6730
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"
29 /**
30 * Build the database keystring for getting a range
31 * belonging to a domain sid and a range index.
33 static void idmap_autorid_build_keystr(const char *domsid,
34 uint32_t domain_range_index,
35 fstring keystr)
37 if (domain_range_index > 0) {
38 fstr_sprintf(keystr, "%s#%"PRIu32,
39 domsid, domain_range_index);
40 } else {
41 fstrcpy(keystr, domsid);
45 static char *idmap_autorid_build_keystr_talloc(TALLOC_CTX *mem_ctx,
46 const char *domsid,
47 uint32_t domain_range_index)
49 char *keystr;
51 if (domain_range_index > 0) {
52 keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
53 domain_range_index);
54 } else {
55 keystr = talloc_strdup(mem_ctx, domsid);
58 return keystr;
62 static bool idmap_autorid_validate_sid(const char *sid)
64 struct dom_sid ignore;
65 if (sid == NULL) {
66 return false;
69 if (strcmp(sid, ALLOC_RANGE) == 0) {
70 return true;
73 return dom_sid_parse(sid, &ignore);
76 struct idmap_autorid_addrange_ctx {
77 struct autorid_range_config *range;
78 bool acquire;
81 static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
82 void *private_data)
84 struct idmap_autorid_addrange_ctx *ctx;
85 uint32_t requested_rangenum, stored_rangenum;
86 struct autorid_range_config *range;
87 bool acquire;
88 NTSTATUS ret;
89 uint32_t hwm;
90 char *numstr;
91 struct autorid_global_config *globalcfg;
92 fstring keystr;
93 uint32_t increment;
94 TALLOC_CTX *mem_ctx = NULL;
96 ctx = (struct idmap_autorid_addrange_ctx *)private_data;
97 range = ctx->range;
98 acquire = ctx->acquire;
99 requested_rangenum = range->rangenum;
101 if (db == NULL) {
102 DEBUG(3, ("Invalid database argument: NULL"));
103 return NT_STATUS_INVALID_PARAMETER;
106 if (range == NULL) {
107 DEBUG(3, ("Invalid range argument: NULL"));
108 return NT_STATUS_INVALID_PARAMETER;
111 DEBUG(10, ("Adding new range for domain %s "
112 "(domain_range_index=%"PRIu32")\n",
113 range->domsid, range->domain_range_index));
115 if (!idmap_autorid_validate_sid(range->domsid)) {
116 DEBUG(3, ("Invalid SID: %s\n", range->domsid));
117 return NT_STATUS_INVALID_PARAMETER;
120 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
121 keystr);
123 ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
125 if (NT_STATUS_IS_OK(ret)) {
126 /* entry is already present*/
127 if (acquire) {
128 DEBUG(10, ("domain range already allocated - "
129 "Not adding!\n"));
130 return NT_STATUS_OK;
133 if (stored_rangenum != requested_rangenum) {
134 DEBUG(1, ("Error: requested rangenumber (%u) differs "
135 "from stored one (%u).\n",
136 requested_rangenum, stored_rangenum));
137 return NT_STATUS_UNSUCCESSFUL;
140 DEBUG(10, ("Note: stored range agrees with requested "
141 "one - ok\n"));
142 return NT_STATUS_OK;
145 /* fetch the current HWM */
146 ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
147 if (!NT_STATUS_IS_OK(ret)) {
148 DEBUG(1, ("Fatal error while fetching current "
149 "HWM value: %s\n", nt_errstr(ret)));
150 return NT_STATUS_INTERNAL_ERROR;
153 mem_ctx = talloc_stackframe();
155 ret = idmap_autorid_loadconfig(db, mem_ctx, &globalcfg);
156 if (!NT_STATUS_IS_OK(ret)) {
157 DEBUG(1, ("Fatal error while fetching configuration: %s\n",
158 nt_errstr(ret)));
159 goto error;
162 if (acquire) {
164 * automatically acquire the next range
166 requested_rangenum = hwm;
169 if (requested_rangenum >= globalcfg->maxranges) {
170 DEBUG(1, ("Not enough ranges available: New range %u must be "
171 "smaller than configured maximum number of ranges "
172 "(%u).\n",
173 requested_rangenum, globalcfg->maxranges));
174 ret = NT_STATUS_NO_MEMORY;
175 goto error;
179 * Check that it is not yet taken.
180 * If the range is requested and < HWM, we need
181 * to check anyways, and otherwise, we also better
182 * check in order to prevent further corruption
183 * in case the db has been externally modified.
186 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
187 if (!numstr) {
188 ret = NT_STATUS_NO_MEMORY;
189 goto error;
192 if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
193 DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
195 if (requested_rangenum < hwm) {
196 ret = NT_STATUS_INVALID_PARAMETER;
197 } else {
198 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
201 goto error;
204 if (requested_rangenum >= hwm) {
206 * requested or automatic range >= HWM:
207 * increment the HWM.
210 /* HWM always contains current max range + 1 */
211 increment = requested_rangenum + 1 - hwm;
213 /* increase the HWM */
214 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
215 increment);
216 if (!NT_STATUS_IS_OK(ret)) {
217 DEBUG(1, ("Fatal error while incrementing the HWM "
218 "value in the database: %s\n",
219 nt_errstr(ret)));
220 goto error;
225 * store away the new mapping in both directions
228 ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
229 if (!NT_STATUS_IS_OK(ret)) {
230 DEBUG(1, ("Fatal error while storing new "
231 "domain->range assignment: %s\n", nt_errstr(ret)));
232 goto error;
235 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
236 if (!numstr) {
237 ret = NT_STATUS_NO_MEMORY;
238 goto error;
241 ret = dbwrap_store_bystring(db, numstr,
242 string_term_tdb_data(keystr), TDB_INSERT);
244 if (!NT_STATUS_IS_OK(ret)) {
245 DEBUG(1, ("Fatal error while storing new "
246 "domain->range assignment: %s\n", nt_errstr(ret)));
247 goto error;
249 DEBUG(5, ("Acquired new range #%d for domain %s "
250 "(domain_range_index=%"PRIu32")\n", requested_rangenum, keystr,
251 range->domain_range_index));
253 range->rangenum = requested_rangenum;
255 range->low_id = globalcfg->minvalue
256 + range->rangenum * globalcfg->rangesize;
258 ret = NT_STATUS_OK;
260 error:
261 talloc_free(mem_ctx);
262 return ret;
265 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
266 struct autorid_range_config *range,
267 bool acquire)
269 NTSTATUS status;
270 struct idmap_autorid_addrange_ctx ctx;
272 ctx.acquire = acquire;
273 ctx.range = range;
275 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
276 return status;
279 NTSTATUS idmap_autorid_setrange(struct db_context *db,
280 const char *domsid,
281 uint32_t domain_range_index,
282 uint32_t rangenum)
284 NTSTATUS status;
285 struct autorid_range_config range;
287 ZERO_STRUCT(range);
288 fstrcpy(range.domsid, domsid);
289 range.domain_range_index = domain_range_index;
290 range.rangenum = rangenum;
292 status = idmap_autorid_addrange(db, &range, false);
293 return status;
296 static NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
297 struct autorid_range_config *range)
299 return idmap_autorid_addrange(db, range, true);
302 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
303 struct autorid_range_config *range)
305 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
306 struct autorid_global_config *globalcfg = NULL;
307 fstring keystr;
309 if (db == NULL || range == NULL) {
310 DEBUG(3, ("Invalid arguments received\n"));
311 goto done;
314 if (!idmap_autorid_validate_sid(range->domsid)) {
315 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
316 status = NT_STATUS_INVALID_PARAMETER;
317 goto done;
320 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
321 keystr);
323 DEBUG(10, ("reading domain range for key %s\n", keystr));
324 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
325 if (!NT_STATUS_IS_OK(status)) {
326 DEBUG(1, ("Failed to read database for key '%s': %s\n",
327 keystr, nt_errstr(status)));
328 goto done;
331 status = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
332 if (!NT_STATUS_IS_OK(status)) {
333 DEBUG(1, ("Failed to read global configuration"));
334 goto done;
336 range->low_id = globalcfg->minvalue
337 + range->rangenum * globalcfg->rangesize;
339 TALLOC_FREE(globalcfg);
340 done:
341 return status;
344 NTSTATUS idmap_autorid_getrange(struct db_context *db,
345 const char *domsid,
346 uint32_t domain_range_index,
347 uint32_t *rangenum,
348 uint32_t *low_id)
350 NTSTATUS status;
351 struct autorid_range_config range;
353 if (rangenum == NULL) {
354 return NT_STATUS_INVALID_PARAMETER;
357 ZERO_STRUCT(range);
358 fstrcpy(range.domsid, domsid);
359 range.domain_range_index = domain_range_index;
361 status = idmap_autorid_getrange_int(db, &range);
362 if (!NT_STATUS_IS_OK(status)) {
363 return status;
366 *rangenum = range.rangenum;
368 if (low_id != NULL) {
369 *low_id = range.low_id;
372 return NT_STATUS_OK;
375 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
376 struct autorid_range_config *range,
377 bool read_only)
379 NTSTATUS ret;
381 ret = idmap_autorid_getrange_int(db, range);
382 if (!NT_STATUS_IS_OK(ret)) {
383 if (read_only) {
384 return NT_STATUS_NOT_FOUND;
387 ret = idmap_autorid_acquire_range(db, range);
390 DEBUG(10, ("Using range #%d for domain %s "
391 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
392 range->rangenum, range->domsid, range->domain_range_index,
393 range->low_id));
395 return ret;
398 /* initialize the given HWM to 0 if it does not exist yet */
399 static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
400 void *private_data)
402 NTSTATUS status;
403 uint32_t hwmval;
404 const char *hwm;
406 hwm = (char *)private_data;
408 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
409 if (NT_STATUS_IS_OK(status)) {
410 DEBUG(1, ("HWM (%s) already initialized in autorid database "
411 "(value %"PRIu32").\n", hwm, hwmval));
412 return NT_STATUS_OK;
414 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
415 DEBUG(0, ("Error fetching HWM (%s) from autorid "
416 "database: %s\n", hwm, nt_errstr(status)));
417 return status;
420 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
421 if (!NT_STATUS_IS_OK(status)) {
422 DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
423 hwm, nt_errstr(status)));
424 return status;
427 return NT_STATUS_OK;
430 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
432 NTSTATUS status;
433 uint32_t hwmval;
435 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
436 if (NT_STATUS_IS_OK(status)) {
437 DEBUG(1, ("HWM (%s) already initialized in autorid database "
438 "(value %"PRIu32").\n", hwm, hwmval));
439 return NT_STATUS_OK;
441 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
442 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
443 "database: %s\n", hwm, nt_errstr(status)));
444 return status;
447 status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
448 (void *)hwm);
449 if (!NT_STATUS_IS_OK(status)) {
450 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
451 "%s\n", hwm, nt_errstr(status)));
452 return NT_STATUS_INTERNAL_DB_ERROR;
455 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
457 return NT_STATUS_OK;
461 * Delete a domain#index <-> range mapping from the database.
462 * The mapping is specified by the sid and index.
463 * If force == true, invalid mapping records are deleted as far
464 * as possible, otherwise they are left untouched.
467 struct idmap_autorid_delete_range_by_sid_ctx {
468 const char *domsid;
469 uint32_t domain_range_index;
470 bool force;
473 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
474 void *private_data)
476 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
477 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
478 const char *domsid;
479 uint32_t domain_range_index;
480 uint32_t rangenum;
481 char *keystr;
482 char *range_keystr;
483 TDB_DATA data;
484 NTSTATUS status;
485 TALLOC_CTX *frame = talloc_stackframe();
486 bool is_valid_range_mapping = true;
487 bool force;
489 domsid = ctx->domsid;
490 domain_range_index = ctx->domain_range_index;
491 force = ctx->force;
493 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
494 domain_range_index);
495 if (keystr == NULL) {
496 status = NT_STATUS_NO_MEMORY;
497 goto done;
500 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
501 if (!NT_STATUS_IS_OK(status)) {
502 goto done;
505 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
506 if (range_keystr == NULL) {
507 status = NT_STATUS_NO_MEMORY;
508 goto done;
511 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
512 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
513 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
514 keystr, range_keystr));
515 is_valid_range_mapping = false;
516 } else if (!NT_STATUS_IS_OK(status)) {
517 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
518 keystr, range_keystr, nt_errstr(status)));
519 goto done;
520 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
521 != 0)
523 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
524 keystr, range_keystr, (const char *)data.dptr));
525 is_valid_range_mapping = false;
528 if (!is_valid_range_mapping && !force) {
529 DEBUG(10, ("Not deleting invalid mapping, since not in force "
530 "mode.\n"));
531 status = NT_STATUS_FILE_INVALID;
532 goto done;
535 status = dbwrap_delete_bystring(db, keystr);
536 if (!NT_STATUS_IS_OK(status)) {
537 DEBUG(1, ("Deletion of '%s' failed: %s\n",
538 keystr, nt_errstr(status)));
539 goto done;
542 if (!is_valid_range_mapping) {
543 goto done;
546 status = dbwrap_delete_bystring(db, range_keystr);
547 if (!NT_STATUS_IS_OK(status)) {
548 DEBUG(1, ("Deletion of '%s' failed: %s\n",
549 range_keystr, nt_errstr(status)));
550 goto done;
553 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
554 range_keystr));
556 done:
557 TALLOC_FREE(frame);
558 return status;
561 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
562 const char *domsid,
563 uint32_t domain_range_index,
564 bool force)
566 NTSTATUS status;
567 struct idmap_autorid_delete_range_by_sid_ctx ctx;
569 ctx.domain_range_index = domain_range_index;
570 ctx.domsid = domsid;
571 ctx.force = force;
573 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
574 &ctx);
575 return status;
579 * Delete a domain#index <-> range mapping from the database.
580 * The mapping is specified by the range number.
581 * If force == true, invalid mapping records are deleted as far
582 * as possible, otherwise they are left untouched.
584 struct idmap_autorid_delete_range_by_num_ctx {
585 uint32_t rangenum;
586 bool force;
589 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
590 void *private_data)
592 struct idmap_autorid_delete_range_by_num_ctx *ctx =
593 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
594 uint32_t rangenum;
595 char *keystr;
596 char *range_keystr;
597 TDB_DATA val;
598 NTSTATUS status;
599 TALLOC_CTX *frame = talloc_stackframe();
600 bool is_valid_range_mapping = true;
601 bool force;
603 rangenum = ctx->rangenum;
604 force = ctx->force;
606 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
607 if (range_keystr == NULL) {
608 status = NT_STATUS_NO_MEMORY;
609 goto done;
612 ZERO_STRUCT(val);
614 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
615 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
616 DEBUG(10, ("Did not find range '%s' in database.\n",
617 range_keystr));
618 goto done;
619 } else if (!NT_STATUS_IS_OK(status)) {
620 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
621 goto done;
624 if (val.dptr == NULL) {
625 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
626 range_keystr));
627 is_valid_range_mapping = false;
628 } else {
629 uint32_t reverse_rangenum = 0;
631 keystr = (char *)val.dptr;
633 status = dbwrap_fetch_uint32_bystring(db, keystr,
634 &reverse_rangenum);
635 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
636 DEBUG(1, ("Incomplete mapping %s -> %s: "
637 "no backward mapping\n",
638 range_keystr, keystr));
639 is_valid_range_mapping = false;
640 } else if (!NT_STATUS_IS_OK(status)) {
641 DEBUG(1, ("Error fetching reverse mapping for "
642 "%s -> %s: %s\n",
643 range_keystr, keystr, nt_errstr(status)));
644 goto done;
645 } else if (rangenum != reverse_rangenum) {
646 is_valid_range_mapping = false;
650 if (!is_valid_range_mapping && !force) {
651 DEBUG(10, ("Not deleting invalid mapping, since not in force "
652 "mode.\n"));
653 status = NT_STATUS_FILE_INVALID;
654 goto done;
657 status = dbwrap_delete_bystring(db, range_keystr);
658 if (!NT_STATUS_IS_OK(status)) {
659 DEBUG(1, ("Deletion of '%s' failed: %s\n",
660 range_keystr, nt_errstr(status)));
661 goto done;
664 if (!is_valid_range_mapping) {
665 goto done;
668 status = dbwrap_delete_bystring(db, keystr);
669 if (!NT_STATUS_IS_OK(status)) {
670 DEBUG(1, ("Deletion of '%s' failed: %s\n",
671 keystr, nt_errstr(status)));
672 goto done;
675 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
676 keystr));
678 done:
679 talloc_free(frame);
680 return status;
683 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
684 uint32_t rangenum,
685 bool force)
687 NTSTATUS status;
688 struct idmap_autorid_delete_range_by_num_ctx ctx;
690 ctx.rangenum = rangenum;
691 ctx.force = force;
693 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
694 &ctx);
695 return status;
699 * open and initialize the database which stores the ranges for the domains
701 NTSTATUS idmap_autorid_db_init(const char *path,
702 TALLOC_CTX *mem_ctx,
703 struct db_context **db)
705 NTSTATUS status;
707 if (*db != NULL) {
708 /* its already open */
709 return NT_STATUS_OK;
712 /* Open idmap repository */
713 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
714 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
716 if (*db == NULL) {
717 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
718 return NT_STATUS_UNSUCCESSFUL;
721 /* Initialize high water mark for the currently used range to 0 */
723 status = idmap_autorid_init_hwm(*db, HWM);
724 NT_STATUS_NOT_OK_RETURN(status);
726 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_UID);
727 NT_STATUS_NOT_OK_RETURN(status);
729 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_GID);
731 return status;
734 struct idmap_autorid_fetch_config_state {
735 TALLOC_CTX *mem_ctx;
736 char *configstr;
739 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
740 void *private_data)
742 struct idmap_autorid_fetch_config_state *state;
744 state = (struct idmap_autorid_fetch_config_state *)private_data;
747 * strndup because we have non-nullterminated strings in the db
749 state->configstr = talloc_strndup(
750 state->mem_ctx, (const char *)value.dptr, value.dsize);
753 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
754 char **result)
756 TDB_DATA key;
757 NTSTATUS status;
758 struct idmap_autorid_fetch_config_state state;
760 if (result == NULL) {
761 return NT_STATUS_INVALID_PARAMETER;
764 key = string_term_tdb_data(CONFIGKEY);
766 state.mem_ctx = mem_ctx;
767 state.configstr = NULL;
769 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
770 &state);
771 if (!NT_STATUS_IS_OK(status)) {
772 DEBUG(1, ("Error while retrieving config: %s\n",
773 nt_errstr(status)));
774 return status;
777 if (state.configstr == NULL) {
778 DEBUG(1, ("Error while retrieving config\n"));
779 return NT_STATUS_NO_MEMORY;
782 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
784 *result = state.configstr;
785 return NT_STATUS_OK;
788 bool idmap_autorid_parse_configstr(const char *configstr,
789 struct autorid_global_config *cfg)
791 unsigned long minvalue, rangesize, maxranges;
793 if (sscanf(configstr,
794 "minvalue:%lu rangesize:%lu maxranges:%lu",
795 &minvalue, &rangesize, &maxranges) != 3) {
796 DEBUG(1,
797 ("Found invalid configuration data. "
798 "Creating new config\n"));
799 return false;
802 cfg->minvalue = minvalue;
803 cfg->rangesize = rangesize;
804 cfg->maxranges = maxranges;
806 return true;
809 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
810 TALLOC_CTX *mem_ctx,
811 struct autorid_global_config **result)
813 struct autorid_global_config *cfg;
814 NTSTATUS status;
815 bool ok;
816 char *configstr = NULL;
818 if (result == NULL) {
819 return NT_STATUS_INVALID_PARAMETER;
822 status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
823 if (!NT_STATUS_IS_OK(status)) {
824 return status;
827 cfg = talloc_zero(mem_ctx, struct autorid_global_config);
828 if (cfg == NULL) {
829 return NT_STATUS_NO_MEMORY;
832 ok = idmap_autorid_parse_configstr(configstr, cfg);
833 if (!ok) {
834 talloc_free(cfg);
835 return NT_STATUS_INVALID_PARAMETER;
838 DEBUG(10, ("Loaded previously stored configuration "
839 "minvalue:%d rangesize:%d\n",
840 cfg->minvalue, cfg->rangesize));
842 *result = cfg;
844 return NT_STATUS_OK;
847 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
848 struct autorid_global_config *cfg)
851 struct autorid_global_config *storedconfig = NULL;
852 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
853 TDB_DATA data;
854 char *cfgstr;
855 uint32_t hwm;
856 TALLOC_CTX *frame = talloc_stackframe();
858 DEBUG(10, ("New configuration provided for storing is "
859 "minvalue:%d rangesize:%d maxranges:%d\n",
860 cfg->minvalue, cfg->rangesize, cfg->maxranges));
862 if (cfg->rangesize < 2000) {
863 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
864 goto done;
867 if (cfg->maxranges == 0) {
868 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
869 "Must have at least one range available.\n"));
870 goto done;
873 status = idmap_autorid_loadconfig(db, frame, &storedconfig);
874 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
875 DEBUG(5, ("No configuration found. Storing initial "
876 "configuration.\n"));
877 } else if (!NT_STATUS_IS_OK(status)) {
878 goto done;
881 /* did the minimum value or rangesize change? */
882 if (storedconfig &&
883 ((storedconfig->minvalue != cfg->minvalue) ||
884 (storedconfig->rangesize != cfg->rangesize)))
886 DEBUG(1, ("New configuration values for rangesize or "
887 "minimum uid value conflict with previously "
888 "used values! Not storing new config.\n"));
889 status = NT_STATUS_INVALID_PARAMETER;
890 goto done;
893 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
894 if (!NT_STATUS_IS_OK(status)) {
895 DEBUG(1, ("Fatal error while fetching current "
896 "HWM value: %s\n", nt_errstr(status)));
897 status = NT_STATUS_INTERNAL_ERROR;
898 goto done;
902 * has the highest uid value been reduced to setting that is not
903 * sufficient any more for already existing ranges?
905 if (hwm > cfg->maxranges) {
906 DEBUG(1, ("New upper uid limit is too low to cover "
907 "existing mappings! Not storing new config.\n"));
908 status = NT_STATUS_INVALID_PARAMETER;
909 goto done;
912 cfgstr =
913 talloc_asprintf(frame,
914 "minvalue:%u rangesize:%u maxranges:%u",
915 cfg->minvalue, cfg->rangesize, cfg->maxranges);
917 if (cfgstr == NULL) {
918 status = NT_STATUS_NO_MEMORY;
919 goto done;
922 data = string_tdb_data(cfgstr);
924 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
926 done:
927 TALLOC_FREE(frame);
928 return status;
931 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
932 const char *configstr)
934 bool ok;
935 NTSTATUS status;
936 struct autorid_global_config cfg;
938 ok = idmap_autorid_parse_configstr(configstr, &cfg);
939 if (!ok) {
940 return NT_STATUS_INVALID_PARAMETER;
943 status = idmap_autorid_saveconfig(db, &cfg);
944 return status;
949 * iteration: Work on all range mappings for a given domain
952 struct domain_range_visitor_ctx {
953 const char *domsid;
954 NTSTATUS (*fn)(struct db_context *db,
955 const char *domsid,
956 uint32_t index,
957 uint32_t rangenum,
958 void *private_data);
959 void *private_data;
960 int count; /* number of records worked on */
963 static int idmap_autorid_visit_domain_range(struct db_record *rec,
964 void *private_data)
966 struct domain_range_visitor_ctx *vi;
967 char *domsid;
968 char *sep;
969 uint32_t range_index = 0;
970 uint32_t rangenum = 0;
971 TDB_DATA key, value;
972 NTSTATUS status;
973 int ret = 0;
974 struct db_context *db;
976 vi = talloc_get_type_abort(private_data,
977 struct domain_range_visitor_ctx);
979 key = dbwrap_record_get_key(rec);
982 * split string "<sid>[#<index>]" into sid string and index number
985 domsid = (char *)key.dptr;
987 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
988 domsid));
990 sep = strrchr(domsid, '#');
991 if (sep != NULL) {
992 char *index_str;
993 *sep = '\0';
994 index_str = sep+1;
995 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
996 DEBUG(10, ("Found separator '#' but '%s' is not a "
997 "valid range index. Skipping record\n",
998 index_str));
999 goto done;
1003 if (!idmap_autorid_validate_sid(domsid)) {
1004 DEBUG(10, ("String '%s' is not a valid sid. "
1005 "Skipping record.\n", domsid));
1006 goto done;
1009 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1010 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1011 domsid, vi->domsid));
1012 goto done;
1015 value = dbwrap_record_get_value(rec);
1017 if (value.dsize != sizeof(uint32_t)) {
1018 /* it might be a mapping of a well known sid */
1019 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1020 "skipping.\n", (unsigned)value.dsize, vi->domsid));
1021 goto done;
1024 rangenum = IVAL(value.dptr, 0);
1026 db = dbwrap_record_get_db(rec);
1028 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1029 if (!NT_STATUS_IS_OK(status)) {
1030 ret = -1;
1031 goto done;
1034 vi->count++;
1035 ret = 0;
1037 done:
1038 return ret;
1041 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1042 const char *domsid,
1043 NTSTATUS (*fn)(struct db_context *db,
1044 const char *domsid,
1045 uint32_t index,
1046 uint32_t rangnum,
1047 void *private_data),
1048 void *private_data,
1049 int *count,
1050 NTSTATUS (*traverse)(struct db_context *db,
1051 int (*f)(struct db_record *, void *),
1052 void *private_data,
1053 int *count))
1055 NTSTATUS status;
1056 struct domain_range_visitor_ctx *vi;
1057 TALLOC_CTX *frame = talloc_stackframe();
1059 if (domsid == NULL) {
1060 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1063 if (fn == NULL) {
1064 DEBUG(1, ("Error: missing visitor callback\n"));
1065 status = NT_STATUS_INVALID_PARAMETER;
1066 goto done;
1069 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1070 if (vi == NULL) {
1071 status = NT_STATUS_NO_MEMORY;
1072 goto done;
1075 vi->domsid = domsid;
1076 vi->fn = fn;
1077 vi->private_data = private_data;
1079 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1080 if (!NT_STATUS_IS_OK(status)) {
1081 goto done;
1084 if (count != NULL) {
1085 *count = vi->count;
1088 done:
1089 talloc_free(frame);
1090 return status;
1093 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1094 const char *domsid,
1095 NTSTATUS (*fn)(struct db_context *db,
1096 const char *domsid,
1097 uint32_t index,
1098 uint32_t rangenum,
1099 void *private_data),
1100 void *private_data,
1101 int *count)
1103 NTSTATUS status;
1105 status = idmap_autorid_iterate_domain_ranges_int(db,
1106 domsid,
1108 private_data,
1109 count,
1110 dbwrap_traverse);
1112 return status;
1116 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1117 const char *domsid,
1118 NTSTATUS (*fn)(struct db_context *db,
1119 const char *domsid,
1120 uint32_t index,
1121 uint32_t rangenum,
1122 void *count),
1123 void *private_data,
1124 int *count)
1126 NTSTATUS status;
1128 status = idmap_autorid_iterate_domain_ranges_int(db,
1129 domsid,
1131 private_data,
1132 count,
1133 dbwrap_traverse_read);
1135 return status;
1140 * Delete all ranges configured for a given domain
1143 struct delete_domain_ranges_visitor_ctx {
1144 bool force;
1147 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1148 struct db_context *db,
1149 const char *domsid,
1150 uint32_t domain_range_index,
1151 uint32_t rangenum,
1152 void *private_data)
1154 struct delete_domain_ranges_visitor_ctx *ctx;
1155 NTSTATUS status;
1157 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1159 status = idmap_autorid_delete_range_by_sid(
1160 db, domsid, domain_range_index, ctx->force);
1161 return status;
1164 struct idmap_autorid_delete_domain_ranges_ctx {
1165 const char *domsid;
1166 bool force;
1167 int count; /* output: count records operated on */
1170 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1171 void *private_data)
1173 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1174 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1175 int count;
1176 NTSTATUS status;
1178 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1180 ZERO_STRUCT(visitor_ctx);
1181 visitor_ctx.force = ctx->force;
1183 status = idmap_autorid_iterate_domain_ranges(db,
1184 ctx->domsid,
1185 idmap_autorid_delete_domain_ranges_visitor,
1186 &visitor_ctx,
1187 &count);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 return status;
1192 ctx->count = count;
1194 return NT_STATUS_OK;
1197 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1198 const char *domsid,
1199 bool force,
1200 int *count)
1202 NTSTATUS status;
1203 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1205 ZERO_STRUCT(ctx);
1206 ctx.domsid = domsid;
1207 ctx.force = force;
1209 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1210 &ctx);
1211 if (!NT_STATUS_IS_OK(status)) {
1212 return status;
1215 *count = ctx.count;
1217 return NT_STATUS_OK;