autorid: store hwm as uint32_t in idmap_autorid_init_hwm()
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blob190999eb796529e8572eb320759e62c775a61483
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_EQUAL(status, NT_STATUS_NOT_FOUND)) {
399 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
400 if (!NT_STATUS_IS_OK(status)) {
401 DEBUG(0,
402 ("Unable to initialise HWM (%s) in autorid "
403 "database: %s\n", hwm, nt_errstr(status)));
404 return NT_STATUS_INTERNAL_DB_ERROR;
406 } else if (!NT_STATUS_IS_OK(status)) {
407 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
408 "database: %s\n", hwm, nt_errstr(status)));
409 return status;
412 return NT_STATUS_OK;
416 * Delete a domain#index <-> range mapping from the database.
417 * The mapping is specified by the sid and index.
418 * If force == true, invalid mapping records are deleted as far
419 * as possible, otherwise they are left untouched.
422 struct idmap_autorid_delete_range_by_sid_ctx {
423 const char *domsid;
424 uint32_t domain_range_index;
425 bool force;
428 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
429 void *private_data)
431 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
432 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
433 const char *domsid;
434 uint32_t domain_range_index;
435 uint32_t rangenum;
436 char *keystr;
437 char *range_keystr;
438 TDB_DATA data;
439 NTSTATUS status;
440 TALLOC_CTX *frame = talloc_stackframe();
441 bool is_valid_range_mapping = true;
442 bool force;
444 domsid = ctx->domsid;
445 domain_range_index = ctx->domain_range_index;
446 force = ctx->force;
448 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
449 domain_range_index);
450 if (keystr == NULL) {
451 status = NT_STATUS_NO_MEMORY;
452 goto done;
455 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
456 if (!NT_STATUS_IS_OK(status)) {
457 goto done;
460 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
461 if (range_keystr == NULL) {
462 status = NT_STATUS_NO_MEMORY;
463 goto done;
466 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
467 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
468 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
469 keystr, range_keystr));
470 is_valid_range_mapping = false;
471 } else if (!NT_STATUS_IS_OK(status)) {
472 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
473 keystr, range_keystr, nt_errstr(status)));
474 goto done;
475 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
476 != 0)
478 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
479 keystr, range_keystr, (const char *)data.dptr));
480 is_valid_range_mapping = false;
483 if (!is_valid_range_mapping && !force) {
484 DEBUG(10, ("Not deleting invalid mapping, since not in force "
485 "mode.\n"));
486 status = NT_STATUS_FILE_INVALID;
487 goto done;
490 status = dbwrap_delete_bystring(db, keystr);
491 if (!NT_STATUS_IS_OK(status)) {
492 DEBUG(1, ("Deletion of '%s' failed: %s\n",
493 keystr, nt_errstr(status)));
494 goto done;
497 if (!is_valid_range_mapping) {
498 goto done;
501 status = dbwrap_delete_bystring(db, range_keystr);
502 if (!NT_STATUS_IS_OK(status)) {
503 DEBUG(1, ("Deletion of '%s' failed: %s\n",
504 range_keystr, nt_errstr(status)));
505 goto done;
508 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
509 range_keystr));
511 done:
512 TALLOC_FREE(frame);
513 return status;
516 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
517 const char *domsid,
518 uint32_t domain_range_index,
519 bool force)
521 NTSTATUS status;
522 struct idmap_autorid_delete_range_by_sid_ctx ctx;
524 ctx.domain_range_index = domain_range_index;
525 ctx.domsid = domsid;
526 ctx.force = force;
528 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
529 &ctx);
530 return status;
534 * Delete a domain#index <-> range mapping from the database.
535 * The mapping is specified by the range number.
536 * If force == true, invalid mapping records are deleted as far
537 * as possible, otherwise they are left untouched.
539 struct idmap_autorid_delete_range_by_num_ctx {
540 uint32_t rangenum;
541 bool force;
544 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
545 void *private_data)
547 struct idmap_autorid_delete_range_by_num_ctx *ctx =
548 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
549 uint32_t rangenum;
550 char *keystr;
551 char *range_keystr;
552 TDB_DATA val;
553 NTSTATUS status;
554 TALLOC_CTX *frame = talloc_stackframe();
555 bool is_valid_range_mapping = true;
556 bool force;
558 rangenum = ctx->rangenum;
559 force = ctx->force;
561 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
562 if (range_keystr == NULL) {
563 status = NT_STATUS_NO_MEMORY;
564 goto done;
567 ZERO_STRUCT(val);
569 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
570 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
571 DEBUG(10, ("Did not find range '%s' in database.\n",
572 range_keystr));
573 goto done;
574 } else if (!NT_STATUS_IS_OK(status)) {
575 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
576 goto done;
579 if (val.dptr == NULL) {
580 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
581 range_keystr));
582 is_valid_range_mapping = false;
583 } else {
584 uint32_t reverse_rangenum = 0;
586 keystr = (char *)val.dptr;
588 status = dbwrap_fetch_uint32_bystring(db, keystr,
589 &reverse_rangenum);
590 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
591 DEBUG(1, ("Incomplete mapping %s -> %s: "
592 "no backward mapping\n",
593 range_keystr, keystr));
594 is_valid_range_mapping = false;
595 } else if (!NT_STATUS_IS_OK(status)) {
596 DEBUG(1, ("Error fetching reverse mapping for "
597 "%s -> %s: %s\n",
598 range_keystr, keystr, nt_errstr(status)));
599 goto done;
600 } else if (rangenum != reverse_rangenum) {
601 is_valid_range_mapping = false;
605 if (!is_valid_range_mapping && !force) {
606 DEBUG(10, ("Not deleting invalid mapping, since not in force "
607 "mode.\n"));
608 status = NT_STATUS_FILE_INVALID;
609 goto done;
612 status = dbwrap_delete_bystring(db, range_keystr);
613 if (!NT_STATUS_IS_OK(status)) {
614 DEBUG(1, ("Deletion of '%s' failed: %s\n",
615 range_keystr, nt_errstr(status)));
616 goto done;
619 if (!is_valid_range_mapping) {
620 goto done;
623 status = dbwrap_delete_bystring(db, keystr);
624 if (!NT_STATUS_IS_OK(status)) {
625 DEBUG(1, ("Deletion of '%s' failed: %s\n",
626 keystr, nt_errstr(status)));
627 goto done;
630 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
631 keystr));
633 done:
634 talloc_free(frame);
635 return status;
638 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
639 uint32_t rangenum,
640 bool force)
642 NTSTATUS status;
643 struct idmap_autorid_delete_range_by_num_ctx ctx;
645 ctx.rangenum = rangenum;
646 ctx.force = force;
648 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
649 &ctx);
650 return status;
654 * open and initialize the database which stores the ranges for the domains
656 NTSTATUS idmap_autorid_db_init(const char *path,
657 TALLOC_CTX *mem_ctx,
658 struct db_context **db)
660 NTSTATUS status;
662 if (*db != NULL) {
663 /* its already open */
664 return NT_STATUS_OK;
667 /* Open idmap repository */
668 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
669 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
671 if (*db == NULL) {
672 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
673 return NT_STATUS_UNSUCCESSFUL;
676 /* Initialize high water mark for the currently used range to 0 */
678 status = idmap_autorid_init_hwm(*db, HWM);
679 NT_STATUS_NOT_OK_RETURN(status);
681 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_UID);
682 NT_STATUS_NOT_OK_RETURN(status);
684 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_GID);
686 return status;
689 struct idmap_autorid_fetch_config_state {
690 TALLOC_CTX *mem_ctx;
691 char *configstr;
694 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
695 void *private_data)
697 struct idmap_autorid_fetch_config_state *state;
699 state = (struct idmap_autorid_fetch_config_state *)private_data;
702 * strndup because we have non-nullterminated strings in the db
704 state->configstr = talloc_strndup(
705 state->mem_ctx, (const char *)value.dptr, value.dsize);
708 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
709 char **result)
711 TDB_DATA key;
712 NTSTATUS status;
713 struct idmap_autorid_fetch_config_state state;
715 if (result == NULL) {
716 return NT_STATUS_INVALID_PARAMETER;
719 key = string_term_tdb_data(CONFIGKEY);
721 state.mem_ctx = mem_ctx;
722 state.configstr = NULL;
724 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
725 &state);
726 if (!NT_STATUS_IS_OK(status)) {
727 DEBUG(1, ("Error while retrieving config: %s\n",
728 nt_errstr(status)));
729 return status;
732 if (state.configstr == NULL) {
733 DEBUG(1, ("Error while retrieving config\n"));
734 return NT_STATUS_NO_MEMORY;
737 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
739 *result = state.configstr;
740 return NT_STATUS_OK;
743 bool idmap_autorid_parse_configstr(const char *configstr,
744 struct autorid_global_config *cfg)
746 unsigned long minvalue, rangesize, maxranges;
748 if (sscanf(configstr,
749 "minvalue:%lu rangesize:%lu maxranges:%lu",
750 &minvalue, &rangesize, &maxranges) != 3) {
751 DEBUG(1,
752 ("Found invalid configuration data. "
753 "Creating new config\n"));
754 return false;
757 cfg->minvalue = minvalue;
758 cfg->rangesize = rangesize;
759 cfg->maxranges = maxranges;
761 return true;
764 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
765 TALLOC_CTX *mem_ctx,
766 struct autorid_global_config **result)
768 struct autorid_global_config *cfg;
769 NTSTATUS status;
770 bool ok;
771 char *configstr = NULL;
773 if (result == NULL) {
774 return NT_STATUS_INVALID_PARAMETER;
777 status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
778 if (!NT_STATUS_IS_OK(status)) {
779 return status;
782 cfg = talloc_zero(mem_ctx, struct autorid_global_config);
783 if (cfg == NULL) {
784 return NT_STATUS_NO_MEMORY;
787 ok = idmap_autorid_parse_configstr(configstr, cfg);
788 if (!ok) {
789 talloc_free(cfg);
790 return NT_STATUS_INVALID_PARAMETER;
793 DEBUG(10, ("Loaded previously stored configuration "
794 "minvalue:%d rangesize:%d\n",
795 cfg->minvalue, cfg->rangesize));
797 *result = cfg;
799 return NT_STATUS_OK;
802 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
803 struct autorid_global_config *cfg)
806 struct autorid_global_config *storedconfig = NULL;
807 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
808 TDB_DATA data;
809 char *cfgstr;
810 uint32_t hwm;
811 TALLOC_CTX *frame = talloc_stackframe();
813 DEBUG(10, ("New configuration provided for storing is "
814 "minvalue:%d rangesize:%d maxranges:%d\n",
815 cfg->minvalue, cfg->rangesize, cfg->maxranges));
817 if (cfg->rangesize < 2000) {
818 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
819 goto done;
822 if (cfg->maxranges == 0) {
823 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
824 "Must have at least one range available.\n"));
825 goto done;
828 status = idmap_autorid_loadconfig(db, frame, &storedconfig);
829 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
830 DEBUG(5, ("No configuration found. Storing initial "
831 "configuration.\n"));
832 } else if (!NT_STATUS_IS_OK(status)) {
833 goto done;
836 /* did the minimum value or rangesize change? */
837 if (storedconfig &&
838 ((storedconfig->minvalue != cfg->minvalue) ||
839 (storedconfig->rangesize != cfg->rangesize)))
841 DEBUG(1, ("New configuration values for rangesize or "
842 "minimum uid value conflict with previously "
843 "used values! Not storing new config.\n"));
844 status = NT_STATUS_INVALID_PARAMETER;
845 goto done;
848 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
849 if (!NT_STATUS_IS_OK(status)) {
850 DEBUG(1, ("Fatal error while fetching current "
851 "HWM value: %s\n", nt_errstr(status)));
852 status = NT_STATUS_INTERNAL_ERROR;
853 goto done;
857 * has the highest uid value been reduced to setting that is not
858 * sufficient any more for already existing ranges?
860 if (hwm > cfg->maxranges) {
861 DEBUG(1, ("New upper uid limit is too low to cover "
862 "existing mappings! Not storing new config.\n"));
863 status = NT_STATUS_INVALID_PARAMETER;
864 goto done;
867 cfgstr =
868 talloc_asprintf(frame,
869 "minvalue:%u rangesize:%u maxranges:%u",
870 cfg->minvalue, cfg->rangesize, cfg->maxranges);
872 if (cfgstr == NULL) {
873 status = NT_STATUS_NO_MEMORY;
874 goto done;
877 data = string_tdb_data(cfgstr);
879 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
881 done:
882 TALLOC_FREE(frame);
883 return status;
886 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
887 const char *configstr)
889 bool ok;
890 NTSTATUS status;
891 struct autorid_global_config cfg;
893 ok = idmap_autorid_parse_configstr(configstr, &cfg);
894 if (!ok) {
895 return NT_STATUS_INVALID_PARAMETER;
898 status = idmap_autorid_saveconfig(db, &cfg);
899 return status;
904 * iteration: Work on all range mappings for a given domain
907 struct domain_range_visitor_ctx {
908 const char *domsid;
909 NTSTATUS (*fn)(struct db_context *db,
910 const char *domsid,
911 uint32_t index,
912 uint32_t rangenum,
913 void *private_data);
914 void *private_data;
915 int count; /* number of records worked on */
918 static int idmap_autorid_visit_domain_range(struct db_record *rec,
919 void *private_data)
921 struct domain_range_visitor_ctx *vi;
922 char *domsid;
923 char *sep;
924 uint32_t range_index = 0;
925 uint32_t rangenum = 0;
926 TDB_DATA key, value;
927 NTSTATUS status;
928 int ret = 0;
929 struct db_context *db;
931 vi = talloc_get_type_abort(private_data,
932 struct domain_range_visitor_ctx);
934 key = dbwrap_record_get_key(rec);
937 * split string "<sid>[#<index>]" into sid string and index number
940 domsid = (char *)key.dptr;
942 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
943 domsid));
945 sep = strrchr(domsid, '#');
946 if (sep != NULL) {
947 char *index_str;
948 *sep = '\0';
949 index_str = sep+1;
950 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
951 DEBUG(10, ("Found separator '#' but '%s' is not a "
952 "valid range index. Skipping record\n",
953 index_str));
954 goto done;
958 if (!idmap_autorid_validate_sid(domsid)) {
959 DEBUG(10, ("String '%s' is not a valid sid. "
960 "Skipping record.\n", domsid));
961 goto done;
964 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
965 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
966 domsid, vi->domsid));
967 goto done;
970 value = dbwrap_record_get_value(rec);
972 if (value.dsize != sizeof(uint32_t)) {
973 /* it might be a mapping of a well known sid */
974 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
975 "skipping.\n", (unsigned)value.dsize, vi->domsid));
976 goto done;
979 rangenum = IVAL(value.dptr, 0);
981 db = dbwrap_record_get_db(rec);
983 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
984 if (!NT_STATUS_IS_OK(status)) {
985 ret = -1;
986 goto done;
989 vi->count++;
990 ret = 0;
992 done:
993 return ret;
996 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
997 const char *domsid,
998 NTSTATUS (*fn)(struct db_context *db,
999 const char *domsid,
1000 uint32_t index,
1001 uint32_t rangnum,
1002 void *private_data),
1003 void *private_data,
1004 int *count,
1005 NTSTATUS (*traverse)(struct db_context *db,
1006 int (*f)(struct db_record *, void *),
1007 void *private_data,
1008 int *count))
1010 NTSTATUS status;
1011 struct domain_range_visitor_ctx *vi;
1012 TALLOC_CTX *frame = talloc_stackframe();
1014 if (domsid == NULL) {
1015 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1018 if (fn == NULL) {
1019 DEBUG(1, ("Error: missing visitor callback\n"));
1020 status = NT_STATUS_INVALID_PARAMETER;
1021 goto done;
1024 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1025 if (vi == NULL) {
1026 status = NT_STATUS_NO_MEMORY;
1027 goto done;
1030 vi->domsid = domsid;
1031 vi->fn = fn;
1032 vi->private_data = private_data;
1034 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 goto done;
1039 if (count != NULL) {
1040 *count = vi->count;
1043 done:
1044 talloc_free(frame);
1045 return status;
1048 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1049 const char *domsid,
1050 NTSTATUS (*fn)(struct db_context *db,
1051 const char *domsid,
1052 uint32_t index,
1053 uint32_t rangenum,
1054 void *private_data),
1055 void *private_data,
1056 int *count)
1058 NTSTATUS status;
1060 status = idmap_autorid_iterate_domain_ranges_int(db,
1061 domsid,
1063 private_data,
1064 count,
1065 dbwrap_traverse);
1067 return status;
1071 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1072 const char *domsid,
1073 NTSTATUS (*fn)(struct db_context *db,
1074 const char *domsid,
1075 uint32_t index,
1076 uint32_t rangenum,
1077 void *count),
1078 void *private_data,
1079 int *count)
1081 NTSTATUS status;
1083 status = idmap_autorid_iterate_domain_ranges_int(db,
1084 domsid,
1086 private_data,
1087 count,
1088 dbwrap_traverse_read);
1090 return status;
1095 * Delete all ranges configured for a given domain
1098 struct delete_domain_ranges_visitor_ctx {
1099 bool force;
1102 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1103 struct db_context *db,
1104 const char *domsid,
1105 uint32_t domain_range_index,
1106 uint32_t rangenum,
1107 void *private_data)
1109 struct delete_domain_ranges_visitor_ctx *ctx;
1110 NTSTATUS status;
1112 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1114 status = idmap_autorid_delete_range_by_sid(
1115 db, domsid, domain_range_index, ctx->force);
1116 return status;
1119 struct idmap_autorid_delete_domain_ranges_ctx {
1120 const char *domsid;
1121 bool force;
1122 int count; /* output: count records operated on */
1125 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1126 void *private_data)
1128 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1129 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1130 int count;
1131 NTSTATUS status;
1133 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1135 ZERO_STRUCT(visitor_ctx);
1136 visitor_ctx.force = ctx->force;
1138 status = idmap_autorid_iterate_domain_ranges(db,
1139 ctx->domsid,
1140 idmap_autorid_delete_domain_ranges_visitor,
1141 &visitor_ctx,
1142 &count);
1143 if (!NT_STATUS_IS_OK(status)) {
1144 return status;
1147 ctx->count = count;
1149 return NT_STATUS_OK;
1152 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1153 const char *domsid,
1154 bool force,
1155 int *count)
1157 NTSTATUS status;
1158 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1160 ZERO_STRUCT(ctx);
1161 ctx.domsid = domsid;
1162 ctx.force = force;
1164 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1165 &ctx);
1166 if (!NT_STATUS_IS_OK(status)) {
1167 return status;
1170 *count = ctx.count;
1172 return NT_STATUS_OK;