s3: libsmb: In cli_list_old_send(), push state->mask into the packet, not just mask.
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blob24cf380945d6db774815e3439122e99882ce6da2
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"
28 #include "lib/util/string_wrappers.h"
30 /**
31 * Build the database keystring for getting a range
32 * belonging to a domain sid and a range index.
34 static void idmap_autorid_build_keystr(const char *domsid,
35 uint32_t domain_range_index,
36 fstring keystr)
38 if (domain_range_index > 0) {
39 fstr_sprintf(keystr, "%s#%"PRIu32,
40 domsid, domain_range_index);
41 } else {
42 fstrcpy(keystr, domsid);
46 static char *idmap_autorid_build_keystr_talloc(TALLOC_CTX *mem_ctx,
47 const char *domsid,
48 uint32_t domain_range_index)
50 char *keystr;
52 if (domain_range_index > 0) {
53 keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
54 domain_range_index);
55 } else {
56 keystr = talloc_strdup(mem_ctx, domsid);
59 return keystr;
63 static bool idmap_autorid_validate_sid(const char *sid)
65 struct dom_sid ignore;
66 if (sid == NULL) {
67 return false;
70 if (strcmp(sid, ALLOC_RANGE) == 0) {
71 return true;
74 return dom_sid_parse(sid, &ignore);
77 struct idmap_autorid_addrange_ctx {
78 struct autorid_range_config *range;
79 bool acquire;
82 static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
83 void *private_data)
85 struct idmap_autorid_addrange_ctx *ctx;
86 uint32_t requested_rangenum, stored_rangenum;
87 struct autorid_range_config *range;
88 bool acquire;
89 NTSTATUS ret;
90 uint32_t hwm;
91 char *numstr;
92 struct autorid_global_config globalcfg = {0};
93 fstring keystr;
94 uint32_t increment;
95 TALLOC_CTX *mem_ctx = NULL;
97 ctx = (struct idmap_autorid_addrange_ctx *)private_data;
98 range = ctx->range;
99 acquire = ctx->acquire;
100 requested_rangenum = range->rangenum;
102 if (db == NULL) {
103 DEBUG(3, ("Invalid database argument: NULL"));
104 return NT_STATUS_INVALID_PARAMETER;
107 if (range == NULL) {
108 DEBUG(3, ("Invalid range argument: NULL"));
109 return NT_STATUS_INVALID_PARAMETER;
112 DEBUG(10, ("Adding new range for domain %s "
113 "(domain_range_index=%"PRIu32")\n",
114 range->domsid, range->domain_range_index));
116 if (!idmap_autorid_validate_sid(range->domsid)) {
117 DEBUG(3, ("Invalid SID: %s\n", range->domsid));
118 return NT_STATUS_INVALID_PARAMETER;
121 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
122 keystr);
124 ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
126 if (NT_STATUS_IS_OK(ret)) {
127 /* entry is already present*/
128 if (acquire) {
129 DEBUG(10, ("domain range already allocated - "
130 "Not adding!\n"));
132 ret = idmap_autorid_loadconfig(db, &globalcfg);
133 if (!NT_STATUS_IS_OK(ret)) {
134 DEBUG(1, ("Fatal error while fetching "
135 "configuration: %s\n",
136 nt_errstr(ret)));
137 goto error;
140 range->rangenum = stored_rangenum;
141 range->low_id = globalcfg.minvalue
142 + range->rangenum * globalcfg.rangesize;
143 range->high_id =
144 range->low_id + globalcfg.rangesize - 1;
146 return NT_STATUS_OK;
149 if (stored_rangenum != requested_rangenum) {
150 DEBUG(1, ("Error: requested rangenumber (%u) differs "
151 "from stored one (%u).\n",
152 requested_rangenum, stored_rangenum));
153 return NT_STATUS_UNSUCCESSFUL;
156 DEBUG(10, ("Note: stored range agrees with requested "
157 "one - ok\n"));
158 return NT_STATUS_OK;
161 /* fetch the current HWM */
162 ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
163 if (!NT_STATUS_IS_OK(ret)) {
164 DEBUG(1, ("Fatal error while fetching current "
165 "HWM value: %s\n", nt_errstr(ret)));
166 return NT_STATUS_INTERNAL_ERROR;
169 mem_ctx = talloc_stackframe();
171 ret = idmap_autorid_loadconfig(db, &globalcfg);
172 if (!NT_STATUS_IS_OK(ret)) {
173 DEBUG(1, ("Fatal error while fetching configuration: %s\n",
174 nt_errstr(ret)));
175 goto error;
178 if (acquire) {
180 * automatically acquire the next range
182 requested_rangenum = hwm;
185 if (requested_rangenum >= globalcfg.maxranges) {
186 DEBUG(1, ("Not enough ranges available: New range %u must be "
187 "smaller than configured maximum number of ranges "
188 "(%u).\n",
189 requested_rangenum, globalcfg.maxranges));
190 ret = NT_STATUS_NO_MEMORY;
191 goto error;
195 * Check that it is not yet taken.
196 * If the range is requested and < HWM, we need
197 * to check anyways, and otherwise, we also better
198 * check in order to prevent further corruption
199 * in case the db has been externally modified.
202 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
203 if (!numstr) {
204 DEBUG(1, ("Talloc failed!\n"));
205 ret = NT_STATUS_NO_MEMORY;
206 goto error;
209 if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
210 DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
212 if (requested_rangenum < hwm) {
213 ret = NT_STATUS_INVALID_PARAMETER;
214 } else {
215 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
218 goto error;
221 if (requested_rangenum >= hwm) {
223 * requested or automatic range >= HWM:
224 * increment the HWM.
227 /* HWM always contains current max range + 1 */
228 increment = requested_rangenum + 1 - hwm;
230 /* increase the HWM */
231 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
232 increment);
233 if (!NT_STATUS_IS_OK(ret)) {
234 DEBUG(1, ("Fatal error while incrementing the HWM "
235 "value in the database: %s\n",
236 nt_errstr(ret)));
237 goto error;
242 * store away the new mapping in both directions
245 ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
246 if (!NT_STATUS_IS_OK(ret)) {
247 DEBUG(1, ("Fatal error while storing new "
248 "domain->range assignment: %s\n", nt_errstr(ret)));
249 goto error;
252 numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
253 if (!numstr) {
254 ret = NT_STATUS_NO_MEMORY;
255 goto error;
258 ret = dbwrap_store_bystring(db, numstr,
259 string_term_tdb_data(keystr), TDB_INSERT);
261 if (!NT_STATUS_IS_OK(ret)) {
262 DEBUG(1, ("Fatal error while storing new "
263 "domain->range assignment: %s\n", nt_errstr(ret)));
264 goto error;
267 DEBUG(5, ("%s new range #%d for domain %s "
268 "(domain_range_index=%"PRIu32")\n",
269 (acquire?"Acquired":"Stored"),
270 requested_rangenum, keystr,
271 range->domain_range_index));
273 range->rangenum = requested_rangenum;
275 range->low_id = globalcfg.minvalue
276 + range->rangenum * globalcfg.rangesize;
277 range->high_id = range->low_id + globalcfg.rangesize - 1;
279 ret = NT_STATUS_OK;
281 error:
282 talloc_free(mem_ctx);
283 return ret;
286 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
287 struct autorid_range_config *range,
288 bool acquire)
290 NTSTATUS status;
291 struct idmap_autorid_addrange_ctx ctx;
293 ctx.acquire = acquire;
294 ctx.range = range;
296 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
297 return status;
300 NTSTATUS idmap_autorid_setrange(struct db_context *db,
301 const char *domsid,
302 uint32_t domain_range_index,
303 uint32_t rangenum)
305 NTSTATUS status;
306 struct autorid_range_config range;
308 ZERO_STRUCT(range);
309 fstrcpy(range.domsid, domsid);
310 range.domain_range_index = domain_range_index;
311 range.rangenum = rangenum;
313 status = idmap_autorid_addrange(db, &range, false);
314 return status;
317 NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
318 struct autorid_range_config *range)
320 return idmap_autorid_addrange(db, range, true);
323 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
324 struct autorid_range_config *range)
326 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
327 struct autorid_global_config globalcfg = {0};
328 fstring keystr;
330 if (db == NULL || range == NULL) {
331 DEBUG(3, ("Invalid arguments received\n"));
332 goto done;
335 if (!idmap_autorid_validate_sid(range->domsid)) {
336 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
337 status = NT_STATUS_INVALID_PARAMETER;
338 goto done;
341 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
342 keystr);
344 DEBUG(10, ("reading domain range for key %s\n", keystr));
345 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
346 if (!NT_STATUS_IS_OK(status)) {
347 DEBUG(1, ("Failed to read database record for key '%s': %s\n",
348 keystr, nt_errstr(status)));
349 goto done;
352 status = idmap_autorid_loadconfig(db, &globalcfg);
353 if (!NT_STATUS_IS_OK(status)) {
354 DEBUG(1, ("Failed to read global configuration"));
355 goto done;
357 range->low_id = globalcfg.minvalue
358 + range->rangenum * globalcfg.rangesize;
359 range->high_id = range->low_id + globalcfg.rangesize - 1;
360 done:
361 return status;
364 NTSTATUS idmap_autorid_getrange(struct db_context *db,
365 const char *domsid,
366 uint32_t domain_range_index,
367 uint32_t *rangenum,
368 uint32_t *low_id)
370 NTSTATUS status;
371 struct autorid_range_config range;
373 if (rangenum == NULL) {
374 return NT_STATUS_INVALID_PARAMETER;
377 ZERO_STRUCT(range);
378 fstrcpy(range.domsid, domsid);
379 range.domain_range_index = domain_range_index;
381 status = idmap_autorid_getrange_int(db, &range);
382 if (!NT_STATUS_IS_OK(status)) {
383 return status;
386 *rangenum = range.rangenum;
388 if (low_id != NULL) {
389 *low_id = range.low_id;
392 return NT_STATUS_OK;
395 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
396 struct autorid_range_config *range,
397 bool read_only)
399 NTSTATUS ret;
401 ret = idmap_autorid_getrange_int(db, range);
402 if (!NT_STATUS_IS_OK(ret)) {
403 DEBUG(10, ("Failed to read range config for '%s': %s\n",
404 range->domsid, nt_errstr(ret)));
405 if (read_only) {
406 DEBUG(10, ("Not allocating new range for '%s' because "
407 "read-only is enabled.\n", range->domsid));
408 return NT_STATUS_NOT_FOUND;
411 ret = idmap_autorid_acquire_range(db, range);
414 DEBUG(10, ("Using range #%d for domain %s "
415 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
416 range->rangenum, range->domsid, range->domain_range_index,
417 range->low_id));
419 return ret;
422 /* initialize the given HWM to 0 if it does not exist yet */
423 static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
424 void *private_data)
426 NTSTATUS status;
427 uint32_t hwmval;
428 const char *hwm;
430 hwm = (char *)private_data;
432 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
433 if (NT_STATUS_IS_OK(status)) {
434 DEBUG(1, ("HWM (%s) already initialized in autorid database "
435 "(value %"PRIu32").\n", hwm, hwmval));
436 return NT_STATUS_OK;
438 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
439 DEBUG(0, ("Error fetching HWM (%s) from autorid "
440 "database: %s\n", hwm, nt_errstr(status)));
441 return status;
444 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
445 if (!NT_STATUS_IS_OK(status)) {
446 DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
447 hwm, nt_errstr(status)));
448 return status;
451 return NT_STATUS_OK;
454 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
456 NTSTATUS status;
457 uint32_t hwmval;
459 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
460 if (NT_STATUS_IS_OK(status)) {
461 DEBUG(1, ("HWM (%s) already initialized in autorid database "
462 "(value %"PRIu32").\n", hwm, hwmval));
463 return NT_STATUS_OK;
465 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
466 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
467 "database: %s\n", hwm, nt_errstr(status)));
468 return status;
471 status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
472 discard_const(hwm));
473 if (!NT_STATUS_IS_OK(status)) {
474 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
475 "%s\n", hwm, nt_errstr(status)));
476 return NT_STATUS_INTERNAL_DB_ERROR;
479 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
481 return NT_STATUS_OK;
485 * Delete a domain#index <-> range mapping from the database.
486 * The mapping is specified by the sid and index.
487 * If force == true, invalid mapping records are deleted as far
488 * as possible, otherwise they are left untouched.
491 struct idmap_autorid_delete_range_by_sid_ctx {
492 const char *domsid;
493 uint32_t domain_range_index;
494 bool force;
497 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
498 void *private_data)
500 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
501 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
502 const char *domsid;
503 uint32_t domain_range_index;
504 uint32_t rangenum;
505 char *keystr;
506 char *range_keystr;
507 TDB_DATA data;
508 NTSTATUS status;
509 TALLOC_CTX *frame = talloc_stackframe();
510 bool is_valid_range_mapping = true;
511 bool force;
513 domsid = ctx->domsid;
514 domain_range_index = ctx->domain_range_index;
515 force = ctx->force;
517 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
518 domain_range_index);
519 if (keystr == NULL) {
520 status = NT_STATUS_NO_MEMORY;
521 goto done;
524 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
525 if (!NT_STATUS_IS_OK(status)) {
526 goto done;
529 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
530 if (range_keystr == NULL) {
531 status = NT_STATUS_NO_MEMORY;
532 goto done;
535 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
536 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
537 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
538 keystr, range_keystr));
539 is_valid_range_mapping = false;
540 } else if (!NT_STATUS_IS_OK(status)) {
541 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
542 keystr, range_keystr, nt_errstr(status)));
543 goto done;
544 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
545 != 0)
547 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
548 keystr, range_keystr, (const char *)data.dptr));
549 is_valid_range_mapping = false;
552 if (!is_valid_range_mapping && !force) {
553 DEBUG(10, ("Not deleting invalid mapping, since not in force "
554 "mode.\n"));
555 status = NT_STATUS_FILE_INVALID;
556 goto done;
559 status = dbwrap_delete_bystring(db, keystr);
560 if (!NT_STATUS_IS_OK(status)) {
561 DEBUG(1, ("Deletion of '%s' failed: %s\n",
562 keystr, nt_errstr(status)));
563 goto done;
566 if (!is_valid_range_mapping) {
567 goto done;
570 status = dbwrap_delete_bystring(db, range_keystr);
571 if (!NT_STATUS_IS_OK(status)) {
572 DEBUG(1, ("Deletion of '%s' failed: %s\n",
573 range_keystr, nt_errstr(status)));
574 goto done;
577 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
578 range_keystr));
580 done:
581 TALLOC_FREE(frame);
582 return status;
585 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
586 const char *domsid,
587 uint32_t domain_range_index,
588 bool force)
590 NTSTATUS status;
591 struct idmap_autorid_delete_range_by_sid_ctx ctx;
593 ctx.domain_range_index = domain_range_index;
594 ctx.domsid = domsid;
595 ctx.force = force;
597 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
598 &ctx);
599 return status;
603 * Delete a domain#index <-> range mapping from the database.
604 * The mapping is specified by the range number.
605 * If force == true, invalid mapping records are deleted as far
606 * as possible, otherwise they are left untouched.
608 struct idmap_autorid_delete_range_by_num_ctx {
609 uint32_t rangenum;
610 bool force;
613 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
614 void *private_data)
616 struct idmap_autorid_delete_range_by_num_ctx *ctx =
617 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
618 uint32_t rangenum;
619 char *keystr = NULL;
620 char *range_keystr;
621 TDB_DATA val;
622 NTSTATUS status;
623 TALLOC_CTX *frame = talloc_stackframe();
624 bool is_valid_range_mapping = true;
625 bool force;
627 rangenum = ctx->rangenum;
628 force = ctx->force;
630 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
631 if (range_keystr == NULL) {
632 status = NT_STATUS_NO_MEMORY;
633 goto done;
636 ZERO_STRUCT(val);
638 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
639 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
640 DEBUG(10, ("Did not find range '%s' in database.\n",
641 range_keystr));
642 goto done;
643 } else if (!NT_STATUS_IS_OK(status)) {
644 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
645 goto done;
648 if (val.dptr == NULL) {
649 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
650 range_keystr));
651 is_valid_range_mapping = false;
652 } else {
653 uint32_t reverse_rangenum = 0;
655 keystr = (char *)val.dptr;
657 status = dbwrap_fetch_uint32_bystring(db, keystr,
658 &reverse_rangenum);
659 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
660 DEBUG(1, ("Incomplete mapping %s -> %s: "
661 "no backward mapping\n",
662 range_keystr, keystr));
663 is_valid_range_mapping = false;
664 } else if (!NT_STATUS_IS_OK(status)) {
665 DEBUG(1, ("Error fetching reverse mapping for "
666 "%s -> %s: %s\n",
667 range_keystr, keystr, nt_errstr(status)));
668 goto done;
669 } else if (rangenum != reverse_rangenum) {
670 is_valid_range_mapping = false;
674 if (!is_valid_range_mapping && !force) {
675 DEBUG(10, ("Not deleting invalid mapping, since not in force "
676 "mode.\n"));
677 status = NT_STATUS_FILE_INVALID;
678 goto done;
681 status = dbwrap_delete_bystring(db, range_keystr);
682 if (!NT_STATUS_IS_OK(status)) {
683 DEBUG(1, ("Deletion of '%s' failed: %s\n",
684 range_keystr, nt_errstr(status)));
685 goto done;
688 if (!is_valid_range_mapping) {
689 goto done;
692 status = dbwrap_delete_bystring(db, keystr);
693 if (!NT_STATUS_IS_OK(status)) {
694 DEBUG(1, ("Deletion of '%s' failed: %s\n",
695 keystr, nt_errstr(status)));
696 goto done;
699 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
700 keystr));
702 done:
703 talloc_free(frame);
704 return status;
707 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
708 uint32_t rangenum,
709 bool force)
711 NTSTATUS status;
712 struct idmap_autorid_delete_range_by_num_ctx ctx;
714 ctx.rangenum = rangenum;
715 ctx.force = force;
717 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
718 &ctx);
719 return status;
723 * Open and possibly create the database.
725 NTSTATUS idmap_autorid_db_open(const char *path,
726 TALLOC_CTX *mem_ctx,
727 struct db_context **db)
729 if (*db != NULL) {
730 /* its already open */
731 return NT_STATUS_OK;
734 /* Open idmap repository */
735 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
736 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
738 if (*db == NULL) {
739 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
740 return NT_STATUS_UNSUCCESSFUL;
743 return NT_STATUS_OK;
747 * Initialize the high watermark records in the database.
749 NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
751 NTSTATUS status;
753 status = idmap_autorid_init_hwm(db, HWM);
754 if (!NT_STATUS_IS_OK(status)) {
755 return status;
758 status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
759 if (!NT_STATUS_IS_OK(status)) {
760 return status;
763 status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
765 return status;
768 NTSTATUS idmap_autorid_db_init(const char *path,
769 TALLOC_CTX *mem_ctx,
770 struct db_context **db)
772 NTSTATUS status;
774 status = idmap_autorid_db_open(path, mem_ctx, db);
775 if (!NT_STATUS_IS_OK(status)) {
776 return status;
779 status = idmap_autorid_init_hwms(*db);
780 return status;
785 struct idmap_autorid_fetch_config_state {
786 TALLOC_CTX *mem_ctx;
787 char *configstr;
790 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
791 void *private_data)
793 struct idmap_autorid_fetch_config_state *state;
795 state = (struct idmap_autorid_fetch_config_state *)private_data;
798 * strndup because we have non-nullterminated strings in the db
800 state->configstr = talloc_strndup(
801 state->mem_ctx, (const char *)value.dptr, value.dsize);
804 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
805 char **result)
807 TDB_DATA key;
808 NTSTATUS status;
809 struct idmap_autorid_fetch_config_state state;
811 if (result == NULL) {
812 return NT_STATUS_INVALID_PARAMETER;
815 key = string_term_tdb_data(CONFIGKEY);
817 state.mem_ctx = mem_ctx;
818 state.configstr = NULL;
820 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
821 &state);
822 if (!NT_STATUS_IS_OK(status)) {
823 DEBUG(1, ("Error while retrieving config: %s\n",
824 nt_errstr(status)));
825 return status;
828 if (state.configstr == NULL) {
829 DEBUG(1, ("Error while retrieving config\n"));
830 return NT_STATUS_NO_MEMORY;
833 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
835 *result = state.configstr;
836 return NT_STATUS_OK;
839 bool idmap_autorid_parse_configstr(const char *configstr,
840 struct autorid_global_config *cfg)
842 unsigned long minvalue, rangesize, maxranges;
844 if (sscanf(configstr,
845 "minvalue:%lu rangesize:%lu maxranges:%lu",
846 &minvalue, &rangesize, &maxranges) != 3) {
847 DEBUG(1,
848 ("Found invalid configuration data. "
849 "Creating new config\n"));
850 return false;
853 cfg->minvalue = minvalue;
854 cfg->rangesize = rangesize;
855 cfg->maxranges = maxranges;
857 return true;
860 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
861 struct autorid_global_config *result)
863 struct autorid_global_config cfg = {0};
864 NTSTATUS status;
865 bool ok;
866 char *configstr = NULL;
868 if (result == NULL) {
869 return NT_STATUS_INVALID_PARAMETER;
872 status = idmap_autorid_getconfigstr(db, db, &configstr);
873 if (!NT_STATUS_IS_OK(status)) {
874 return status;
877 ok = idmap_autorid_parse_configstr(configstr, &cfg);
878 TALLOC_FREE(configstr);
879 if (!ok) {
880 return NT_STATUS_INVALID_PARAMETER;
883 DEBUG(10, ("Loaded previously stored configuration "
884 "minvalue:%d rangesize:%d\n",
885 cfg.minvalue, cfg.rangesize));
887 *result = cfg;
889 return NT_STATUS_OK;
892 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
893 struct autorid_global_config *cfg)
896 struct autorid_global_config storedconfig = {0};
897 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
898 TDB_DATA data;
899 char *cfgstr;
900 uint32_t hwm;
901 TALLOC_CTX *frame = talloc_stackframe();
903 DEBUG(10, ("New configuration provided for storing is "
904 "minvalue:%d rangesize:%d maxranges:%d\n",
905 cfg->minvalue, cfg->rangesize, cfg->maxranges));
907 if (cfg->rangesize < 2000) {
908 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
909 goto done;
912 if (cfg->maxranges == 0) {
913 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
914 "Must have at least one range available.\n"));
915 goto done;
918 status = idmap_autorid_loadconfig(db, &storedconfig);
919 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
920 DEBUG(5, ("No configuration found. Storing initial "
921 "configuration.\n"));
922 storedconfig = *cfg;
923 } else if (!NT_STATUS_IS_OK(status)) {
924 DEBUG(1, ("Error loading configuration: %s\n",
925 nt_errstr(status)));
926 goto done;
929 /* did the minimum value or rangesize change? */
930 if ((storedconfig.minvalue != cfg->minvalue) ||
931 (storedconfig.rangesize != cfg->rangesize))
933 DEBUG(1, ("New configuration values for rangesize or "
934 "minimum uid value conflict with previously "
935 "used values! Not storing new config.\n"));
936 status = NT_STATUS_INVALID_PARAMETER;
937 goto done;
940 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
941 if (!NT_STATUS_IS_OK(status)) {
942 DEBUG(1, ("Fatal error while fetching current "
943 "HWM value: %s\n", nt_errstr(status)));
944 status = NT_STATUS_INTERNAL_ERROR;
945 goto done;
949 * has the highest uid value been reduced to setting that is not
950 * sufficient any more for already existing ranges?
952 if (hwm > cfg->maxranges) {
953 DEBUG(1, ("New upper uid limit is too low to cover "
954 "existing mappings! Not storing new config.\n"));
955 status = NT_STATUS_INVALID_PARAMETER;
956 goto done;
959 cfgstr =
960 talloc_asprintf(frame,
961 "minvalue:%u rangesize:%u maxranges:%u",
962 cfg->minvalue, cfg->rangesize, cfg->maxranges);
964 if (cfgstr == NULL) {
965 status = NT_STATUS_NO_MEMORY;
966 goto done;
969 data = string_tdb_data(cfgstr);
971 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
973 done:
974 TALLOC_FREE(frame);
975 return status;
978 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
979 const char *configstr)
981 bool ok;
982 NTSTATUS status;
983 struct autorid_global_config cfg;
985 ok = idmap_autorid_parse_configstr(configstr, &cfg);
986 if (!ok) {
987 return NT_STATUS_INVALID_PARAMETER;
990 status = idmap_autorid_saveconfig(db, &cfg);
991 return status;
996 * iteration: Work on all range mappings for a given domain
999 struct domain_range_visitor_ctx {
1000 const char *domsid;
1001 NTSTATUS (*fn)(struct db_context *db,
1002 const char *domsid,
1003 uint32_t index,
1004 uint32_t rangenum,
1005 void *private_data);
1006 void *private_data;
1007 int count; /* number of records worked on */
1010 static int idmap_autorid_visit_domain_range(struct db_record *rec,
1011 void *private_data)
1013 struct domain_range_visitor_ctx *vi;
1014 char *domsid;
1015 char *sep;
1016 uint32_t range_index = 0;
1017 uint32_t rangenum = 0;
1018 TDB_DATA key, value;
1019 NTSTATUS status;
1020 int ret = 0;
1021 struct db_context *db;
1023 vi = talloc_get_type_abort(private_data,
1024 struct domain_range_visitor_ctx);
1026 key = dbwrap_record_get_key(rec);
1029 * split string "<sid>[#<index>]" into sid string and index number
1032 domsid = (char *)key.dptr;
1034 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1035 domsid));
1037 sep = strrchr(domsid, '#');
1038 if (sep != NULL) {
1039 char *index_str;
1040 *sep = '\0';
1041 index_str = sep+1;
1042 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1043 DEBUG(10, ("Found separator '#' but '%s' is not a "
1044 "valid range index. Skipping record\n",
1045 index_str));
1046 goto done;
1050 if (!idmap_autorid_validate_sid(domsid)) {
1051 DEBUG(10, ("String '%s' is not a valid sid. "
1052 "Skipping record.\n", domsid));
1053 goto done;
1056 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1057 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1058 domsid, vi->domsid));
1059 goto done;
1062 value = dbwrap_record_get_value(rec);
1064 if (value.dsize != sizeof(uint32_t)) {
1065 /* it might be a mapping of a well known sid */
1066 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1067 "skipping.\n", (unsigned)value.dsize, vi->domsid));
1068 goto done;
1071 rangenum = IVAL(value.dptr, 0);
1073 db = dbwrap_record_get_db(rec);
1075 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 ret = -1;
1078 goto done;
1081 vi->count++;
1082 ret = 0;
1084 done:
1085 return ret;
1088 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1089 const char *domsid,
1090 NTSTATUS (*fn)(struct db_context *db,
1091 const char *domsid,
1092 uint32_t index,
1093 uint32_t rangnum,
1094 void *private_data),
1095 void *private_data,
1096 int *count,
1097 NTSTATUS (*traverse)(struct db_context *db,
1098 int (*f)(struct db_record *, void *),
1099 void *private_data,
1100 int *count))
1102 NTSTATUS status;
1103 struct domain_range_visitor_ctx *vi;
1104 TALLOC_CTX *frame = talloc_stackframe();
1106 if (domsid == NULL) {
1107 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1110 if (fn == NULL) {
1111 DEBUG(1, ("Error: missing visitor callback\n"));
1112 status = NT_STATUS_INVALID_PARAMETER;
1113 goto done;
1116 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1117 if (vi == NULL) {
1118 status = NT_STATUS_NO_MEMORY;
1119 goto done;
1122 vi->domsid = domsid;
1123 vi->fn = fn;
1124 vi->private_data = private_data;
1126 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1127 if (!NT_STATUS_IS_OK(status)) {
1128 goto done;
1131 if (count != NULL) {
1132 *count = vi->count;
1135 done:
1136 talloc_free(frame);
1137 return status;
1140 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1141 const char *domsid,
1142 NTSTATUS (*fn)(struct db_context *db,
1143 const char *domsid,
1144 uint32_t index,
1145 uint32_t rangenum,
1146 void *private_data),
1147 void *private_data,
1148 int *count)
1150 NTSTATUS status;
1152 status = idmap_autorid_iterate_domain_ranges_int(db,
1153 domsid,
1155 private_data,
1156 count,
1157 dbwrap_traverse);
1159 return status;
1163 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1164 const char *domsid,
1165 NTSTATUS (*fn)(struct db_context *db,
1166 const char *domsid,
1167 uint32_t index,
1168 uint32_t rangenum,
1169 void *count),
1170 void *private_data,
1171 int *count)
1173 NTSTATUS status;
1175 status = idmap_autorid_iterate_domain_ranges_int(db,
1176 domsid,
1178 private_data,
1179 count,
1180 dbwrap_traverse_read);
1182 return status;
1187 * Delete all ranges configured for a given domain
1190 struct delete_domain_ranges_visitor_ctx {
1191 bool force;
1194 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1195 struct db_context *db,
1196 const char *domsid,
1197 uint32_t domain_range_index,
1198 uint32_t rangenum,
1199 void *private_data)
1201 struct delete_domain_ranges_visitor_ctx *ctx;
1202 NTSTATUS status;
1204 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1206 status = idmap_autorid_delete_range_by_sid(
1207 db, domsid, domain_range_index, ctx->force);
1208 return status;
1211 struct idmap_autorid_delete_domain_ranges_ctx {
1212 const char *domsid;
1213 bool force;
1214 int count; /* output: count records operated on */
1217 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1218 void *private_data)
1220 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1221 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1222 int count;
1223 NTSTATUS status;
1225 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1227 ZERO_STRUCT(visitor_ctx);
1228 visitor_ctx.force = ctx->force;
1230 status = idmap_autorid_iterate_domain_ranges(db,
1231 ctx->domsid,
1232 idmap_autorid_delete_domain_ranges_visitor,
1233 &visitor_ctx,
1234 &count);
1235 if (!NT_STATUS_IS_OK(status)) {
1236 return status;
1239 ctx->count = count;
1241 return NT_STATUS_OK;
1244 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1245 const char *domsid,
1246 bool force,
1247 int *count)
1249 NTSTATUS status;
1250 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1252 ZERO_STRUCT(ctx);
1253 ctx.domsid = domsid;
1254 ctx.force = force;
1256 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1257 &ctx);
1258 if (!NT_STATUS_IS_OK(status)) {
1259 return status;
1262 *count = ctx.count;
1264 return NT_STATUS_OK;