tests/krb5: Fix method for creating invalid length zeroed checksum
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
bloba95702e619e15aa25748ef8bd383791ba021d542
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 = {0};
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"));
131 ret = idmap_autorid_loadconfig(db, &globalcfg);
132 if (!NT_STATUS_IS_OK(ret)) {
133 DEBUG(1, ("Fatal error while fetching "
134 "configuration: %s\n",
135 nt_errstr(ret)));
136 goto error;
139 range->rangenum = stored_rangenum;
140 range->low_id = globalcfg.minvalue
141 + range->rangenum * globalcfg.rangesize;
142 range->high_id =
143 range->low_id + globalcfg.rangesize - 1;
145 return NT_STATUS_OK;
148 if (stored_rangenum != requested_rangenum) {
149 DEBUG(1, ("Error: requested rangenumber (%u) differs "
150 "from stored one (%u).\n",
151 requested_rangenum, stored_rangenum));
152 return NT_STATUS_UNSUCCESSFUL;
155 DEBUG(10, ("Note: stored range agrees with requested "
156 "one - ok\n"));
157 return NT_STATUS_OK;
160 /* fetch the current HWM */
161 ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
162 if (!NT_STATUS_IS_OK(ret)) {
163 DEBUG(1, ("Fatal error while fetching current "
164 "HWM value: %s\n", nt_errstr(ret)));
165 return NT_STATUS_INTERNAL_ERROR;
168 mem_ctx = talloc_stackframe();
170 ret = idmap_autorid_loadconfig(db, &globalcfg);
171 if (!NT_STATUS_IS_OK(ret)) {
172 DEBUG(1, ("Fatal error while fetching configuration: %s\n",
173 nt_errstr(ret)));
174 goto error;
177 if (acquire) {
179 * automatically acquire the next range
181 requested_rangenum = hwm;
184 if (requested_rangenum >= globalcfg.maxranges) {
185 DEBUG(1, ("Not enough ranges available: New range %u must be "
186 "smaller than configured maximum number of ranges "
187 "(%u).\n",
188 requested_rangenum, globalcfg.maxranges));
189 ret = NT_STATUS_NO_MEMORY;
190 goto error;
194 * Check that it is not yet taken.
195 * If the range is requested and < HWM, we need
196 * to check anyways, and otherwise, we also better
197 * check in order to prevent further corruption
198 * in case the db has been externally modified.
201 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
202 if (!numstr) {
203 DEBUG(1, ("Talloc failed!\n"));
204 ret = NT_STATUS_NO_MEMORY;
205 goto error;
208 if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
209 DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
211 if (requested_rangenum < hwm) {
212 ret = NT_STATUS_INVALID_PARAMETER;
213 } else {
214 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
217 goto error;
220 if (requested_rangenum >= hwm) {
222 * requested or automatic range >= HWM:
223 * increment the HWM.
226 /* HWM always contains current max range + 1 */
227 increment = requested_rangenum + 1 - hwm;
229 /* increase the HWM */
230 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
231 increment);
232 if (!NT_STATUS_IS_OK(ret)) {
233 DEBUG(1, ("Fatal error while incrementing the HWM "
234 "value in the database: %s\n",
235 nt_errstr(ret)));
236 goto error;
241 * store away the new mapping in both directions
244 ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
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 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
252 if (!numstr) {
253 ret = NT_STATUS_NO_MEMORY;
254 goto error;
257 ret = dbwrap_store_bystring(db, numstr,
258 string_term_tdb_data(keystr), TDB_INSERT);
260 if (!NT_STATUS_IS_OK(ret)) {
261 DEBUG(1, ("Fatal error while storing new "
262 "domain->range assignment: %s\n", nt_errstr(ret)));
263 goto error;
266 DEBUG(5, ("%s new range #%d for domain %s "
267 "(domain_range_index=%"PRIu32")\n",
268 (acquire?"Acquired":"Stored"),
269 requested_rangenum, keystr,
270 range->domain_range_index));
272 range->rangenum = requested_rangenum;
274 range->low_id = globalcfg.minvalue
275 + range->rangenum * globalcfg.rangesize;
276 range->high_id = range->low_id + globalcfg.rangesize - 1;
278 ret = NT_STATUS_OK;
280 error:
281 talloc_free(mem_ctx);
282 return ret;
285 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
286 struct autorid_range_config *range,
287 bool acquire)
289 NTSTATUS status;
290 struct idmap_autorid_addrange_ctx ctx;
292 ctx.acquire = acquire;
293 ctx.range = range;
295 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
296 return status;
299 NTSTATUS idmap_autorid_setrange(struct db_context *db,
300 const char *domsid,
301 uint32_t domain_range_index,
302 uint32_t rangenum)
304 NTSTATUS status;
305 struct autorid_range_config range;
307 ZERO_STRUCT(range);
308 fstrcpy(range.domsid, domsid);
309 range.domain_range_index = domain_range_index;
310 range.rangenum = rangenum;
312 status = idmap_autorid_addrange(db, &range, false);
313 return status;
316 NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
317 struct autorid_range_config *range)
319 return idmap_autorid_addrange(db, range, true);
322 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
323 struct autorid_range_config *range)
325 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
326 struct autorid_global_config globalcfg = {0};
327 fstring keystr;
329 if (db == NULL || range == NULL) {
330 DEBUG(3, ("Invalid arguments received\n"));
331 goto done;
334 if (!idmap_autorid_validate_sid(range->domsid)) {
335 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
336 status = NT_STATUS_INVALID_PARAMETER;
337 goto done;
340 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
341 keystr);
343 DEBUG(10, ("reading domain range for key %s\n", keystr));
344 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
345 if (!NT_STATUS_IS_OK(status)) {
346 DEBUG(1, ("Failed to read database record for key '%s': %s\n",
347 keystr, nt_errstr(status)));
348 goto done;
351 status = idmap_autorid_loadconfig(db, &globalcfg);
352 if (!NT_STATUS_IS_OK(status)) {
353 DEBUG(1, ("Failed to read global configuration"));
354 goto done;
356 range->low_id = globalcfg.minvalue
357 + range->rangenum * globalcfg.rangesize;
358 range->high_id = range->low_id + globalcfg.rangesize - 1;
359 done:
360 return status;
363 NTSTATUS idmap_autorid_getrange(struct db_context *db,
364 const char *domsid,
365 uint32_t domain_range_index,
366 uint32_t *rangenum,
367 uint32_t *low_id)
369 NTSTATUS status;
370 struct autorid_range_config range;
372 if (rangenum == NULL) {
373 return NT_STATUS_INVALID_PARAMETER;
376 ZERO_STRUCT(range);
377 fstrcpy(range.domsid, domsid);
378 range.domain_range_index = domain_range_index;
380 status = idmap_autorid_getrange_int(db, &range);
381 if (!NT_STATUS_IS_OK(status)) {
382 return status;
385 *rangenum = range.rangenum;
387 if (low_id != NULL) {
388 *low_id = range.low_id;
391 return NT_STATUS_OK;
394 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
395 struct autorid_range_config *range,
396 bool read_only)
398 NTSTATUS ret;
400 ret = idmap_autorid_getrange_int(db, range);
401 if (!NT_STATUS_IS_OK(ret)) {
402 DEBUG(10, ("Failed to read range config for '%s': %s\n",
403 range->domsid, nt_errstr(ret)));
404 if (read_only) {
405 DEBUG(10, ("Not allocating new range for '%s' because "
406 "read-only is enabled.\n", range->domsid));
407 return NT_STATUS_NOT_FOUND;
410 ret = idmap_autorid_acquire_range(db, range);
413 DEBUG(10, ("Using range #%d for domain %s "
414 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
415 range->rangenum, range->domsid, range->domain_range_index,
416 range->low_id));
418 return ret;
421 /* initialize the given HWM to 0 if it does not exist yet */
422 static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
423 void *private_data)
425 NTSTATUS status;
426 uint32_t hwmval;
427 const char *hwm;
429 hwm = (char *)private_data;
431 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
432 if (NT_STATUS_IS_OK(status)) {
433 DEBUG(1, ("HWM (%s) already initialized in autorid database "
434 "(value %"PRIu32").\n", hwm, hwmval));
435 return NT_STATUS_OK;
437 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
438 DEBUG(0, ("Error fetching HWM (%s) from autorid "
439 "database: %s\n", hwm, nt_errstr(status)));
440 return status;
443 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
444 if (!NT_STATUS_IS_OK(status)) {
445 DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
446 hwm, nt_errstr(status)));
447 return status;
450 return NT_STATUS_OK;
453 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
455 NTSTATUS status;
456 uint32_t hwmval;
458 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
459 if (NT_STATUS_IS_OK(status)) {
460 DEBUG(1, ("HWM (%s) already initialized in autorid database "
461 "(value %"PRIu32").\n", hwm, hwmval));
462 return NT_STATUS_OK;
464 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
465 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
466 "database: %s\n", hwm, nt_errstr(status)));
467 return status;
470 status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
471 discard_const(hwm));
472 if (!NT_STATUS_IS_OK(status)) {
473 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
474 "%s\n", hwm, nt_errstr(status)));
475 return NT_STATUS_INTERNAL_DB_ERROR;
478 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
480 return NT_STATUS_OK;
484 * Delete a domain#index <-> range mapping from the database.
485 * The mapping is specified by the sid and index.
486 * If force == true, invalid mapping records are deleted as far
487 * as possible, otherwise they are left untouched.
490 struct idmap_autorid_delete_range_by_sid_ctx {
491 const char *domsid;
492 uint32_t domain_range_index;
493 bool force;
496 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
497 void *private_data)
499 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
500 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
501 const char *domsid;
502 uint32_t domain_range_index;
503 uint32_t rangenum;
504 char *keystr;
505 char *range_keystr;
506 TDB_DATA data;
507 NTSTATUS status;
508 TALLOC_CTX *frame = talloc_stackframe();
509 bool is_valid_range_mapping = true;
510 bool force;
512 domsid = ctx->domsid;
513 domain_range_index = ctx->domain_range_index;
514 force = ctx->force;
516 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
517 domain_range_index);
518 if (keystr == NULL) {
519 status = NT_STATUS_NO_MEMORY;
520 goto done;
523 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
524 if (!NT_STATUS_IS_OK(status)) {
525 goto done;
528 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
529 if (range_keystr == NULL) {
530 status = NT_STATUS_NO_MEMORY;
531 goto done;
534 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
535 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
536 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
537 keystr, range_keystr));
538 is_valid_range_mapping = false;
539 } else if (!NT_STATUS_IS_OK(status)) {
540 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
541 keystr, range_keystr, nt_errstr(status)));
542 goto done;
543 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
544 != 0)
546 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
547 keystr, range_keystr, (const char *)data.dptr));
548 is_valid_range_mapping = false;
551 if (!is_valid_range_mapping && !force) {
552 DEBUG(10, ("Not deleting invalid mapping, since not in force "
553 "mode.\n"));
554 status = NT_STATUS_FILE_INVALID;
555 goto done;
558 status = dbwrap_delete_bystring(db, keystr);
559 if (!NT_STATUS_IS_OK(status)) {
560 DEBUG(1, ("Deletion of '%s' failed: %s\n",
561 keystr, nt_errstr(status)));
562 goto done;
565 if (!is_valid_range_mapping) {
566 goto done;
569 status = dbwrap_delete_bystring(db, range_keystr);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(1, ("Deletion of '%s' failed: %s\n",
572 range_keystr, nt_errstr(status)));
573 goto done;
576 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
577 range_keystr));
579 done:
580 TALLOC_FREE(frame);
581 return status;
584 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
585 const char *domsid,
586 uint32_t domain_range_index,
587 bool force)
589 NTSTATUS status;
590 struct idmap_autorid_delete_range_by_sid_ctx ctx;
592 ctx.domain_range_index = domain_range_index;
593 ctx.domsid = domsid;
594 ctx.force = force;
596 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
597 &ctx);
598 return status;
602 * Delete a domain#index <-> range mapping from the database.
603 * The mapping is specified by the range number.
604 * If force == true, invalid mapping records are deleted as far
605 * as possible, otherwise they are left untouched.
607 struct idmap_autorid_delete_range_by_num_ctx {
608 uint32_t rangenum;
609 bool force;
612 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
613 void *private_data)
615 struct idmap_autorid_delete_range_by_num_ctx *ctx =
616 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
617 uint32_t rangenum;
618 char *keystr = NULL;
619 char *range_keystr;
620 TDB_DATA val;
621 NTSTATUS status;
622 TALLOC_CTX *frame = talloc_stackframe();
623 bool is_valid_range_mapping = true;
624 bool force;
626 rangenum = ctx->rangenum;
627 force = ctx->force;
629 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
630 if (range_keystr == NULL) {
631 status = NT_STATUS_NO_MEMORY;
632 goto done;
635 ZERO_STRUCT(val);
637 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
638 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
639 DEBUG(10, ("Did not find range '%s' in database.\n",
640 range_keystr));
641 goto done;
642 } else if (!NT_STATUS_IS_OK(status)) {
643 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
644 goto done;
647 if (val.dptr == NULL) {
648 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
649 range_keystr));
650 is_valid_range_mapping = false;
651 } else {
652 uint32_t reverse_rangenum = 0;
654 keystr = (char *)val.dptr;
656 status = dbwrap_fetch_uint32_bystring(db, keystr,
657 &reverse_rangenum);
658 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
659 DEBUG(1, ("Incomplete mapping %s -> %s: "
660 "no backward mapping\n",
661 range_keystr, keystr));
662 is_valid_range_mapping = false;
663 } else if (!NT_STATUS_IS_OK(status)) {
664 DEBUG(1, ("Error fetching reverse mapping for "
665 "%s -> %s: %s\n",
666 range_keystr, keystr, nt_errstr(status)));
667 goto done;
668 } else if (rangenum != reverse_rangenum) {
669 is_valid_range_mapping = false;
673 if (!is_valid_range_mapping && !force) {
674 DEBUG(10, ("Not deleting invalid mapping, since not in force "
675 "mode.\n"));
676 status = NT_STATUS_FILE_INVALID;
677 goto done;
680 status = dbwrap_delete_bystring(db, range_keystr);
681 if (!NT_STATUS_IS_OK(status)) {
682 DEBUG(1, ("Deletion of '%s' failed: %s\n",
683 range_keystr, nt_errstr(status)));
684 goto done;
687 if (!is_valid_range_mapping) {
688 goto done;
691 status = dbwrap_delete_bystring(db, keystr);
692 if (!NT_STATUS_IS_OK(status)) {
693 DEBUG(1, ("Deletion of '%s' failed: %s\n",
694 keystr, nt_errstr(status)));
695 goto done;
698 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
699 keystr));
701 done:
702 talloc_free(frame);
703 return status;
706 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
707 uint32_t rangenum,
708 bool force)
710 NTSTATUS status;
711 struct idmap_autorid_delete_range_by_num_ctx ctx;
713 ctx.rangenum = rangenum;
714 ctx.force = force;
716 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
717 &ctx);
718 return status;
722 * Open and possibly create the database.
724 NTSTATUS idmap_autorid_db_open(const char *path,
725 TALLOC_CTX *mem_ctx,
726 struct db_context **db)
728 if (*db != NULL) {
729 /* its already open */
730 return NT_STATUS_OK;
733 /* Open idmap repository */
734 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
735 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
737 if (*db == NULL) {
738 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
739 return NT_STATUS_UNSUCCESSFUL;
742 return NT_STATUS_OK;
746 * Initialize the high watermark records in the database.
748 NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
750 NTSTATUS status;
752 status = idmap_autorid_init_hwm(db, HWM);
753 if (!NT_STATUS_IS_OK(status)) {
754 return status;
757 status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
762 status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
764 return status;
767 NTSTATUS idmap_autorid_db_init(const char *path,
768 TALLOC_CTX *mem_ctx,
769 struct db_context **db)
771 NTSTATUS status;
773 status = idmap_autorid_db_open(path, mem_ctx, db);
774 if (!NT_STATUS_IS_OK(status)) {
775 return status;
778 status = idmap_autorid_init_hwms(*db);
779 return status;
784 struct idmap_autorid_fetch_config_state {
785 TALLOC_CTX *mem_ctx;
786 char *configstr;
789 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
790 void *private_data)
792 struct idmap_autorid_fetch_config_state *state;
794 state = (struct idmap_autorid_fetch_config_state *)private_data;
797 * strndup because we have non-nullterminated strings in the db
799 state->configstr = talloc_strndup(
800 state->mem_ctx, (const char *)value.dptr, value.dsize);
803 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
804 char **result)
806 TDB_DATA key;
807 NTSTATUS status;
808 struct idmap_autorid_fetch_config_state state;
810 if (result == NULL) {
811 return NT_STATUS_INVALID_PARAMETER;
814 key = string_term_tdb_data(CONFIGKEY);
816 state.mem_ctx = mem_ctx;
817 state.configstr = NULL;
819 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
820 &state);
821 if (!NT_STATUS_IS_OK(status)) {
822 DEBUG(1, ("Error while retrieving config: %s\n",
823 nt_errstr(status)));
824 return status;
827 if (state.configstr == NULL) {
828 DEBUG(1, ("Error while retrieving config\n"));
829 return NT_STATUS_NO_MEMORY;
832 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
834 *result = state.configstr;
835 return NT_STATUS_OK;
838 bool idmap_autorid_parse_configstr(const char *configstr,
839 struct autorid_global_config *cfg)
841 unsigned long minvalue, rangesize, maxranges;
843 if (sscanf(configstr,
844 "minvalue:%lu rangesize:%lu maxranges:%lu",
845 &minvalue, &rangesize, &maxranges) != 3) {
846 DEBUG(1,
847 ("Found invalid configuration data. "
848 "Creating new config\n"));
849 return false;
852 cfg->minvalue = minvalue;
853 cfg->rangesize = rangesize;
854 cfg->maxranges = maxranges;
856 return true;
859 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
860 struct autorid_global_config *result)
862 struct autorid_global_config cfg = {0};
863 NTSTATUS status;
864 bool ok;
865 char *configstr = NULL;
867 if (result == NULL) {
868 return NT_STATUS_INVALID_PARAMETER;
871 status = idmap_autorid_getconfigstr(db, db, &configstr);
872 if (!NT_STATUS_IS_OK(status)) {
873 return status;
876 ok = idmap_autorid_parse_configstr(configstr, &cfg);
877 TALLOC_FREE(configstr);
878 if (!ok) {
879 return NT_STATUS_INVALID_PARAMETER;
882 DEBUG(10, ("Loaded previously stored configuration "
883 "minvalue:%d rangesize:%d\n",
884 cfg.minvalue, cfg.rangesize));
886 *result = cfg;
888 return NT_STATUS_OK;
891 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
892 struct autorid_global_config *cfg)
895 struct autorid_global_config storedconfig = {0};
896 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
897 TDB_DATA data;
898 char *cfgstr;
899 uint32_t hwm;
900 TALLOC_CTX *frame = talloc_stackframe();
902 DEBUG(10, ("New configuration provided for storing is "
903 "minvalue:%d rangesize:%d maxranges:%d\n",
904 cfg->minvalue, cfg->rangesize, cfg->maxranges));
906 if (cfg->rangesize < 2000) {
907 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
908 goto done;
911 if (cfg->maxranges == 0) {
912 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
913 "Must have at least one range available.\n"));
914 goto done;
917 status = idmap_autorid_loadconfig(db, &storedconfig);
918 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
919 DEBUG(5, ("No configuration found. Storing initial "
920 "configuration.\n"));
921 storedconfig = *cfg;
922 } else if (!NT_STATUS_IS_OK(status)) {
923 DEBUG(1, ("Error loading configuration: %s\n",
924 nt_errstr(status)));
925 goto done;
928 /* did the minimum value or rangesize change? */
929 if ((storedconfig.minvalue != cfg->minvalue) ||
930 (storedconfig.rangesize != cfg->rangesize))
932 DEBUG(1, ("New configuration values for rangesize or "
933 "minimum uid value conflict with previously "
934 "used values! Not storing new config.\n"));
935 status = NT_STATUS_INVALID_PARAMETER;
936 goto done;
939 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
940 if (!NT_STATUS_IS_OK(status)) {
941 DEBUG(1, ("Fatal error while fetching current "
942 "HWM value: %s\n", nt_errstr(status)));
943 status = NT_STATUS_INTERNAL_ERROR;
944 goto done;
948 * has the highest uid value been reduced to setting that is not
949 * sufficient any more for already existing ranges?
951 if (hwm > cfg->maxranges) {
952 DEBUG(1, ("New upper uid limit is too low to cover "
953 "existing mappings! Not storing new config.\n"));
954 status = NT_STATUS_INVALID_PARAMETER;
955 goto done;
958 cfgstr =
959 talloc_asprintf(frame,
960 "minvalue:%u rangesize:%u maxranges:%u",
961 cfg->minvalue, cfg->rangesize, cfg->maxranges);
963 if (cfgstr == NULL) {
964 status = NT_STATUS_NO_MEMORY;
965 goto done;
968 data = string_tdb_data(cfgstr);
970 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
972 done:
973 TALLOC_FREE(frame);
974 return status;
977 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
978 const char *configstr)
980 bool ok;
981 NTSTATUS status;
982 struct autorid_global_config cfg;
984 ok = idmap_autorid_parse_configstr(configstr, &cfg);
985 if (!ok) {
986 return NT_STATUS_INVALID_PARAMETER;
989 status = idmap_autorid_saveconfig(db, &cfg);
990 return status;
995 * iteration: Work on all range mappings for a given domain
998 struct domain_range_visitor_ctx {
999 const char *domsid;
1000 NTSTATUS (*fn)(struct db_context *db,
1001 const char *domsid,
1002 uint32_t index,
1003 uint32_t rangenum,
1004 void *private_data);
1005 void *private_data;
1006 int count; /* number of records worked on */
1009 static int idmap_autorid_visit_domain_range(struct db_record *rec,
1010 void *private_data)
1012 struct domain_range_visitor_ctx *vi;
1013 char *domsid;
1014 char *sep;
1015 uint32_t range_index = 0;
1016 uint32_t rangenum = 0;
1017 TDB_DATA key, value;
1018 NTSTATUS status;
1019 int ret = 0;
1020 struct db_context *db;
1022 vi = talloc_get_type_abort(private_data,
1023 struct domain_range_visitor_ctx);
1025 key = dbwrap_record_get_key(rec);
1028 * split string "<sid>[#<index>]" into sid string and index number
1031 domsid = (char *)key.dptr;
1033 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1034 domsid));
1036 sep = strrchr(domsid, '#');
1037 if (sep != NULL) {
1038 char *index_str;
1039 *sep = '\0';
1040 index_str = sep+1;
1041 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1042 DEBUG(10, ("Found separator '#' but '%s' is not a "
1043 "valid range index. Skipping record\n",
1044 index_str));
1045 goto done;
1049 if (!idmap_autorid_validate_sid(domsid)) {
1050 DEBUG(10, ("String '%s' is not a valid sid. "
1051 "Skipping record.\n", domsid));
1052 goto done;
1055 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1056 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1057 domsid, vi->domsid));
1058 goto done;
1061 value = dbwrap_record_get_value(rec);
1063 if (value.dsize != sizeof(uint32_t)) {
1064 /* it might be a mapping of a well known sid */
1065 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1066 "skipping.\n", (unsigned)value.dsize, vi->domsid));
1067 goto done;
1070 rangenum = IVAL(value.dptr, 0);
1072 db = dbwrap_record_get_db(rec);
1074 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1075 if (!NT_STATUS_IS_OK(status)) {
1076 ret = -1;
1077 goto done;
1080 vi->count++;
1081 ret = 0;
1083 done:
1084 return ret;
1087 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1088 const char *domsid,
1089 NTSTATUS (*fn)(struct db_context *db,
1090 const char *domsid,
1091 uint32_t index,
1092 uint32_t rangnum,
1093 void *private_data),
1094 void *private_data,
1095 int *count,
1096 NTSTATUS (*traverse)(struct db_context *db,
1097 int (*f)(struct db_record *, void *),
1098 void *private_data,
1099 int *count))
1101 NTSTATUS status;
1102 struct domain_range_visitor_ctx *vi;
1103 TALLOC_CTX *frame = talloc_stackframe();
1105 if (domsid == NULL) {
1106 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1109 if (fn == NULL) {
1110 DEBUG(1, ("Error: missing visitor callback\n"));
1111 status = NT_STATUS_INVALID_PARAMETER;
1112 goto done;
1115 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1116 if (vi == NULL) {
1117 status = NT_STATUS_NO_MEMORY;
1118 goto done;
1121 vi->domsid = domsid;
1122 vi->fn = fn;
1123 vi->private_data = private_data;
1125 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1126 if (!NT_STATUS_IS_OK(status)) {
1127 goto done;
1130 if (count != NULL) {
1131 *count = vi->count;
1134 done:
1135 talloc_free(frame);
1136 return status;
1139 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1140 const char *domsid,
1141 NTSTATUS (*fn)(struct db_context *db,
1142 const char *domsid,
1143 uint32_t index,
1144 uint32_t rangenum,
1145 void *private_data),
1146 void *private_data,
1147 int *count)
1149 NTSTATUS status;
1151 status = idmap_autorid_iterate_domain_ranges_int(db,
1152 domsid,
1154 private_data,
1155 count,
1156 dbwrap_traverse);
1158 return status;
1162 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1163 const char *domsid,
1164 NTSTATUS (*fn)(struct db_context *db,
1165 const char *domsid,
1166 uint32_t index,
1167 uint32_t rangenum,
1168 void *count),
1169 void *private_data,
1170 int *count)
1172 NTSTATUS status;
1174 status = idmap_autorid_iterate_domain_ranges_int(db,
1175 domsid,
1177 private_data,
1178 count,
1179 dbwrap_traverse_read);
1181 return status;
1186 * Delete all ranges configured for a given domain
1189 struct delete_domain_ranges_visitor_ctx {
1190 bool force;
1193 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1194 struct db_context *db,
1195 const char *domsid,
1196 uint32_t domain_range_index,
1197 uint32_t rangenum,
1198 void *private_data)
1200 struct delete_domain_ranges_visitor_ctx *ctx;
1201 NTSTATUS status;
1203 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1205 status = idmap_autorid_delete_range_by_sid(
1206 db, domsid, domain_range_index, ctx->force);
1207 return status;
1210 struct idmap_autorid_delete_domain_ranges_ctx {
1211 const char *domsid;
1212 bool force;
1213 int count; /* output: count records operated on */
1216 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1217 void *private_data)
1219 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1220 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1221 int count;
1222 NTSTATUS status;
1224 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1226 ZERO_STRUCT(visitor_ctx);
1227 visitor_ctx.force = ctx->force;
1229 status = idmap_autorid_iterate_domain_ranges(db,
1230 ctx->domsid,
1231 idmap_autorid_delete_domain_ranges_visitor,
1232 &visitor_ctx,
1233 &count);
1234 if (!NT_STATUS_IS_OK(status)) {
1235 return status;
1238 ctx->count = count;
1240 return NT_STATUS_OK;
1243 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1244 const char *domsid,
1245 bool force,
1246 int *count)
1248 NTSTATUS status;
1249 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1251 ZERO_STRUCT(ctx);
1252 ctx.domsid = domsid;
1253 ctx.force = force;
1255 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1256 &ctx);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 return status;
1261 *count = ctx.count;
1263 return NT_STATUS_OK;