autorid: fix uninitialized return code for successful autorid.tdb creation/opening
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blob0d07d3359549d50ffd831a9d7810db612bb5a0c4
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 DEBUG(1, ("Talloc failed!\n"));
189 ret = NT_STATUS_NO_MEMORY;
190 goto error;
193 if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
194 DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
196 if (requested_rangenum < hwm) {
197 ret = NT_STATUS_INVALID_PARAMETER;
198 } else {
199 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
202 goto error;
205 if (requested_rangenum >= hwm) {
207 * requested or automatic range >= HWM:
208 * increment the HWM.
211 /* HWM always contains current max range + 1 */
212 increment = requested_rangenum + 1 - hwm;
214 /* increase the HWM */
215 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
216 increment);
217 if (!NT_STATUS_IS_OK(ret)) {
218 DEBUG(1, ("Fatal error while incrementing the HWM "
219 "value in the database: %s\n",
220 nt_errstr(ret)));
221 goto error;
226 * store away the new mapping in both directions
229 ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
230 if (!NT_STATUS_IS_OK(ret)) {
231 DEBUG(1, ("Fatal error while storing new "
232 "domain->range assignment: %s\n", nt_errstr(ret)));
233 goto error;
236 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
237 if (!numstr) {
238 ret = NT_STATUS_NO_MEMORY;
239 goto error;
242 ret = dbwrap_store_bystring(db, numstr,
243 string_term_tdb_data(keystr), TDB_INSERT);
245 if (!NT_STATUS_IS_OK(ret)) {
246 DEBUG(1, ("Fatal error while storing new "
247 "domain->range assignment: %s\n", nt_errstr(ret)));
248 goto error;
251 DEBUG(5, ("%s new range #%d for domain %s "
252 "(domain_range_index=%"PRIu32")\n",
253 (acquire?"Acquired":"Stored"),
254 requested_rangenum, keystr,
255 range->domain_range_index));
257 range->rangenum = requested_rangenum;
259 range->low_id = globalcfg->minvalue
260 + range->rangenum * globalcfg->rangesize;
262 ret = NT_STATUS_OK;
264 error:
265 talloc_free(mem_ctx);
266 return ret;
269 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
270 struct autorid_range_config *range,
271 bool acquire)
273 NTSTATUS status;
274 struct idmap_autorid_addrange_ctx ctx;
276 ctx.acquire = acquire;
277 ctx.range = range;
279 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
280 return status;
283 NTSTATUS idmap_autorid_setrange(struct db_context *db,
284 const char *domsid,
285 uint32_t domain_range_index,
286 uint32_t rangenum)
288 NTSTATUS status;
289 struct autorid_range_config range;
291 ZERO_STRUCT(range);
292 fstrcpy(range.domsid, domsid);
293 range.domain_range_index = domain_range_index;
294 range.rangenum = rangenum;
296 status = idmap_autorid_addrange(db, &range, false);
297 return status;
300 static NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
301 struct autorid_range_config *range)
303 return idmap_autorid_addrange(db, range, true);
306 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
307 struct autorid_range_config *range)
309 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
310 struct autorid_global_config *globalcfg = NULL;
311 fstring keystr;
313 if (db == NULL || range == NULL) {
314 DEBUG(3, ("Invalid arguments received\n"));
315 goto done;
318 if (!idmap_autorid_validate_sid(range->domsid)) {
319 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
320 status = NT_STATUS_INVALID_PARAMETER;
321 goto done;
324 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
325 keystr);
327 DEBUG(10, ("reading domain range for key %s\n", keystr));
328 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
329 if (!NT_STATUS_IS_OK(status)) {
330 DEBUG(1, ("Failed to read database record for key '%s': %s\n",
331 keystr, nt_errstr(status)));
332 goto done;
335 status = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
336 if (!NT_STATUS_IS_OK(status)) {
337 DEBUG(1, ("Failed to read global configuration"));
338 goto done;
340 range->low_id = globalcfg->minvalue
341 + range->rangenum * globalcfg->rangesize;
343 TALLOC_FREE(globalcfg);
344 done:
345 return status;
348 NTSTATUS idmap_autorid_getrange(struct db_context *db,
349 const char *domsid,
350 uint32_t domain_range_index,
351 uint32_t *rangenum,
352 uint32_t *low_id)
354 NTSTATUS status;
355 struct autorid_range_config range;
357 if (rangenum == NULL) {
358 return NT_STATUS_INVALID_PARAMETER;
361 ZERO_STRUCT(range);
362 fstrcpy(range.domsid, domsid);
363 range.domain_range_index = domain_range_index;
365 status = idmap_autorid_getrange_int(db, &range);
366 if (!NT_STATUS_IS_OK(status)) {
367 return status;
370 *rangenum = range.rangenum;
372 if (low_id != NULL) {
373 *low_id = range.low_id;
376 return NT_STATUS_OK;
379 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
380 struct autorid_range_config *range,
381 bool read_only)
383 NTSTATUS ret;
385 ret = idmap_autorid_getrange_int(db, range);
386 if (!NT_STATUS_IS_OK(ret)) {
387 DEBUG(10, ("Failed to read range config for '%s': %s\n",
388 range->domsid, nt_errstr(ret)));
389 if (read_only) {
390 DEBUG(10, ("Not allocating new range for '%s' because "
391 "read-only is enabled.\n", range->domsid));
392 return NT_STATUS_NOT_FOUND;
395 ret = idmap_autorid_acquire_range(db, range);
398 DEBUG(10, ("Using range #%d for domain %s "
399 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
400 range->rangenum, range->domsid, range->domain_range_index,
401 range->low_id));
403 return ret;
406 /* initialize the given HWM to 0 if it does not exist yet */
407 static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
408 void *private_data)
410 NTSTATUS status;
411 uint32_t hwmval;
412 const char *hwm;
414 hwm = (char *)private_data;
416 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
417 if (NT_STATUS_IS_OK(status)) {
418 DEBUG(1, ("HWM (%s) already initialized in autorid database "
419 "(value %"PRIu32").\n", hwm, hwmval));
420 return NT_STATUS_OK;
422 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
423 DEBUG(0, ("Error fetching HWM (%s) from autorid "
424 "database: %s\n", hwm, nt_errstr(status)));
425 return status;
428 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
429 if (!NT_STATUS_IS_OK(status)) {
430 DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
431 hwm, nt_errstr(status)));
432 return status;
435 return NT_STATUS_OK;
438 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
440 NTSTATUS status;
441 uint32_t hwmval;
443 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
444 if (NT_STATUS_IS_OK(status)) {
445 DEBUG(1, ("HWM (%s) already initialized in autorid database "
446 "(value %"PRIu32").\n", hwm, hwmval));
447 return NT_STATUS_OK;
449 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
450 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
451 "database: %s\n", hwm, nt_errstr(status)));
452 return status;
455 status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
456 (void *)hwm);
457 if (!NT_STATUS_IS_OK(status)) {
458 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
459 "%s\n", hwm, nt_errstr(status)));
460 return NT_STATUS_INTERNAL_DB_ERROR;
463 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
465 return NT_STATUS_OK;
469 * Delete a domain#index <-> range mapping from the database.
470 * The mapping is specified by the sid and index.
471 * If force == true, invalid mapping records are deleted as far
472 * as possible, otherwise they are left untouched.
475 struct idmap_autorid_delete_range_by_sid_ctx {
476 const char *domsid;
477 uint32_t domain_range_index;
478 bool force;
481 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
482 void *private_data)
484 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
485 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
486 const char *domsid;
487 uint32_t domain_range_index;
488 uint32_t rangenum;
489 char *keystr;
490 char *range_keystr;
491 TDB_DATA data;
492 NTSTATUS status;
493 TALLOC_CTX *frame = talloc_stackframe();
494 bool is_valid_range_mapping = true;
495 bool force;
497 domsid = ctx->domsid;
498 domain_range_index = ctx->domain_range_index;
499 force = ctx->force;
501 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
502 domain_range_index);
503 if (keystr == NULL) {
504 status = NT_STATUS_NO_MEMORY;
505 goto done;
508 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
509 if (!NT_STATUS_IS_OK(status)) {
510 goto done;
513 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
514 if (range_keystr == NULL) {
515 status = NT_STATUS_NO_MEMORY;
516 goto done;
519 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
520 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
521 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
522 keystr, range_keystr));
523 is_valid_range_mapping = false;
524 } else if (!NT_STATUS_IS_OK(status)) {
525 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
526 keystr, range_keystr, nt_errstr(status)));
527 goto done;
528 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
529 != 0)
531 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
532 keystr, range_keystr, (const char *)data.dptr));
533 is_valid_range_mapping = false;
536 if (!is_valid_range_mapping && !force) {
537 DEBUG(10, ("Not deleting invalid mapping, since not in force "
538 "mode.\n"));
539 status = NT_STATUS_FILE_INVALID;
540 goto done;
543 status = dbwrap_delete_bystring(db, keystr);
544 if (!NT_STATUS_IS_OK(status)) {
545 DEBUG(1, ("Deletion of '%s' failed: %s\n",
546 keystr, nt_errstr(status)));
547 goto done;
550 if (!is_valid_range_mapping) {
551 goto done;
554 status = dbwrap_delete_bystring(db, range_keystr);
555 if (!NT_STATUS_IS_OK(status)) {
556 DEBUG(1, ("Deletion of '%s' failed: %s\n",
557 range_keystr, nt_errstr(status)));
558 goto done;
561 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
562 range_keystr));
564 done:
565 TALLOC_FREE(frame);
566 return status;
569 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
570 const char *domsid,
571 uint32_t domain_range_index,
572 bool force)
574 NTSTATUS status;
575 struct idmap_autorid_delete_range_by_sid_ctx ctx;
577 ctx.domain_range_index = domain_range_index;
578 ctx.domsid = domsid;
579 ctx.force = force;
581 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
582 &ctx);
583 return status;
587 * Delete a domain#index <-> range mapping from the database.
588 * The mapping is specified by the range number.
589 * If force == true, invalid mapping records are deleted as far
590 * as possible, otherwise they are left untouched.
592 struct idmap_autorid_delete_range_by_num_ctx {
593 uint32_t rangenum;
594 bool force;
597 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
598 void *private_data)
600 struct idmap_autorid_delete_range_by_num_ctx *ctx =
601 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
602 uint32_t rangenum;
603 char *keystr;
604 char *range_keystr;
605 TDB_DATA val;
606 NTSTATUS status;
607 TALLOC_CTX *frame = talloc_stackframe();
608 bool is_valid_range_mapping = true;
609 bool force;
611 rangenum = ctx->rangenum;
612 force = ctx->force;
614 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
615 if (range_keystr == NULL) {
616 status = NT_STATUS_NO_MEMORY;
617 goto done;
620 ZERO_STRUCT(val);
622 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
623 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
624 DEBUG(10, ("Did not find range '%s' in database.\n",
625 range_keystr));
626 goto done;
627 } else if (!NT_STATUS_IS_OK(status)) {
628 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
629 goto done;
632 if (val.dptr == NULL) {
633 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
634 range_keystr));
635 is_valid_range_mapping = false;
636 } else {
637 uint32_t reverse_rangenum = 0;
639 keystr = (char *)val.dptr;
641 status = dbwrap_fetch_uint32_bystring(db, keystr,
642 &reverse_rangenum);
643 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
644 DEBUG(1, ("Incomplete mapping %s -> %s: "
645 "no backward mapping\n",
646 range_keystr, keystr));
647 is_valid_range_mapping = false;
648 } else if (!NT_STATUS_IS_OK(status)) {
649 DEBUG(1, ("Error fetching reverse mapping for "
650 "%s -> %s: %s\n",
651 range_keystr, keystr, nt_errstr(status)));
652 goto done;
653 } else if (rangenum != reverse_rangenum) {
654 is_valid_range_mapping = false;
658 if (!is_valid_range_mapping && !force) {
659 DEBUG(10, ("Not deleting invalid mapping, since not in force "
660 "mode.\n"));
661 status = NT_STATUS_FILE_INVALID;
662 goto done;
665 status = dbwrap_delete_bystring(db, range_keystr);
666 if (!NT_STATUS_IS_OK(status)) {
667 DEBUG(1, ("Deletion of '%s' failed: %s\n",
668 range_keystr, nt_errstr(status)));
669 goto done;
672 if (!is_valid_range_mapping) {
673 goto done;
676 status = dbwrap_delete_bystring(db, keystr);
677 if (!NT_STATUS_IS_OK(status)) {
678 DEBUG(1, ("Deletion of '%s' failed: %s\n",
679 keystr, nt_errstr(status)));
680 goto done;
683 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
684 keystr));
686 done:
687 talloc_free(frame);
688 return status;
691 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
692 uint32_t rangenum,
693 bool force)
695 NTSTATUS status;
696 struct idmap_autorid_delete_range_by_num_ctx ctx;
698 ctx.rangenum = rangenum;
699 ctx.force = force;
701 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
702 &ctx);
703 return status;
707 * Open and possibly create the database.
709 NTSTATUS idmap_autorid_db_open(const char *path,
710 TALLOC_CTX *mem_ctx,
711 struct db_context **db)
713 if (*db != NULL) {
714 /* its already open */
715 return NT_STATUS_OK;
718 /* Open idmap repository */
719 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
720 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
722 if (*db == NULL) {
723 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
724 return NT_STATUS_UNSUCCESSFUL;
727 return NT_STATUS_OK;
731 * Initialize the high watermark records in the database.
733 NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
735 NTSTATUS status;
737 status = idmap_autorid_init_hwm(db, HWM);
738 if (!NT_STATUS_IS_OK(status)) {
739 return status;
742 status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
743 if (!NT_STATUS_IS_OK(status)) {
744 return status;
747 status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
749 return status;
752 NTSTATUS idmap_autorid_db_init(const char *path,
753 TALLOC_CTX *mem_ctx,
754 struct db_context **db)
756 NTSTATUS status;
758 status = idmap_autorid_db_open(path, mem_ctx, db);
759 if (!NT_STATUS_IS_OK(status)) {
760 return status;
763 status = idmap_autorid_init_hwms(*db);
764 return status;
769 struct idmap_autorid_fetch_config_state {
770 TALLOC_CTX *mem_ctx;
771 char *configstr;
774 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
775 void *private_data)
777 struct idmap_autorid_fetch_config_state *state;
779 state = (struct idmap_autorid_fetch_config_state *)private_data;
782 * strndup because we have non-nullterminated strings in the db
784 state->configstr = talloc_strndup(
785 state->mem_ctx, (const char *)value.dptr, value.dsize);
788 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
789 char **result)
791 TDB_DATA key;
792 NTSTATUS status;
793 struct idmap_autorid_fetch_config_state state;
795 if (result == NULL) {
796 return NT_STATUS_INVALID_PARAMETER;
799 key = string_term_tdb_data(CONFIGKEY);
801 state.mem_ctx = mem_ctx;
802 state.configstr = NULL;
804 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
805 &state);
806 if (!NT_STATUS_IS_OK(status)) {
807 DEBUG(1, ("Error while retrieving config: %s\n",
808 nt_errstr(status)));
809 return status;
812 if (state.configstr == NULL) {
813 DEBUG(1, ("Error while retrieving config\n"));
814 return NT_STATUS_NO_MEMORY;
817 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
819 *result = state.configstr;
820 return NT_STATUS_OK;
823 bool idmap_autorid_parse_configstr(const char *configstr,
824 struct autorid_global_config *cfg)
826 unsigned long minvalue, rangesize, maxranges;
828 if (sscanf(configstr,
829 "minvalue:%lu rangesize:%lu maxranges:%lu",
830 &minvalue, &rangesize, &maxranges) != 3) {
831 DEBUG(1,
832 ("Found invalid configuration data. "
833 "Creating new config\n"));
834 return false;
837 cfg->minvalue = minvalue;
838 cfg->rangesize = rangesize;
839 cfg->maxranges = maxranges;
841 return true;
844 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
845 TALLOC_CTX *mem_ctx,
846 struct autorid_global_config **result)
848 struct autorid_global_config *cfg;
849 NTSTATUS status;
850 bool ok;
851 char *configstr = NULL;
853 if (result == NULL) {
854 return NT_STATUS_INVALID_PARAMETER;
857 status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
858 if (!NT_STATUS_IS_OK(status)) {
859 return status;
862 cfg = talloc_zero(mem_ctx, struct autorid_global_config);
863 if (cfg == NULL) {
864 return NT_STATUS_NO_MEMORY;
867 ok = idmap_autorid_parse_configstr(configstr, cfg);
868 if (!ok) {
869 talloc_free(cfg);
870 return NT_STATUS_INVALID_PARAMETER;
873 DEBUG(10, ("Loaded previously stored configuration "
874 "minvalue:%d rangesize:%d\n",
875 cfg->minvalue, cfg->rangesize));
877 *result = cfg;
879 return NT_STATUS_OK;
882 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
883 struct autorid_global_config *cfg)
886 struct autorid_global_config *storedconfig = NULL;
887 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
888 TDB_DATA data;
889 char *cfgstr;
890 uint32_t hwm;
891 TALLOC_CTX *frame = talloc_stackframe();
893 DEBUG(10, ("New configuration provided for storing is "
894 "minvalue:%d rangesize:%d maxranges:%d\n",
895 cfg->minvalue, cfg->rangesize, cfg->maxranges));
897 if (cfg->rangesize < 2000) {
898 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
899 goto done;
902 if (cfg->maxranges == 0) {
903 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
904 "Must have at least one range available.\n"));
905 goto done;
908 status = idmap_autorid_loadconfig(db, frame, &storedconfig);
909 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
910 DEBUG(5, ("No configuration found. Storing initial "
911 "configuration.\n"));
912 } else if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(1, ("Error loading configuration: %s\n",
914 nt_errstr(status)));
915 goto done;
918 /* did the minimum value or rangesize change? */
919 if (storedconfig &&
920 ((storedconfig->minvalue != cfg->minvalue) ||
921 (storedconfig->rangesize != cfg->rangesize)))
923 DEBUG(1, ("New configuration values for rangesize or "
924 "minimum uid value conflict with previously "
925 "used values! Not storing new config.\n"));
926 status = NT_STATUS_INVALID_PARAMETER;
927 goto done;
930 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
931 if (!NT_STATUS_IS_OK(status)) {
932 DEBUG(1, ("Fatal error while fetching current "
933 "HWM value: %s\n", nt_errstr(status)));
934 status = NT_STATUS_INTERNAL_ERROR;
935 goto done;
939 * has the highest uid value been reduced to setting that is not
940 * sufficient any more for already existing ranges?
942 if (hwm > cfg->maxranges) {
943 DEBUG(1, ("New upper uid limit is too low to cover "
944 "existing mappings! Not storing new config.\n"));
945 status = NT_STATUS_INVALID_PARAMETER;
946 goto done;
949 cfgstr =
950 talloc_asprintf(frame,
951 "minvalue:%u rangesize:%u maxranges:%u",
952 cfg->minvalue, cfg->rangesize, cfg->maxranges);
954 if (cfgstr == NULL) {
955 status = NT_STATUS_NO_MEMORY;
956 goto done;
959 data = string_tdb_data(cfgstr);
961 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
963 done:
964 TALLOC_FREE(frame);
965 return status;
968 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
969 const char *configstr)
971 bool ok;
972 NTSTATUS status;
973 struct autorid_global_config cfg;
975 ok = idmap_autorid_parse_configstr(configstr, &cfg);
976 if (!ok) {
977 return NT_STATUS_INVALID_PARAMETER;
980 status = idmap_autorid_saveconfig(db, &cfg);
981 return status;
986 * iteration: Work on all range mappings for a given domain
989 struct domain_range_visitor_ctx {
990 const char *domsid;
991 NTSTATUS (*fn)(struct db_context *db,
992 const char *domsid,
993 uint32_t index,
994 uint32_t rangenum,
995 void *private_data);
996 void *private_data;
997 int count; /* number of records worked on */
1000 static int idmap_autorid_visit_domain_range(struct db_record *rec,
1001 void *private_data)
1003 struct domain_range_visitor_ctx *vi;
1004 char *domsid;
1005 char *sep;
1006 uint32_t range_index = 0;
1007 uint32_t rangenum = 0;
1008 TDB_DATA key, value;
1009 NTSTATUS status;
1010 int ret = 0;
1011 struct db_context *db;
1013 vi = talloc_get_type_abort(private_data,
1014 struct domain_range_visitor_ctx);
1016 key = dbwrap_record_get_key(rec);
1019 * split string "<sid>[#<index>]" into sid string and index number
1022 domsid = (char *)key.dptr;
1024 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1025 domsid));
1027 sep = strrchr(domsid, '#');
1028 if (sep != NULL) {
1029 char *index_str;
1030 *sep = '\0';
1031 index_str = sep+1;
1032 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1033 DEBUG(10, ("Found separator '#' but '%s' is not a "
1034 "valid range index. Skipping record\n",
1035 index_str));
1036 goto done;
1040 if (!idmap_autorid_validate_sid(domsid)) {
1041 DEBUG(10, ("String '%s' is not a valid sid. "
1042 "Skipping record.\n", domsid));
1043 goto done;
1046 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1047 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1048 domsid, vi->domsid));
1049 goto done;
1052 value = dbwrap_record_get_value(rec);
1054 if (value.dsize != sizeof(uint32_t)) {
1055 /* it might be a mapping of a well known sid */
1056 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1057 "skipping.\n", (unsigned)value.dsize, vi->domsid));
1058 goto done;
1061 rangenum = IVAL(value.dptr, 0);
1063 db = dbwrap_record_get_db(rec);
1065 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 ret = -1;
1068 goto done;
1071 vi->count++;
1072 ret = 0;
1074 done:
1075 return ret;
1078 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1079 const char *domsid,
1080 NTSTATUS (*fn)(struct db_context *db,
1081 const char *domsid,
1082 uint32_t index,
1083 uint32_t rangnum,
1084 void *private_data),
1085 void *private_data,
1086 int *count,
1087 NTSTATUS (*traverse)(struct db_context *db,
1088 int (*f)(struct db_record *, void *),
1089 void *private_data,
1090 int *count))
1092 NTSTATUS status;
1093 struct domain_range_visitor_ctx *vi;
1094 TALLOC_CTX *frame = talloc_stackframe();
1096 if (domsid == NULL) {
1097 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1100 if (fn == NULL) {
1101 DEBUG(1, ("Error: missing visitor callback\n"));
1102 status = NT_STATUS_INVALID_PARAMETER;
1103 goto done;
1106 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1107 if (vi == NULL) {
1108 status = NT_STATUS_NO_MEMORY;
1109 goto done;
1112 vi->domsid = domsid;
1113 vi->fn = fn;
1114 vi->private_data = private_data;
1116 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 goto done;
1121 if (count != NULL) {
1122 *count = vi->count;
1125 done:
1126 talloc_free(frame);
1127 return status;
1130 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1131 const char *domsid,
1132 NTSTATUS (*fn)(struct db_context *db,
1133 const char *domsid,
1134 uint32_t index,
1135 uint32_t rangenum,
1136 void *private_data),
1137 void *private_data,
1138 int *count)
1140 NTSTATUS status;
1142 status = idmap_autorid_iterate_domain_ranges_int(db,
1143 domsid,
1145 private_data,
1146 count,
1147 dbwrap_traverse);
1149 return status;
1153 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1154 const char *domsid,
1155 NTSTATUS (*fn)(struct db_context *db,
1156 const char *domsid,
1157 uint32_t index,
1158 uint32_t rangenum,
1159 void *count),
1160 void *private_data,
1161 int *count)
1163 NTSTATUS status;
1165 status = idmap_autorid_iterate_domain_ranges_int(db,
1166 domsid,
1168 private_data,
1169 count,
1170 dbwrap_traverse_read);
1172 return status;
1177 * Delete all ranges configured for a given domain
1180 struct delete_domain_ranges_visitor_ctx {
1181 bool force;
1184 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1185 struct db_context *db,
1186 const char *domsid,
1187 uint32_t domain_range_index,
1188 uint32_t rangenum,
1189 void *private_data)
1191 struct delete_domain_ranges_visitor_ctx *ctx;
1192 NTSTATUS status;
1194 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1196 status = idmap_autorid_delete_range_by_sid(
1197 db, domsid, domain_range_index, ctx->force);
1198 return status;
1201 struct idmap_autorid_delete_domain_ranges_ctx {
1202 const char *domsid;
1203 bool force;
1204 int count; /* output: count records operated on */
1207 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1208 void *private_data)
1210 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1211 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1212 int count;
1213 NTSTATUS status;
1215 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1217 ZERO_STRUCT(visitor_ctx);
1218 visitor_ctx.force = ctx->force;
1220 status = idmap_autorid_iterate_domain_ranges(db,
1221 ctx->domsid,
1222 idmap_autorid_delete_domain_ranges_visitor,
1223 &visitor_ctx,
1224 &count);
1225 if (!NT_STATUS_IS_OK(status)) {
1226 return status;
1229 ctx->count = count;
1231 return NT_STATUS_OK;
1234 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1235 const char *domsid,
1236 bool force,
1237 int *count)
1239 NTSTATUS status;
1240 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1242 ZERO_STRUCT(ctx);
1243 ctx.domsid = domsid;
1244 ctx.force = force;
1246 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1247 &ctx);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 return status;
1252 *count = ctx.count;
1254 return NT_STATUS_OK;