printing: fix purge of all print jobs
[Samba.git] / source3 / winbindd / idmap_autorid_tdb.c
blob89c3ad7b9a305063849c3b16e23b2ec10f241c09
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;
261 range->high_id = range->low_id + globalcfg->rangesize - 1;
263 ret = NT_STATUS_OK;
265 error:
266 talloc_free(mem_ctx);
267 return ret;
270 static NTSTATUS idmap_autorid_addrange(struct db_context *db,
271 struct autorid_range_config *range,
272 bool acquire)
274 NTSTATUS status;
275 struct idmap_autorid_addrange_ctx ctx;
277 ctx.acquire = acquire;
278 ctx.range = range;
280 status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
281 return status;
284 NTSTATUS idmap_autorid_setrange(struct db_context *db,
285 const char *domsid,
286 uint32_t domain_range_index,
287 uint32_t rangenum)
289 NTSTATUS status;
290 struct autorid_range_config range;
292 ZERO_STRUCT(range);
293 fstrcpy(range.domsid, domsid);
294 range.domain_range_index = domain_range_index;
295 range.rangenum = rangenum;
297 status = idmap_autorid_addrange(db, &range, false);
298 return status;
301 static NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
302 struct autorid_range_config *range)
304 return idmap_autorid_addrange(db, range, true);
307 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
308 struct autorid_range_config *range)
310 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
311 struct autorid_global_config *globalcfg = NULL;
312 fstring keystr;
314 if (db == NULL || range == NULL) {
315 DEBUG(3, ("Invalid arguments received\n"));
316 goto done;
319 if (!idmap_autorid_validate_sid(range->domsid)) {
320 DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
321 status = NT_STATUS_INVALID_PARAMETER;
322 goto done;
325 idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
326 keystr);
328 DEBUG(10, ("reading domain range for key %s\n", keystr));
329 status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
330 if (!NT_STATUS_IS_OK(status)) {
331 DEBUG(1, ("Failed to read database record for key '%s': %s\n",
332 keystr, nt_errstr(status)));
333 goto done;
336 status = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
337 if (!NT_STATUS_IS_OK(status)) {
338 DEBUG(1, ("Failed to read global configuration"));
339 goto done;
341 range->low_id = globalcfg->minvalue
342 + range->rangenum * globalcfg->rangesize;
343 range->high_id = range->low_id + globalcfg->rangesize - 1;
345 TALLOC_FREE(globalcfg);
346 done:
347 return status;
350 NTSTATUS idmap_autorid_getrange(struct db_context *db,
351 const char *domsid,
352 uint32_t domain_range_index,
353 uint32_t *rangenum,
354 uint32_t *low_id)
356 NTSTATUS status;
357 struct autorid_range_config range;
359 if (rangenum == NULL) {
360 return NT_STATUS_INVALID_PARAMETER;
363 ZERO_STRUCT(range);
364 fstrcpy(range.domsid, domsid);
365 range.domain_range_index = domain_range_index;
367 status = idmap_autorid_getrange_int(db, &range);
368 if (!NT_STATUS_IS_OK(status)) {
369 return status;
372 *rangenum = range.rangenum;
374 if (low_id != NULL) {
375 *low_id = range.low_id;
378 return NT_STATUS_OK;
381 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
382 struct autorid_range_config *range,
383 bool read_only)
385 NTSTATUS ret;
387 ret = idmap_autorid_getrange_int(db, range);
388 if (!NT_STATUS_IS_OK(ret)) {
389 DEBUG(10, ("Failed to read range config for '%s': %s\n",
390 range->domsid, nt_errstr(ret)));
391 if (read_only) {
392 DEBUG(10, ("Not allocating new range for '%s' because "
393 "read-only is enabled.\n", range->domsid));
394 return NT_STATUS_NOT_FOUND;
397 ret = idmap_autorid_acquire_range(db, range);
400 DEBUG(10, ("Using range #%d for domain %s "
401 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
402 range->rangenum, range->domsid, range->domain_range_index,
403 range->low_id));
405 return ret;
408 /* initialize the given HWM to 0 if it does not exist yet */
409 static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
410 void *private_data)
412 NTSTATUS status;
413 uint32_t hwmval;
414 const char *hwm;
416 hwm = (char *)private_data;
418 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
419 if (NT_STATUS_IS_OK(status)) {
420 DEBUG(1, ("HWM (%s) already initialized in autorid database "
421 "(value %"PRIu32").\n", hwm, hwmval));
422 return NT_STATUS_OK;
424 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
425 DEBUG(0, ("Error fetching HWM (%s) from autorid "
426 "database: %s\n", hwm, nt_errstr(status)));
427 return status;
430 status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
431 if (!NT_STATUS_IS_OK(status)) {
432 DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
433 hwm, nt_errstr(status)));
434 return status;
437 return NT_STATUS_OK;
440 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
442 NTSTATUS status;
443 uint32_t hwmval;
445 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
446 if (NT_STATUS_IS_OK(status)) {
447 DEBUG(1, ("HWM (%s) already initialized in autorid database "
448 "(value %"PRIu32").\n", hwm, hwmval));
449 return NT_STATUS_OK;
451 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
452 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
453 "database: %s\n", hwm, nt_errstr(status)));
454 return status;
457 status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
458 discard_const(hwm));
459 if (!NT_STATUS_IS_OK(status)) {
460 DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
461 "%s\n", hwm, nt_errstr(status)));
462 return NT_STATUS_INTERNAL_DB_ERROR;
465 DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
467 return NT_STATUS_OK;
471 * Delete a domain#index <-> range mapping from the database.
472 * The mapping is specified by the sid and index.
473 * If force == true, invalid mapping records are deleted as far
474 * as possible, otherwise they are left untouched.
477 struct idmap_autorid_delete_range_by_sid_ctx {
478 const char *domsid;
479 uint32_t domain_range_index;
480 bool force;
483 static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
484 void *private_data)
486 struct idmap_autorid_delete_range_by_sid_ctx *ctx =
487 (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
488 const char *domsid;
489 uint32_t domain_range_index;
490 uint32_t rangenum;
491 char *keystr;
492 char *range_keystr;
493 TDB_DATA data;
494 NTSTATUS status;
495 TALLOC_CTX *frame = talloc_stackframe();
496 bool is_valid_range_mapping = true;
497 bool force;
499 domsid = ctx->domsid;
500 domain_range_index = ctx->domain_range_index;
501 force = ctx->force;
503 keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
504 domain_range_index);
505 if (keystr == NULL) {
506 status = NT_STATUS_NO_MEMORY;
507 goto done;
510 status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
511 if (!NT_STATUS_IS_OK(status)) {
512 goto done;
515 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
516 if (range_keystr == NULL) {
517 status = NT_STATUS_NO_MEMORY;
518 goto done;
521 status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
522 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
523 DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
524 keystr, range_keystr));
525 is_valid_range_mapping = false;
526 } else if (!NT_STATUS_IS_OK(status)) {
527 DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
528 keystr, range_keystr, nt_errstr(status)));
529 goto done;
530 } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
531 != 0)
533 DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
534 keystr, range_keystr, (const char *)data.dptr));
535 is_valid_range_mapping = false;
538 if (!is_valid_range_mapping && !force) {
539 DEBUG(10, ("Not deleting invalid mapping, since not in force "
540 "mode.\n"));
541 status = NT_STATUS_FILE_INVALID;
542 goto done;
545 status = dbwrap_delete_bystring(db, keystr);
546 if (!NT_STATUS_IS_OK(status)) {
547 DEBUG(1, ("Deletion of '%s' failed: %s\n",
548 keystr, nt_errstr(status)));
549 goto done;
552 if (!is_valid_range_mapping) {
553 goto done;
556 status = dbwrap_delete_bystring(db, range_keystr);
557 if (!NT_STATUS_IS_OK(status)) {
558 DEBUG(1, ("Deletion of '%s' failed: %s\n",
559 range_keystr, nt_errstr(status)));
560 goto done;
563 DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
564 range_keystr));
566 done:
567 TALLOC_FREE(frame);
568 return status;
571 NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
572 const char *domsid,
573 uint32_t domain_range_index,
574 bool force)
576 NTSTATUS status;
577 struct idmap_autorid_delete_range_by_sid_ctx ctx;
579 ctx.domain_range_index = domain_range_index;
580 ctx.domsid = domsid;
581 ctx.force = force;
583 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
584 &ctx);
585 return status;
589 * Delete a domain#index <-> range mapping from the database.
590 * The mapping is specified by the range number.
591 * If force == true, invalid mapping records are deleted as far
592 * as possible, otherwise they are left untouched.
594 struct idmap_autorid_delete_range_by_num_ctx {
595 uint32_t rangenum;
596 bool force;
599 static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
600 void *private_data)
602 struct idmap_autorid_delete_range_by_num_ctx *ctx =
603 (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
604 uint32_t rangenum;
605 char *keystr;
606 char *range_keystr;
607 TDB_DATA val;
608 NTSTATUS status;
609 TALLOC_CTX *frame = talloc_stackframe();
610 bool is_valid_range_mapping = true;
611 bool force;
613 rangenum = ctx->rangenum;
614 force = ctx->force;
616 range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
617 if (range_keystr == NULL) {
618 status = NT_STATUS_NO_MEMORY;
619 goto done;
622 ZERO_STRUCT(val);
624 status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
625 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
626 DEBUG(10, ("Did not find range '%s' in database.\n",
627 range_keystr));
628 goto done;
629 } else if (!NT_STATUS_IS_OK(status)) {
630 DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
631 goto done;
634 if (val.dptr == NULL) {
635 DEBUG(1, ("Invalid mapping: %s -> empty value\n",
636 range_keystr));
637 is_valid_range_mapping = false;
638 } else {
639 uint32_t reverse_rangenum = 0;
641 keystr = (char *)val.dptr;
643 status = dbwrap_fetch_uint32_bystring(db, keystr,
644 &reverse_rangenum);
645 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
646 DEBUG(1, ("Incomplete mapping %s -> %s: "
647 "no backward mapping\n",
648 range_keystr, keystr));
649 is_valid_range_mapping = false;
650 } else if (!NT_STATUS_IS_OK(status)) {
651 DEBUG(1, ("Error fetching reverse mapping for "
652 "%s -> %s: %s\n",
653 range_keystr, keystr, nt_errstr(status)));
654 goto done;
655 } else if (rangenum != reverse_rangenum) {
656 is_valid_range_mapping = false;
660 if (!is_valid_range_mapping && !force) {
661 DEBUG(10, ("Not deleting invalid mapping, since not in force "
662 "mode.\n"));
663 status = NT_STATUS_FILE_INVALID;
664 goto done;
667 status = dbwrap_delete_bystring(db, range_keystr);
668 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(1, ("Deletion of '%s' failed: %s\n",
670 range_keystr, nt_errstr(status)));
671 goto done;
674 if (!is_valid_range_mapping) {
675 goto done;
678 status = dbwrap_delete_bystring(db, keystr);
679 if (!NT_STATUS_IS_OK(status)) {
680 DEBUG(1, ("Deletion of '%s' failed: %s\n",
681 keystr, nt_errstr(status)));
682 goto done;
685 DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
686 keystr));
688 done:
689 talloc_free(frame);
690 return status;
693 NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
694 uint32_t rangenum,
695 bool force)
697 NTSTATUS status;
698 struct idmap_autorid_delete_range_by_num_ctx ctx;
700 ctx.rangenum = rangenum;
701 ctx.force = force;
703 status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
704 &ctx);
705 return status;
709 * Open and possibly create the database.
711 NTSTATUS idmap_autorid_db_open(const char *path,
712 TALLOC_CTX *mem_ctx,
713 struct db_context **db)
715 if (*db != NULL) {
716 /* its already open */
717 return NT_STATUS_OK;
720 /* Open idmap repository */
721 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
722 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
724 if (*db == NULL) {
725 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
726 return NT_STATUS_UNSUCCESSFUL;
729 return NT_STATUS_OK;
733 * Initialize the high watermark records in the database.
735 NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
737 NTSTATUS status;
739 status = idmap_autorid_init_hwm(db, HWM);
740 if (!NT_STATUS_IS_OK(status)) {
741 return status;
744 status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
745 if (!NT_STATUS_IS_OK(status)) {
746 return status;
749 status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
751 return status;
754 NTSTATUS idmap_autorid_db_init(const char *path,
755 TALLOC_CTX *mem_ctx,
756 struct db_context **db)
758 NTSTATUS status;
760 status = idmap_autorid_db_open(path, mem_ctx, db);
761 if (!NT_STATUS_IS_OK(status)) {
762 return status;
765 status = idmap_autorid_init_hwms(*db);
766 return status;
771 struct idmap_autorid_fetch_config_state {
772 TALLOC_CTX *mem_ctx;
773 char *configstr;
776 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
777 void *private_data)
779 struct idmap_autorid_fetch_config_state *state;
781 state = (struct idmap_autorid_fetch_config_state *)private_data;
784 * strndup because we have non-nullterminated strings in the db
786 state->configstr = talloc_strndup(
787 state->mem_ctx, (const char *)value.dptr, value.dsize);
790 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
791 char **result)
793 TDB_DATA key;
794 NTSTATUS status;
795 struct idmap_autorid_fetch_config_state state;
797 if (result == NULL) {
798 return NT_STATUS_INVALID_PARAMETER;
801 key = string_term_tdb_data(CONFIGKEY);
803 state.mem_ctx = mem_ctx;
804 state.configstr = NULL;
806 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
807 &state);
808 if (!NT_STATUS_IS_OK(status)) {
809 DEBUG(1, ("Error while retrieving config: %s\n",
810 nt_errstr(status)));
811 return status;
814 if (state.configstr == NULL) {
815 DEBUG(1, ("Error while retrieving config\n"));
816 return NT_STATUS_NO_MEMORY;
819 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
821 *result = state.configstr;
822 return NT_STATUS_OK;
825 bool idmap_autorid_parse_configstr(const char *configstr,
826 struct autorid_global_config *cfg)
828 unsigned long minvalue, rangesize, maxranges;
830 if (sscanf(configstr,
831 "minvalue:%lu rangesize:%lu maxranges:%lu",
832 &minvalue, &rangesize, &maxranges) != 3) {
833 DEBUG(1,
834 ("Found invalid configuration data. "
835 "Creating new config\n"));
836 return false;
839 cfg->minvalue = minvalue;
840 cfg->rangesize = rangesize;
841 cfg->maxranges = maxranges;
843 return true;
846 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
847 TALLOC_CTX *mem_ctx,
848 struct autorid_global_config **result)
850 struct autorid_global_config *cfg;
851 NTSTATUS status;
852 bool ok;
853 char *configstr = NULL;
855 if (result == NULL) {
856 return NT_STATUS_INVALID_PARAMETER;
859 status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
860 if (!NT_STATUS_IS_OK(status)) {
861 return status;
864 cfg = talloc_zero(mem_ctx, struct autorid_global_config);
865 if (cfg == NULL) {
866 return NT_STATUS_NO_MEMORY;
869 ok = idmap_autorid_parse_configstr(configstr, cfg);
870 if (!ok) {
871 talloc_free(cfg);
872 return NT_STATUS_INVALID_PARAMETER;
875 DEBUG(10, ("Loaded previously stored configuration "
876 "minvalue:%d rangesize:%d\n",
877 cfg->minvalue, cfg->rangesize));
879 *result = cfg;
881 return NT_STATUS_OK;
884 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
885 struct autorid_global_config *cfg)
888 struct autorid_global_config *storedconfig = NULL;
889 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
890 TDB_DATA data;
891 char *cfgstr;
892 uint32_t hwm;
893 TALLOC_CTX *frame = talloc_stackframe();
895 DEBUG(10, ("New configuration provided for storing is "
896 "minvalue:%d rangesize:%d maxranges:%d\n",
897 cfg->minvalue, cfg->rangesize, cfg->maxranges));
899 if (cfg->rangesize < 2000) {
900 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
901 goto done;
904 if (cfg->maxranges == 0) {
905 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
906 "Must have at least one range available.\n"));
907 goto done;
910 status = idmap_autorid_loadconfig(db, frame, &storedconfig);
911 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
912 DEBUG(5, ("No configuration found. Storing initial "
913 "configuration.\n"));
914 } else if (!NT_STATUS_IS_OK(status)) {
915 DEBUG(1, ("Error loading configuration: %s\n",
916 nt_errstr(status)));
917 goto done;
920 /* did the minimum value or rangesize change? */
921 if (storedconfig &&
922 ((storedconfig->minvalue != cfg->minvalue) ||
923 (storedconfig->rangesize != cfg->rangesize)))
925 DEBUG(1, ("New configuration values for rangesize or "
926 "minimum uid value conflict with previously "
927 "used values! Not storing new config.\n"));
928 status = NT_STATUS_INVALID_PARAMETER;
929 goto done;
932 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
933 if (!NT_STATUS_IS_OK(status)) {
934 DEBUG(1, ("Fatal error while fetching current "
935 "HWM value: %s\n", nt_errstr(status)));
936 status = NT_STATUS_INTERNAL_ERROR;
937 goto done;
941 * has the highest uid value been reduced to setting that is not
942 * sufficient any more for already existing ranges?
944 if (hwm > cfg->maxranges) {
945 DEBUG(1, ("New upper uid limit is too low to cover "
946 "existing mappings! Not storing new config.\n"));
947 status = NT_STATUS_INVALID_PARAMETER;
948 goto done;
951 cfgstr =
952 talloc_asprintf(frame,
953 "minvalue:%u rangesize:%u maxranges:%u",
954 cfg->minvalue, cfg->rangesize, cfg->maxranges);
956 if (cfgstr == NULL) {
957 status = NT_STATUS_NO_MEMORY;
958 goto done;
961 data = string_tdb_data(cfgstr);
963 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
965 done:
966 TALLOC_FREE(frame);
967 return status;
970 NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
971 const char *configstr)
973 bool ok;
974 NTSTATUS status;
975 struct autorid_global_config cfg;
977 ok = idmap_autorid_parse_configstr(configstr, &cfg);
978 if (!ok) {
979 return NT_STATUS_INVALID_PARAMETER;
982 status = idmap_autorid_saveconfig(db, &cfg);
983 return status;
988 * iteration: Work on all range mappings for a given domain
991 struct domain_range_visitor_ctx {
992 const char *domsid;
993 NTSTATUS (*fn)(struct db_context *db,
994 const char *domsid,
995 uint32_t index,
996 uint32_t rangenum,
997 void *private_data);
998 void *private_data;
999 int count; /* number of records worked on */
1002 static int idmap_autorid_visit_domain_range(struct db_record *rec,
1003 void *private_data)
1005 struct domain_range_visitor_ctx *vi;
1006 char *domsid;
1007 char *sep;
1008 uint32_t range_index = 0;
1009 uint32_t rangenum = 0;
1010 TDB_DATA key, value;
1011 NTSTATUS status;
1012 int ret = 0;
1013 struct db_context *db;
1015 vi = talloc_get_type_abort(private_data,
1016 struct domain_range_visitor_ctx);
1018 key = dbwrap_record_get_key(rec);
1021 * split string "<sid>[#<index>]" into sid string and index number
1024 domsid = (char *)key.dptr;
1026 DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1027 domsid));
1029 sep = strrchr(domsid, '#');
1030 if (sep != NULL) {
1031 char *index_str;
1032 *sep = '\0';
1033 index_str = sep+1;
1034 if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1035 DEBUG(10, ("Found separator '#' but '%s' is not a "
1036 "valid range index. Skipping record\n",
1037 index_str));
1038 goto done;
1042 if (!idmap_autorid_validate_sid(domsid)) {
1043 DEBUG(10, ("String '%s' is not a valid sid. "
1044 "Skipping record.\n", domsid));
1045 goto done;
1048 if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1049 DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1050 domsid, vi->domsid));
1051 goto done;
1054 value = dbwrap_record_get_value(rec);
1056 if (value.dsize != sizeof(uint32_t)) {
1057 /* it might be a mapping of a well known sid */
1058 DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1059 "skipping.\n", (unsigned)value.dsize, vi->domsid));
1060 goto done;
1063 rangenum = IVAL(value.dptr, 0);
1065 db = dbwrap_record_get_db(rec);
1067 status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1068 if (!NT_STATUS_IS_OK(status)) {
1069 ret = -1;
1070 goto done;
1073 vi->count++;
1074 ret = 0;
1076 done:
1077 return ret;
1080 static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1081 const char *domsid,
1082 NTSTATUS (*fn)(struct db_context *db,
1083 const char *domsid,
1084 uint32_t index,
1085 uint32_t rangnum,
1086 void *private_data),
1087 void *private_data,
1088 int *count,
1089 NTSTATUS (*traverse)(struct db_context *db,
1090 int (*f)(struct db_record *, void *),
1091 void *private_data,
1092 int *count))
1094 NTSTATUS status;
1095 struct domain_range_visitor_ctx *vi;
1096 TALLOC_CTX *frame = talloc_stackframe();
1098 if (domsid == NULL) {
1099 DEBUG(10, ("No sid provided, operating on all ranges\n"));
1102 if (fn == NULL) {
1103 DEBUG(1, ("Error: missing visitor callback\n"));
1104 status = NT_STATUS_INVALID_PARAMETER;
1105 goto done;
1108 vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1109 if (vi == NULL) {
1110 status = NT_STATUS_NO_MEMORY;
1111 goto done;
1114 vi->domsid = domsid;
1115 vi->fn = fn;
1116 vi->private_data = private_data;
1118 status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 goto done;
1123 if (count != NULL) {
1124 *count = vi->count;
1127 done:
1128 talloc_free(frame);
1129 return status;
1132 NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1133 const char *domsid,
1134 NTSTATUS (*fn)(struct db_context *db,
1135 const char *domsid,
1136 uint32_t index,
1137 uint32_t rangenum,
1138 void *private_data),
1139 void *private_data,
1140 int *count)
1142 NTSTATUS status;
1144 status = idmap_autorid_iterate_domain_ranges_int(db,
1145 domsid,
1147 private_data,
1148 count,
1149 dbwrap_traverse);
1151 return status;
1155 NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1156 const char *domsid,
1157 NTSTATUS (*fn)(struct db_context *db,
1158 const char *domsid,
1159 uint32_t index,
1160 uint32_t rangenum,
1161 void *count),
1162 void *private_data,
1163 int *count)
1165 NTSTATUS status;
1167 status = idmap_autorid_iterate_domain_ranges_int(db,
1168 domsid,
1170 private_data,
1171 count,
1172 dbwrap_traverse_read);
1174 return status;
1179 * Delete all ranges configured for a given domain
1182 struct delete_domain_ranges_visitor_ctx {
1183 bool force;
1186 static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1187 struct db_context *db,
1188 const char *domsid,
1189 uint32_t domain_range_index,
1190 uint32_t rangenum,
1191 void *private_data)
1193 struct delete_domain_ranges_visitor_ctx *ctx;
1194 NTSTATUS status;
1196 ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1198 status = idmap_autorid_delete_range_by_sid(
1199 db, domsid, domain_range_index, ctx->force);
1200 return status;
1203 struct idmap_autorid_delete_domain_ranges_ctx {
1204 const char *domsid;
1205 bool force;
1206 int count; /* output: count records operated on */
1209 static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1210 void *private_data)
1212 struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1213 struct delete_domain_ranges_visitor_ctx visitor_ctx;
1214 int count;
1215 NTSTATUS status;
1217 ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1219 ZERO_STRUCT(visitor_ctx);
1220 visitor_ctx.force = ctx->force;
1222 status = idmap_autorid_iterate_domain_ranges(db,
1223 ctx->domsid,
1224 idmap_autorid_delete_domain_ranges_visitor,
1225 &visitor_ctx,
1226 &count);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 return status;
1231 ctx->count = count;
1233 return NT_STATUS_OK;
1236 NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1237 const char *domsid,
1238 bool force,
1239 int *count)
1241 NTSTATUS status;
1242 struct idmap_autorid_delete_domain_ranges_ctx ctx;
1244 ZERO_STRUCT(ctx);
1245 ctx.domsid = domsid;
1246 ctx.force = force;
1248 status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1249 &ctx);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 return status;
1254 *count = ctx.count;
1256 return NT_STATUS_OK;