autorid: print debug message when a HWM key has been created
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blob15d0192323411bd48e1b7f3d3e1ce3f8b7ecb4ed
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;
178 if (requested_rangenum < hwm) {
180 * Set a specified range below the HWM:
181 * We need to check that it is not yet taken.
184 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
185 if (!numstr) {
186 ret = NT_STATUS_NO_MEMORY;
187 goto error;
190 if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
191 DEBUG(1, ("Requested range already in use.\n"));
192 ret = NT_STATUS_INVALID_PARAMETER;
193 goto error;
196 TALLOC_FREE(numstr);
197 } else {
199 * requested or automatic range >= HWM:
200 * increment the HWM.
203 /* HWM always contains current max range + 1 */
204 increment = requested_rangenum + 1 - hwm;
206 /* increase the HWM */
207 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
208 increment);
209 if (!NT_STATUS_IS_OK(ret)) {
210 DEBUG(1, ("Fatal error while incrementing the HWM "
211 "value in the database: %s\n",
212 nt_errstr(ret)));
213 goto error;
218 * store away the new mapping in both directions
221 ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
222 if (!NT_STATUS_IS_OK(ret)) {
223 DEBUG(1, ("Fatal error while storing new "
224 "domain->range assignment: %s\n", nt_errstr(ret)));
225 goto error;
228 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
229 if (!numstr) {
230 ret = NT_STATUS_NO_MEMORY;
231 goto error;
234 ret = dbwrap_store_bystring(db, numstr,
235 string_term_tdb_data(keystr), TDB_INSERT);
237 if (!NT_STATUS_IS_OK(ret)) {
238 DEBUG(1, ("Fatal error while storing new "
239 "domain->range assignment: %s\n", nt_errstr(ret)));
240 goto error;
242 DEBUG(5, ("Acquired new range #%d for domain %s "
243 "(domain_range_index=%"PRIu32")\n", requested_rangenum, keystr,
244 range->domain_range_index));
246 range->rangenum = requested_rangenum;
248 range->low_id = globalcfg->minvalue
249 + range->rangenum * globalcfg->rangesize;
251 ret = NT_STATUS_OK;
253 error:
254 talloc_free(mem_ctx);
255 return ret;
258 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
259 struct autorid_range_config *range,
260 bool acquire)
262 NTSTATUS status;
263 struct idmap_autorid_addrange_ctx ctx;
265 ctx.acquire = acquire;
266 ctx.range = range;
268 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
269 return status;
272 NTSTATUS idmap_autorid_setrange(struct db_context *db,
273 const char *domsid,
274 uint32_t domain_range_index,
275 uint32_t rangenum)
277 NTSTATUS status;
278 struct autorid_range_config range;
280 ZERO_STRUCT(range);
281 fstrcpy(range.domsid, domsid);
282 range.domain_range_index = domain_range_index;
283 range.rangenum = rangenum;
285 status = idmap_autorid_addrange(db, &range, false);
286 return status;
289 static NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
290 struct autorid_range_config *range)
292 return idmap_autorid_addrange(db, range, true);
295 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
296 struct autorid_range_config *range)
298 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
299 struct autorid_global_config *globalcfg = NULL;
300 fstring keystr;
302 if (db == NULL || range == NULL) {
303 DEBUG(3, ("Invalid arguments received\n"));
304 goto done;
307 if (!idmap_autorid_validate_sid(range->domsid)) {
308 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
309 status = NT_STATUS_INVALID_PARAMETER;
310 goto done;
313 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
314 keystr);
316 DEBUG(10, ("reading domain range for key %s\n", keystr));
317 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
318 if (!NT_STATUS_IS_OK(status)) {
319 DEBUG(1, ("Failed to read database for key '%s': %s\n",
320 keystr, nt_errstr(status)));
321 goto done;
324 status = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
325 if (!NT_STATUS_IS_OK(status)) {
326 DEBUG(1, ("Failed to read global configuration"));
327 goto done;
329 range->low_id = globalcfg->minvalue
330 + range->rangenum * globalcfg->rangesize;
332 TALLOC_FREE(globalcfg);
333 done:
334 return status;
337 NTSTATUS idmap_autorid_getrange(struct db_context *db,
338 const char *domsid,
339 uint32_t domain_range_index,
340 uint32_t *rangenum,
341 uint32_t *low_id)
343 NTSTATUS status;
344 struct autorid_range_config range;
346 if (rangenum == NULL) {
347 return NT_STATUS_INVALID_PARAMETER;
350 ZERO_STRUCT(range);
351 fstrcpy(range.domsid, domsid);
352 range.domain_range_index = domain_range_index;
354 status = idmap_autorid_getrange_int(db, &range);
355 if (!NT_STATUS_IS_OK(status)) {
356 return status;
359 *rangenum = range.rangenum;
361 if (low_id != NULL) {
362 *low_id = range.low_id;
365 return NT_STATUS_OK;
368 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
369 struct autorid_range_config *range,
370 bool read_only)
372 NTSTATUS ret;
374 ret = idmap_autorid_getrange_int(db, range);
375 if (!NT_STATUS_IS_OK(ret)) {
376 if (read_only) {
377 return NT_STATUS_NOT_FOUND;
380 ret = idmap_autorid_acquire_range(db, range);
383 DEBUG(10, ("Using range #%d for domain %s "
384 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
385 range->rangenum, range->domsid, range->domain_range_index,
386 range->low_id));
388 return ret;
391 /* initialize the given HWM to 0 if it does not exist yet */
392 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
394 NTSTATUS status;
395 uint32_t hwmval;
397 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
398 if (NT_STATUS_IS_OK(status)) {
399 DEBUG(1, ("HWM (%s) already initialized in autorid database "
400 "(value %"PRIu32").\n", hwm, hwmval));
401 return NT_STATUS_OK;
403 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
404 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
405 "database: %s\n", hwm, nt_errstr(status)));
406 return status;
409 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
410 if (!NT_STATUS_IS_OK(status)) {
411 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
412 "%s\n", hwm, nt_errstr(status)));
413 return NT_STATUS_INTERNAL_DB_ERROR;
416 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
418 return NT_STATUS_OK;
422 * Delete a domain#index <-> range mapping from the database.
423 * The mapping is specified by the sid and index.
424 * If force == true, invalid mapping records are deleted as far
425 * as possible, otherwise they are left untouched.
428 struct idmap_autorid_delete_range_by_sid_ctx {
429 const char *domsid;
430 uint32_t domain_range_index;
431 bool force;
434 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
435 void *private_data)
437 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
438 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
439 const char *domsid;
440 uint32_t domain_range_index;
441 uint32_t rangenum;
442 char *keystr;
443 char *range_keystr;
444 TDB_DATA data;
445 NTSTATUS status;
446 TALLOC_CTX *frame = talloc_stackframe();
447 bool is_valid_range_mapping = true;
448 bool force;
450 domsid = ctx->domsid;
451 domain_range_index = ctx->domain_range_index;
452 force = ctx->force;
454 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
455 domain_range_index);
456 if (keystr == NULL) {
457 status = NT_STATUS_NO_MEMORY;
458 goto done;
461 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
462 if (!NT_STATUS_IS_OK(status)) {
463 goto done;
466 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
467 if (range_keystr == NULL) {
468 status = NT_STATUS_NO_MEMORY;
469 goto done;
472 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
473 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
474 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
475 keystr, range_keystr));
476 is_valid_range_mapping = false;
477 } else if (!NT_STATUS_IS_OK(status)) {
478 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
479 keystr, range_keystr, nt_errstr(status)));
480 goto done;
481 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
482 != 0)
484 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
485 keystr, range_keystr, (const char *)data.dptr));
486 is_valid_range_mapping = false;
489 if (!is_valid_range_mapping && !force) {
490 DEBUG(10, ("Not deleting invalid mapping, since not in force "
491 "mode.\n"));
492 status = NT_STATUS_FILE_INVALID;
493 goto done;
496 status = dbwrap_delete_bystring(db, keystr);
497 if (!NT_STATUS_IS_OK(status)) {
498 DEBUG(1, ("Deletion of '%s' failed: %s\n",
499 keystr, nt_errstr(status)));
500 goto done;
503 if (!is_valid_range_mapping) {
504 goto done;
507 status = dbwrap_delete_bystring(db, range_keystr);
508 if (!NT_STATUS_IS_OK(status)) {
509 DEBUG(1, ("Deletion of '%s' failed: %s\n",
510 range_keystr, nt_errstr(status)));
511 goto done;
514 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
515 range_keystr));
517 done:
518 TALLOC_FREE(frame);
519 return status;
522 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
523 const char *domsid,
524 uint32_t domain_range_index,
525 bool force)
527 NTSTATUS status;
528 struct idmap_autorid_delete_range_by_sid_ctx ctx;
530 ctx.domain_range_index = domain_range_index;
531 ctx.domsid = domsid;
532 ctx.force = force;
534 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
535 &ctx);
536 return status;
540 * Delete a domain#index <-> range mapping from the database.
541 * The mapping is specified by the range number.
542 * If force == true, invalid mapping records are deleted as far
543 * as possible, otherwise they are left untouched.
545 struct idmap_autorid_delete_range_by_num_ctx {
546 uint32_t rangenum;
547 bool force;
550 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
551 void *private_data)
553 struct idmap_autorid_delete_range_by_num_ctx *ctx =
554 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
555 uint32_t rangenum;
556 char *keystr;
557 char *range_keystr;
558 TDB_DATA val;
559 NTSTATUS status;
560 TALLOC_CTX *frame = talloc_stackframe();
561 bool is_valid_range_mapping = true;
562 bool force;
564 rangenum = ctx->rangenum;
565 force = ctx->force;
567 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
568 if (range_keystr == NULL) {
569 status = NT_STATUS_NO_MEMORY;
570 goto done;
573 ZERO_STRUCT(val);
575 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
576 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
577 DEBUG(10, ("Did not find range '%s' in database.\n",
578 range_keystr));
579 goto done;
580 } else if (!NT_STATUS_IS_OK(status)) {
581 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
582 goto done;
585 if (val.dptr == NULL) {
586 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
587 range_keystr));
588 is_valid_range_mapping = false;
589 } else {
590 uint32_t reverse_rangenum = 0;
592 keystr = (char *)val.dptr;
594 status = dbwrap_fetch_uint32_bystring(db, keystr,
595 &reverse_rangenum);
596 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
597 DEBUG(1, ("Incomplete mapping %s -> %s: "
598 "no backward mapping\n",
599 range_keystr, keystr));
600 is_valid_range_mapping = false;
601 } else if (!NT_STATUS_IS_OK(status)) {
602 DEBUG(1, ("Error fetching reverse mapping for "
603 "%s -> %s: %s\n",
604 range_keystr, keystr, nt_errstr(status)));
605 goto done;
606 } else if (rangenum != reverse_rangenum) {
607 is_valid_range_mapping = false;
611 if (!is_valid_range_mapping && !force) {
612 DEBUG(10, ("Not deleting invalid mapping, since not in force "
613 "mode.\n"));
614 status = NT_STATUS_FILE_INVALID;
615 goto done;
618 status = dbwrap_delete_bystring(db, range_keystr);
619 if (!NT_STATUS_IS_OK(status)) {
620 DEBUG(1, ("Deletion of '%s' failed: %s\n",
621 range_keystr, nt_errstr(status)));
622 goto done;
625 if (!is_valid_range_mapping) {
626 goto done;
629 status = dbwrap_delete_bystring(db, keystr);
630 if (!NT_STATUS_IS_OK(status)) {
631 DEBUG(1, ("Deletion of '%s' failed: %s\n",
632 keystr, nt_errstr(status)));
633 goto done;
636 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
637 keystr));
639 done:
640 talloc_free(frame);
641 return status;
644 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
645 uint32_t rangenum,
646 bool force)
648 NTSTATUS status;
649 struct idmap_autorid_delete_range_by_num_ctx ctx;
651 ctx.rangenum = rangenum;
652 ctx.force = force;
654 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
655 &ctx);
656 return status;
660 * open and initialize the database which stores the ranges for the domains
662 NTSTATUS idmap_autorid_db_init(const char *path,
663 TALLOC_CTX *mem_ctx,
664 struct db_context **db)
666 NTSTATUS status;
668 if (*db != NULL) {
669 /* its already open */
670 return NT_STATUS_OK;
673 /* Open idmap repository */
674 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
675 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
677 if (*db == NULL) {
678 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
679 return NT_STATUS_UNSUCCESSFUL;
682 /* Initialize high water mark for the currently used range to 0 */
684 status = idmap_autorid_init_hwm(*db, HWM);
685 NT_STATUS_NOT_OK_RETURN(status);
687 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_UID);
688 NT_STATUS_NOT_OK_RETURN(status);
690 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_GID);
692 return status;
695 struct idmap_autorid_fetch_config_state {
696 TALLOC_CTX *mem_ctx;
697 char *configstr;
700 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
701 void *private_data)
703 struct idmap_autorid_fetch_config_state *state;
705 state = (struct idmap_autorid_fetch_config_state *)private_data;
708 * strndup because we have non-nullterminated strings in the db
710 state->configstr = talloc_strndup(
711 state->mem_ctx, (const char *)value.dptr, value.dsize);
714 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
715 char **result)
717 TDB_DATA key;
718 NTSTATUS status;
719 struct idmap_autorid_fetch_config_state state;
721 if (result == NULL) {
722 return NT_STATUS_INVALID_PARAMETER;
725 key = string_term_tdb_data(CONFIGKEY);
727 state.mem_ctx = mem_ctx;
728 state.configstr = NULL;
730 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
731 &state);
732 if (!NT_STATUS_IS_OK(status)) {
733 DEBUG(1, ("Error while retrieving config: %s\n",
734 nt_errstr(status)));
735 return status;
738 if (state.configstr == NULL) {
739 DEBUG(1, ("Error while retrieving config\n"));
740 return NT_STATUS_NO_MEMORY;
743 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
745 *result = state.configstr;
746 return NT_STATUS_OK;
749 bool idmap_autorid_parse_configstr(const char *configstr,
750 struct autorid_global_config *cfg)
752 unsigned long minvalue, rangesize, maxranges;
754 if (sscanf(configstr,
755 "minvalue:%lu rangesize:%lu maxranges:%lu",
756 &minvalue, &rangesize, &maxranges) != 3) {
757 DEBUG(1,
758 ("Found invalid configuration data. "
759 "Creating new config\n"));
760 return false;
763 cfg->minvalue = minvalue;
764 cfg->rangesize = rangesize;
765 cfg->maxranges = maxranges;
767 return true;
770 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
771 TALLOC_CTX *mem_ctx,
772 struct autorid_global_config **result)
774 struct autorid_global_config *cfg;
775 NTSTATUS status;
776 bool ok;
777 char *configstr = NULL;
779 if (result == NULL) {
780 return NT_STATUS_INVALID_PARAMETER;
783 status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
784 if (!NT_STATUS_IS_OK(status)) {
785 return status;
788 cfg = talloc_zero(mem_ctx, struct autorid_global_config);
789 if (cfg == NULL) {
790 return NT_STATUS_NO_MEMORY;
793 ok = idmap_autorid_parse_configstr(configstr, cfg);
794 if (!ok) {
795 talloc_free(cfg);
796 return NT_STATUS_INVALID_PARAMETER;
799 DEBUG(10, ("Loaded previously stored configuration "
800 "minvalue:%d rangesize:%d\n",
801 cfg->minvalue, cfg->rangesize));
803 *result = cfg;
805 return NT_STATUS_OK;
808 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
809 struct autorid_global_config *cfg)
812 struct autorid_global_config *storedconfig = NULL;
813 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
814 TDB_DATA data;
815 char *cfgstr;
816 uint32_t hwm;
817 TALLOC_CTX *frame = talloc_stackframe();
819 DEBUG(10, ("New configuration provided for storing is "
820 "minvalue:%d rangesize:%d maxranges:%d\n",
821 cfg->minvalue, cfg->rangesize, cfg->maxranges));
823 if (cfg->rangesize < 2000) {
824 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
825 goto done;
828 if (cfg->maxranges == 0) {
829 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
830 "Must have at least one range available.\n"));
831 goto done;
834 status = idmap_autorid_loadconfig(db, frame, &storedconfig);
835 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
836 DEBUG(5, ("No configuration found. Storing initial "
837 "configuration.\n"));
838 } else if (!NT_STATUS_IS_OK(status)) {
839 goto done;
842 /* did the minimum value or rangesize change? */
843 if (storedconfig &&
844 ((storedconfig->minvalue != cfg->minvalue) ||
845 (storedconfig->rangesize != cfg->rangesize)))
847 DEBUG(1, ("New configuration values for rangesize or "
848 "minimum uid value conflict with previously "
849 "used values! Not storing new config.\n"));
850 status = NT_STATUS_INVALID_PARAMETER;
851 goto done;
854 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
855 if (!NT_STATUS_IS_OK(status)) {
856 DEBUG(1, ("Fatal error while fetching current "
857 "HWM value: %s\n", nt_errstr(status)));
858 status = NT_STATUS_INTERNAL_ERROR;
859 goto done;
863 * has the highest uid value been reduced to setting that is not
864 * sufficient any more for already existing ranges?
866 if (hwm > cfg->maxranges) {
867 DEBUG(1, ("New upper uid limit is too low to cover "
868 "existing mappings! Not storing new config.\n"));
869 status = NT_STATUS_INVALID_PARAMETER;
870 goto done;
873 cfgstr =
874 talloc_asprintf(frame,
875 "minvalue:%u rangesize:%u maxranges:%u",
876 cfg->minvalue, cfg->rangesize, cfg->maxranges);
878 if (cfgstr == NULL) {
879 status = NT_STATUS_NO_MEMORY;
880 goto done;
883 data = string_tdb_data(cfgstr);
885 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
887 done:
888 TALLOC_FREE(frame);
889 return status;
892 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
893 const char *configstr)
895 bool ok;
896 NTSTATUS status;
897 struct autorid_global_config cfg;
899 ok = idmap_autorid_parse_configstr(configstr, &cfg);
900 if (!ok) {
901 return NT_STATUS_INVALID_PARAMETER;
904 status = idmap_autorid_saveconfig(db, &cfg);
905 return status;
910 * iteration: Work on all range mappings for a given domain
913 struct domain_range_visitor_ctx {
914 const char *domsid;
915 NTSTATUS (*fn)(struct db_context *db,
916 const char *domsid,
917 uint32_t index,
918 uint32_t rangenum,
919 void *private_data);
920 void *private_data;
921 int count; /* number of records worked on */
924 static int idmap_autorid_visit_domain_range(struct db_record *rec,
925 void *private_data)
927 struct domain_range_visitor_ctx *vi;
928 char *domsid;
929 char *sep;
930 uint32_t range_index = 0;
931 uint32_t rangenum = 0;
932 TDB_DATA key, value;
933 NTSTATUS status;
934 int ret = 0;
935 struct db_context *db;
937 vi = talloc_get_type_abort(private_data,
938 struct domain_range_visitor_ctx);
940 key = dbwrap_record_get_key(rec);
943 * split string "<sid>[#<index>]" into sid string and index number
946 domsid = (char *)key.dptr;
948 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
949 domsid));
951 sep = strrchr(domsid, '#');
952 if (sep != NULL) {
953 char *index_str;
954 *sep = '\0';
955 index_str = sep+1;
956 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
957 DEBUG(10, ("Found separator '#' but '%s' is not a "
958 "valid range index. Skipping record\n",
959 index_str));
960 goto done;
964 if (!idmap_autorid_validate_sid(domsid)) {
965 DEBUG(10, ("String '%s' is not a valid sid. "
966 "Skipping record.\n", domsid));
967 goto done;
970 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
971 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
972 domsid, vi->domsid));
973 goto done;
976 value = dbwrap_record_get_value(rec);
978 if (value.dsize != sizeof(uint32_t)) {
979 /* it might be a mapping of a well known sid */
980 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
981 "skipping.\n", (unsigned)value.dsize, vi->domsid));
982 goto done;
985 rangenum = IVAL(value.dptr, 0);
987 db = dbwrap_record_get_db(rec);
989 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
990 if (!NT_STATUS_IS_OK(status)) {
991 ret = -1;
992 goto done;
995 vi->count++;
996 ret = 0;
998 done:
999 return ret;
1002 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1003 const char *domsid,
1004 NTSTATUS (*fn)(struct db_context *db,
1005 const char *domsid,
1006 uint32_t index,
1007 uint32_t rangnum,
1008 void *private_data),
1009 void *private_data,
1010 int *count,
1011 NTSTATUS (*traverse)(struct db_context *db,
1012 int (*f)(struct db_record *, void *),
1013 void *private_data,
1014 int *count))
1016 NTSTATUS status;
1017 struct domain_range_visitor_ctx *vi;
1018 TALLOC_CTX *frame = talloc_stackframe();
1020 if (domsid == NULL) {
1021 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1024 if (fn == NULL) {
1025 DEBUG(1, ("Error: missing visitor callback\n"));
1026 status = NT_STATUS_INVALID_PARAMETER;
1027 goto done;
1030 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1031 if (vi == NULL) {
1032 status = NT_STATUS_NO_MEMORY;
1033 goto done;
1036 vi->domsid = domsid;
1037 vi->fn = fn;
1038 vi->private_data = private_data;
1040 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1041 if (!NT_STATUS_IS_OK(status)) {
1042 goto done;
1045 if (count != NULL) {
1046 *count = vi->count;
1049 done:
1050 talloc_free(frame);
1051 return status;
1054 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1055 const char *domsid,
1056 NTSTATUS (*fn)(struct db_context *db,
1057 const char *domsid,
1058 uint32_t index,
1059 uint32_t rangenum,
1060 void *private_data),
1061 void *private_data,
1062 int *count)
1064 NTSTATUS status;
1066 status = idmap_autorid_iterate_domain_ranges_int(db,
1067 domsid,
1069 private_data,
1070 count,
1071 dbwrap_traverse);
1073 return status;
1077 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1078 const char *domsid,
1079 NTSTATUS (*fn)(struct db_context *db,
1080 const char *domsid,
1081 uint32_t index,
1082 uint32_t rangenum,
1083 void *count),
1084 void *private_data,
1085 int *count)
1087 NTSTATUS status;
1089 status = idmap_autorid_iterate_domain_ranges_int(db,
1090 domsid,
1092 private_data,
1093 count,
1094 dbwrap_traverse_read);
1096 return status;
1101 * Delete all ranges configured for a given domain
1104 struct delete_domain_ranges_visitor_ctx {
1105 bool force;
1108 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1109 struct db_context *db,
1110 const char *domsid,
1111 uint32_t domain_range_index,
1112 uint32_t rangenum,
1113 void *private_data)
1115 struct delete_domain_ranges_visitor_ctx *ctx;
1116 NTSTATUS status;
1118 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1120 status = idmap_autorid_delete_range_by_sid(
1121 db, domsid, domain_range_index, ctx->force);
1122 return status;
1125 struct idmap_autorid_delete_domain_ranges_ctx {
1126 const char *domsid;
1127 bool force;
1128 int count; /* output: count records operated on */
1131 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1132 void *private_data)
1134 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1135 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1136 int count;
1137 NTSTATUS status;
1139 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1141 ZERO_STRUCT(visitor_ctx);
1142 visitor_ctx.force = ctx->force;
1144 status = idmap_autorid_iterate_domain_ranges(db,
1145 ctx->domsid,
1146 idmap_autorid_delete_domain_ranges_visitor,
1147 &visitor_ctx,
1148 &count);
1149 if (!NT_STATUS_IS_OK(status)) {
1150 return status;
1153 ctx->count = count;
1155 return NT_STATUS_OK;
1158 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1159 const char *domsid,
1160 bool force,
1161 int *count)
1163 NTSTATUS status;
1164 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1166 ZERO_STRUCT(ctx);
1167 ctx.domsid = domsid;
1168 ctx.force = force;
1170 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1171 &ctx);
1172 if (!NT_STATUS_IS_OK(status)) {
1173 return status;
1176 *count = ctx.count;
1178 return NT_STATUS_OK;