Line data Source code
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
6 : *
7 : * Copyright (C) Christian Ambach, 2010-2012
8 : * Copyright (C) Atul Kulkarni, 2013
9 : * Copyright (C) Michael Adam, 2012-2013
10 : *
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.
15 : *
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.
20 : *
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/>.
23 : *
24 : */
25 :
26 : #include "idmap_autorid_tdb.h"
27 : #include "../libcli/security/dom_sid.h"
28 : #include "lib/util/string_wrappers.h"
29 :
30 : /**
31 : * Build the database keystring for getting a range
32 : * belonging to a domain sid and a range index.
33 : */
34 0 : static void idmap_autorid_build_keystr(const char *domsid,
35 : uint32_t domain_range_index,
36 : fstring keystr)
37 : {
38 0 : if (domain_range_index > 0) {
39 0 : fstr_sprintf(keystr, "%s#%"PRIu32,
40 : domsid, domain_range_index);
41 : } else {
42 0 : fstrcpy(keystr, domsid);
43 : }
44 0 : }
45 :
46 0 : static char *idmap_autorid_build_keystr_talloc(TALLOC_CTX *mem_ctx,
47 : const char *domsid,
48 : uint32_t domain_range_index)
49 : {
50 0 : char *keystr;
51 :
52 0 : if (domain_range_index > 0) {
53 0 : keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
54 : domain_range_index);
55 : } else {
56 0 : keystr = talloc_strdup(mem_ctx, domsid);
57 : }
58 :
59 0 : return keystr;
60 : }
61 :
62 :
63 0 : static bool idmap_autorid_validate_sid(const char *sid)
64 : {
65 0 : struct dom_sid ignore;
66 0 : if (sid == NULL) {
67 0 : return false;
68 : }
69 :
70 0 : if (strcmp(sid, ALLOC_RANGE) == 0) {
71 0 : return true;
72 : }
73 :
74 0 : return dom_sid_parse(sid, &ignore);
75 : }
76 :
77 : struct idmap_autorid_addrange_ctx {
78 : struct autorid_range_config *range;
79 : bool acquire;
80 : };
81 :
82 0 : static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
83 : void *private_data)
84 : {
85 0 : struct idmap_autorid_addrange_ctx *ctx;
86 0 : uint32_t requested_rangenum, stored_rangenum;
87 0 : struct autorid_range_config *range;
88 0 : bool acquire;
89 0 : NTSTATUS ret;
90 0 : uint32_t hwm;
91 0 : char *numstr;
92 0 : struct autorid_global_config globalcfg = {0};
93 0 : fstring keystr;
94 0 : uint32_t increment;
95 0 : TALLOC_CTX *mem_ctx = NULL;
96 :
97 0 : ctx = (struct idmap_autorid_addrange_ctx *)private_data;
98 0 : range = ctx->range;
99 0 : acquire = ctx->acquire;
100 0 : requested_rangenum = range->rangenum;
101 :
102 0 : if (db == NULL) {
103 0 : DEBUG(3, ("Invalid database argument: NULL\n"));
104 0 : return NT_STATUS_INVALID_PARAMETER;
105 : }
106 :
107 0 : if (range == NULL) {
108 0 : DEBUG(3, ("Invalid range argument: NULL\n"));
109 0 : return NT_STATUS_INVALID_PARAMETER;
110 : }
111 :
112 0 : DEBUG(10, ("Adding new range for domain %s "
113 : "(domain_range_index=%"PRIu32")\n",
114 : range->domsid, range->domain_range_index));
115 :
116 0 : if (!idmap_autorid_validate_sid(range->domsid)) {
117 0 : DEBUG(3, ("Invalid SID: %s\n", range->domsid));
118 0 : return NT_STATUS_INVALID_PARAMETER;
119 : }
120 :
121 0 : idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
122 : keystr);
123 :
124 0 : ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
125 :
126 0 : if (NT_STATUS_IS_OK(ret)) {
127 : /* entry is already present*/
128 0 : if (acquire) {
129 0 : DEBUG(10, ("domain range already allocated - "
130 : "Not adding!\n"));
131 :
132 0 : ret = idmap_autorid_loadconfig(db, &globalcfg);
133 0 : if (!NT_STATUS_IS_OK(ret)) {
134 0 : DEBUG(1, ("Fatal error while fetching "
135 : "configuration: %s\n",
136 : nt_errstr(ret)));
137 0 : goto error;
138 : }
139 :
140 0 : range->rangenum = stored_rangenum;
141 0 : range->low_id = globalcfg.minvalue
142 0 : + range->rangenum * globalcfg.rangesize;
143 0 : range->high_id =
144 0 : range->low_id + globalcfg.rangesize - 1;
145 :
146 0 : return NT_STATUS_OK;
147 : }
148 :
149 0 : if (stored_rangenum != requested_rangenum) {
150 0 : DEBUG(1, ("Error: requested rangenumber (%u) differs "
151 : "from stored one (%u).\n",
152 : requested_rangenum, stored_rangenum));
153 0 : return NT_STATUS_UNSUCCESSFUL;
154 : }
155 :
156 0 : DEBUG(10, ("Note: stored range agrees with requested "
157 : "one - ok\n"));
158 0 : return NT_STATUS_OK;
159 : }
160 :
161 : /* fetch the current HWM */
162 0 : ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
163 0 : if (!NT_STATUS_IS_OK(ret)) {
164 0 : DEBUG(1, ("Fatal error while fetching current "
165 : "HWM value: %s\n", nt_errstr(ret)));
166 0 : return NT_STATUS_INTERNAL_ERROR;
167 : }
168 :
169 0 : mem_ctx = talloc_stackframe();
170 :
171 0 : ret = idmap_autorid_loadconfig(db, &globalcfg);
172 0 : if (!NT_STATUS_IS_OK(ret)) {
173 0 : DEBUG(1, ("Fatal error while fetching configuration: %s\n",
174 : nt_errstr(ret)));
175 0 : goto error;
176 : }
177 :
178 0 : if (acquire) {
179 : /*
180 : * automatically acquire the next range
181 : */
182 0 : requested_rangenum = hwm;
183 : }
184 :
185 0 : if (requested_rangenum >= globalcfg.maxranges) {
186 0 : DBG_WARNING("Not enough ranges available: New range %u can't "
187 : "be allocated. Consider increasing the range "
188 : "[%u-%u] by %u.\n",
189 : requested_rangenum,
190 : globalcfg.minvalue,
191 : globalcfg.minvalue +
192 : (globalcfg.maxranges * globalcfg.rangesize),
193 : globalcfg.rangesize);
194 0 : ret = NT_STATUS_NO_MEMORY;
195 0 : goto error;
196 : }
197 :
198 : /*
199 : * Check that it is not yet taken.
200 : * If the range is requested and < HWM, we need
201 : * to check anyways, and otherwise, we also better
202 : * check in order to prevent further corruption
203 : * in case the db has been externally modified.
204 : */
205 :
206 0 : numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
207 0 : if (!numstr) {
208 0 : DEBUG(1, ("Talloc failed!\n"));
209 0 : ret = NT_STATUS_NO_MEMORY;
210 0 : goto error;
211 : }
212 :
213 0 : if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
214 0 : DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
215 :
216 0 : if (requested_rangenum < hwm) {
217 0 : ret = NT_STATUS_INVALID_PARAMETER;
218 : } else {
219 0 : ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
220 : }
221 :
222 0 : goto error;
223 : }
224 :
225 0 : if (requested_rangenum >= hwm) {
226 : /*
227 : * requested or automatic range >= HWM:
228 : * increment the HWM.
229 : */
230 :
231 : /* HWM always contains current max range + 1 */
232 0 : increment = requested_rangenum + 1 - hwm;
233 :
234 : /* increase the HWM */
235 0 : ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
236 : increment);
237 0 : if (!NT_STATUS_IS_OK(ret)) {
238 0 : DEBUG(1, ("Fatal error while incrementing the HWM "
239 : "value in the database: %s\n",
240 : nt_errstr(ret)));
241 0 : goto error;
242 : }
243 : }
244 :
245 : /*
246 : * store away the new mapping in both directions
247 : */
248 :
249 0 : ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
250 0 : if (!NT_STATUS_IS_OK(ret)) {
251 0 : DEBUG(1, ("Fatal error while storing new "
252 : "domain->range assignment: %s\n", nt_errstr(ret)));
253 0 : goto error;
254 : }
255 :
256 0 : numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
257 0 : if (!numstr) {
258 0 : ret = NT_STATUS_NO_MEMORY;
259 0 : goto error;
260 : }
261 :
262 0 : ret = dbwrap_store_bystring(db, numstr,
263 : string_term_tdb_data(keystr), TDB_INSERT);
264 :
265 0 : if (!NT_STATUS_IS_OK(ret)) {
266 0 : DEBUG(1, ("Fatal error while storing new "
267 : "domain->range assignment: %s\n", nt_errstr(ret)));
268 0 : goto error;
269 : }
270 :
271 0 : DEBUG(5, ("%s new range #%d for domain %s "
272 : "(domain_range_index=%"PRIu32")\n",
273 : (acquire?"Acquired":"Stored"),
274 : requested_rangenum, keystr,
275 : range->domain_range_index));
276 :
277 0 : range->rangenum = requested_rangenum;
278 :
279 0 : range->low_id = globalcfg.minvalue
280 0 : + range->rangenum * globalcfg.rangesize;
281 0 : range->high_id = range->low_id + globalcfg.rangesize - 1;
282 :
283 0 : ret = NT_STATUS_OK;
284 :
285 0 : error:
286 0 : talloc_free(mem_ctx);
287 0 : return ret;
288 : }
289 :
290 0 : static NTSTATUS idmap_autorid_addrange(struct db_context *db,
291 : struct autorid_range_config *range,
292 : bool acquire)
293 : {
294 0 : NTSTATUS status;
295 0 : struct idmap_autorid_addrange_ctx ctx;
296 :
297 0 : ctx.acquire = acquire;
298 0 : ctx.range = range;
299 :
300 0 : status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
301 0 : return status;
302 : }
303 :
304 0 : NTSTATUS idmap_autorid_setrange(struct db_context *db,
305 : const char *domsid,
306 : uint32_t domain_range_index,
307 : uint32_t rangenum)
308 : {
309 0 : NTSTATUS status;
310 0 : struct autorid_range_config range;
311 :
312 0 : ZERO_STRUCT(range);
313 0 : fstrcpy(range.domsid, domsid);
314 0 : range.domain_range_index = domain_range_index;
315 0 : range.rangenum = rangenum;
316 :
317 0 : status = idmap_autorid_addrange(db, &range, false);
318 0 : return status;
319 : }
320 :
321 0 : NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
322 : struct autorid_range_config *range)
323 : {
324 0 : return idmap_autorid_addrange(db, range, true);
325 : }
326 :
327 0 : static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
328 : struct autorid_range_config *range)
329 : {
330 0 : NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
331 0 : struct autorid_global_config globalcfg = {0};
332 0 : fstring keystr;
333 :
334 0 : if (db == NULL || range == NULL) {
335 0 : DEBUG(3, ("Invalid arguments received\n"));
336 0 : goto done;
337 : }
338 :
339 0 : if (!idmap_autorid_validate_sid(range->domsid)) {
340 0 : DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
341 0 : status = NT_STATUS_INVALID_PARAMETER;
342 0 : goto done;
343 : }
344 :
345 0 : idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
346 : keystr);
347 :
348 0 : DEBUG(10, ("reading domain range for key %s\n", keystr));
349 0 : status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
350 0 : if (!NT_STATUS_IS_OK(status)) {
351 0 : DEBUG(1, ("Failed to read database record for key '%s': %s\n",
352 : keystr, nt_errstr(status)));
353 0 : goto done;
354 : }
355 :
356 0 : status = idmap_autorid_loadconfig(db, &globalcfg);
357 0 : if (!NT_STATUS_IS_OK(status)) {
358 0 : DEBUG(1, ("Failed to read global configuration\n"));
359 0 : goto done;
360 : }
361 0 : range->low_id = globalcfg.minvalue
362 0 : + range->rangenum * globalcfg.rangesize;
363 0 : range->high_id = range->low_id + globalcfg.rangesize - 1;
364 0 : done:
365 0 : return status;
366 : }
367 :
368 0 : NTSTATUS idmap_autorid_getrange(struct db_context *db,
369 : const char *domsid,
370 : uint32_t domain_range_index,
371 : uint32_t *rangenum,
372 : uint32_t *low_id)
373 : {
374 0 : NTSTATUS status;
375 0 : struct autorid_range_config range;
376 :
377 0 : if (rangenum == NULL) {
378 0 : return NT_STATUS_INVALID_PARAMETER;
379 : }
380 :
381 0 : ZERO_STRUCT(range);
382 0 : fstrcpy(range.domsid, domsid);
383 0 : range.domain_range_index = domain_range_index;
384 :
385 0 : status = idmap_autorid_getrange_int(db, &range);
386 0 : if (!NT_STATUS_IS_OK(status)) {
387 0 : return status;
388 : }
389 :
390 0 : *rangenum = range.rangenum;
391 :
392 0 : if (low_id != NULL) {
393 0 : *low_id = range.low_id;
394 : }
395 :
396 0 : return NT_STATUS_OK;
397 : }
398 :
399 0 : NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
400 : struct autorid_range_config *range,
401 : bool read_only)
402 : {
403 0 : NTSTATUS ret;
404 :
405 0 : ret = idmap_autorid_getrange_int(db, range);
406 0 : if (!NT_STATUS_IS_OK(ret)) {
407 0 : DEBUG(10, ("Failed to read range config for '%s': %s\n",
408 : range->domsid, nt_errstr(ret)));
409 0 : if (read_only) {
410 0 : DEBUG(10, ("Not allocating new range for '%s' because "
411 : "read-only is enabled.\n", range->domsid));
412 0 : return NT_STATUS_NOT_FOUND;
413 : }
414 :
415 0 : ret = idmap_autorid_acquire_range(db, range);
416 : }
417 :
418 0 : DEBUG(10, ("Using range #%d for domain %s "
419 : "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
420 : range->rangenum, range->domsid, range->domain_range_index,
421 : range->low_id));
422 :
423 0 : return ret;
424 : }
425 :
426 : /* initialize the given HWM to 0 if it does not exist yet */
427 0 : static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
428 : void *private_data)
429 : {
430 0 : NTSTATUS status;
431 0 : uint32_t hwmval;
432 0 : const char *hwm;
433 :
434 0 : hwm = (char *)private_data;
435 :
436 0 : status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
437 0 : if (NT_STATUS_IS_OK(status)) {
438 0 : DEBUG(1, ("HWM (%s) already initialized in autorid database "
439 : "(value %"PRIu32").\n", hwm, hwmval));
440 0 : return NT_STATUS_OK;
441 : }
442 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
443 0 : DEBUG(0, ("Error fetching HWM (%s) from autorid "
444 : "database: %s\n", hwm, nt_errstr(status)));
445 0 : return status;
446 : }
447 :
448 0 : status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
449 0 : if (!NT_STATUS_IS_OK(status)) {
450 0 : DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
451 : hwm, nt_errstr(status)));
452 0 : return status;
453 : }
454 :
455 0 : return NT_STATUS_OK;
456 : }
457 :
458 0 : NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
459 : {
460 0 : NTSTATUS status;
461 0 : uint32_t hwmval;
462 :
463 0 : status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
464 0 : if (NT_STATUS_IS_OK(status)) {
465 0 : DEBUG(1, ("HWM (%s) already initialized in autorid database "
466 : "(value %"PRIu32").\n", hwm, hwmval));
467 0 : return NT_STATUS_OK;
468 : }
469 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
470 0 : DEBUG(0, ("unable to fetch HWM (%s) from autorid "
471 : "database: %s\n", hwm, nt_errstr(status)));
472 0 : return status;
473 : }
474 :
475 0 : status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
476 : discard_const(hwm));
477 0 : if (!NT_STATUS_IS_OK(status)) {
478 0 : DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
479 : "%s\n", hwm, nt_errstr(status)));
480 0 : return NT_STATUS_INTERNAL_DB_ERROR;
481 : }
482 :
483 0 : DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
484 :
485 0 : return NT_STATUS_OK;
486 : }
487 :
488 : /*
489 : * Delete a domain#index <-> range mapping from the database.
490 : * The mapping is specified by the sid and index.
491 : * If force == true, invalid mapping records are deleted as far
492 : * as possible, otherwise they are left untouched.
493 : */
494 :
495 : struct idmap_autorid_delete_range_by_sid_ctx {
496 : const char *domsid;
497 : uint32_t domain_range_index;
498 : bool force;
499 : };
500 :
501 0 : static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
502 : void *private_data)
503 : {
504 0 : struct idmap_autorid_delete_range_by_sid_ctx *ctx =
505 : (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
506 0 : const char *domsid;
507 0 : uint32_t domain_range_index;
508 0 : uint32_t rangenum;
509 0 : char *keystr;
510 0 : char *range_keystr;
511 0 : TDB_DATA data;
512 0 : NTSTATUS status;
513 0 : TALLOC_CTX *frame = talloc_stackframe();
514 0 : bool is_valid_range_mapping = true;
515 0 : bool force;
516 :
517 0 : domsid = ctx->domsid;
518 0 : domain_range_index = ctx->domain_range_index;
519 0 : force = ctx->force;
520 :
521 0 : keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
522 : domain_range_index);
523 0 : if (keystr == NULL) {
524 0 : status = NT_STATUS_NO_MEMORY;
525 0 : goto done;
526 : }
527 :
528 0 : status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
529 0 : if (!NT_STATUS_IS_OK(status)) {
530 0 : goto done;
531 : }
532 :
533 0 : range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
534 0 : if (range_keystr == NULL) {
535 0 : status = NT_STATUS_NO_MEMORY;
536 0 : goto done;
537 : }
538 :
539 0 : status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
540 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
541 0 : DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
542 : keystr, range_keystr));
543 0 : is_valid_range_mapping = false;
544 0 : } else if (!NT_STATUS_IS_OK(status)) {
545 0 : DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
546 : keystr, range_keystr, nt_errstr(status)));
547 0 : goto done;
548 0 : } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
549 : != 0)
550 : {
551 0 : DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
552 : keystr, range_keystr, (const char *)data.dptr));
553 0 : is_valid_range_mapping = false;
554 : }
555 :
556 0 : if (!is_valid_range_mapping && !force) {
557 0 : DEBUG(10, ("Not deleting invalid mapping, since not in force "
558 : "mode.\n"));
559 0 : status = NT_STATUS_FILE_INVALID;
560 0 : goto done;
561 : }
562 :
563 0 : status = dbwrap_delete_bystring(db, keystr);
564 0 : if (!NT_STATUS_IS_OK(status)) {
565 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
566 : keystr, nt_errstr(status)));
567 0 : goto done;
568 : }
569 :
570 0 : if (!is_valid_range_mapping) {
571 0 : goto done;
572 : }
573 :
574 0 : status = dbwrap_delete_bystring(db, range_keystr);
575 0 : if (!NT_STATUS_IS_OK(status)) {
576 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
577 : range_keystr, nt_errstr(status)));
578 0 : goto done;
579 : }
580 :
581 0 : DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
582 : range_keystr));
583 :
584 0 : done:
585 0 : TALLOC_FREE(frame);
586 0 : return status;
587 : }
588 :
589 0 : NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
590 : const char *domsid,
591 : uint32_t domain_range_index,
592 : bool force)
593 : {
594 0 : NTSTATUS status;
595 0 : struct idmap_autorid_delete_range_by_sid_ctx ctx;
596 :
597 0 : ctx.domain_range_index = domain_range_index;
598 0 : ctx.domsid = domsid;
599 0 : ctx.force = force;
600 :
601 0 : status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
602 : &ctx);
603 0 : return status;
604 : }
605 :
606 : /*
607 : * Delete a domain#index <-> range mapping from the database.
608 : * The mapping is specified by the range number.
609 : * If force == true, invalid mapping records are deleted as far
610 : * as possible, otherwise they are left untouched.
611 : */
612 : struct idmap_autorid_delete_range_by_num_ctx {
613 : uint32_t rangenum;
614 : bool force;
615 : };
616 :
617 0 : static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
618 : void *private_data)
619 : {
620 0 : struct idmap_autorid_delete_range_by_num_ctx *ctx =
621 : (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
622 0 : uint32_t rangenum;
623 0 : char *keystr = NULL;
624 0 : char *range_keystr;
625 0 : TDB_DATA val;
626 0 : NTSTATUS status;
627 0 : TALLOC_CTX *frame = talloc_stackframe();
628 0 : bool is_valid_range_mapping = true;
629 0 : bool force;
630 :
631 0 : rangenum = ctx->rangenum;
632 0 : force = ctx->force;
633 :
634 0 : range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
635 0 : if (range_keystr == NULL) {
636 0 : status = NT_STATUS_NO_MEMORY;
637 0 : goto done;
638 : }
639 :
640 0 : ZERO_STRUCT(val);
641 :
642 0 : status = dbwrap_fetch_bystring(db, frame, range_keystr, &val);
643 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
644 0 : DEBUG(10, ("Did not find range '%s' in database.\n",
645 : range_keystr));
646 0 : goto done;
647 0 : } else if (!NT_STATUS_IS_OK(status)) {
648 0 : DEBUG(5, ("Error fetching rang key: %s\n", nt_errstr(status)));
649 0 : goto done;
650 : }
651 :
652 0 : if (val.dptr == NULL) {
653 0 : DEBUG(1, ("Invalid mapping: %s -> empty value\n",
654 : range_keystr));
655 0 : is_valid_range_mapping = false;
656 : } else {
657 0 : uint32_t reverse_rangenum = 0;
658 :
659 0 : keystr = (char *)val.dptr;
660 :
661 0 : status = dbwrap_fetch_uint32_bystring(db, keystr,
662 : &reverse_rangenum);
663 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
664 0 : DEBUG(1, ("Incomplete mapping %s -> %s: "
665 : "no backward mapping\n",
666 : range_keystr, keystr));
667 0 : is_valid_range_mapping = false;
668 0 : } else if (!NT_STATUS_IS_OK(status)) {
669 0 : DEBUG(1, ("Error fetching reverse mapping for "
670 : "%s -> %s: %s\n",
671 : range_keystr, keystr, nt_errstr(status)));
672 0 : goto done;
673 0 : } else if (rangenum != reverse_rangenum) {
674 0 : is_valid_range_mapping = false;
675 : }
676 : }
677 :
678 0 : if (!is_valid_range_mapping && !force) {
679 0 : DEBUG(10, ("Not deleting invalid mapping, since not in force "
680 : "mode.\n"));
681 0 : status = NT_STATUS_FILE_INVALID;
682 0 : goto done;
683 : }
684 :
685 0 : status = dbwrap_delete_bystring(db, range_keystr);
686 0 : if (!NT_STATUS_IS_OK(status)) {
687 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
688 : range_keystr, nt_errstr(status)));
689 0 : goto done;
690 : }
691 :
692 0 : if (!is_valid_range_mapping) {
693 0 : goto done;
694 : }
695 :
696 0 : status = dbwrap_delete_bystring(db, keystr);
697 0 : if (!NT_STATUS_IS_OK(status)) {
698 0 : DEBUG(1, ("Deletion of '%s' failed: %s\n",
699 : keystr, nt_errstr(status)));
700 0 : goto done;
701 : }
702 :
703 0 : DEBUG(10, ("Deleted range mapping %s <--> %s\n", range_keystr,
704 : keystr));
705 :
706 0 : done:
707 0 : talloc_free(frame);
708 0 : return status;
709 : }
710 :
711 0 : NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
712 : uint32_t rangenum,
713 : bool force)
714 : {
715 0 : NTSTATUS status;
716 0 : struct idmap_autorid_delete_range_by_num_ctx ctx;
717 :
718 0 : ctx.rangenum = rangenum;
719 0 : ctx.force = force;
720 :
721 0 : status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_num_action,
722 : &ctx);
723 0 : return status;
724 : }
725 :
726 : /**
727 : * Open and possibly create the database.
728 : */
729 0 : NTSTATUS idmap_autorid_db_open(const char *path,
730 : TALLOC_CTX *mem_ctx,
731 : struct db_context **db)
732 : {
733 0 : if (*db != NULL) {
734 : /* its already open */
735 0 : return NT_STATUS_OK;
736 : }
737 :
738 : /* Open idmap repository */
739 0 : *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
740 : DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
741 :
742 0 : if (*db == NULL) {
743 0 : DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
744 0 : return NT_STATUS_UNSUCCESSFUL;
745 : }
746 :
747 0 : return NT_STATUS_OK;
748 : }
749 :
750 : /**
751 : * Initialize the high watermark records in the database.
752 : */
753 0 : NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
754 : {
755 0 : NTSTATUS status;
756 :
757 0 : status = idmap_autorid_init_hwm(db, HWM);
758 0 : if (!NT_STATUS_IS_OK(status)) {
759 0 : return status;
760 : }
761 :
762 0 : status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
763 0 : if (!NT_STATUS_IS_OK(status)) {
764 0 : return status;
765 : }
766 :
767 0 : status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
768 :
769 0 : return status;
770 : }
771 :
772 0 : NTSTATUS idmap_autorid_db_init(const char *path,
773 : TALLOC_CTX *mem_ctx,
774 : struct db_context **db)
775 : {
776 0 : NTSTATUS status;
777 :
778 0 : status = idmap_autorid_db_open(path, mem_ctx, db);
779 0 : if (!NT_STATUS_IS_OK(status)) {
780 0 : return status;
781 : }
782 :
783 0 : status = idmap_autorid_init_hwms(*db);
784 0 : return status;
785 : }
786 :
787 :
788 :
789 : struct idmap_autorid_fetch_config_state {
790 : TALLOC_CTX *mem_ctx;
791 : char *configstr;
792 : };
793 :
794 0 : static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
795 : void *private_data)
796 : {
797 0 : struct idmap_autorid_fetch_config_state *state;
798 :
799 0 : state = (struct idmap_autorid_fetch_config_state *)private_data;
800 :
801 : /*
802 : * strndup because we have non-nullterminated strings in the db
803 : */
804 0 : state->configstr = talloc_strndup(
805 0 : state->mem_ctx, (const char *)value.dptr, value.dsize);
806 0 : }
807 :
808 0 : NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
809 : char **result)
810 : {
811 0 : TDB_DATA key;
812 0 : NTSTATUS status;
813 0 : struct idmap_autorid_fetch_config_state state;
814 :
815 0 : if (result == NULL) {
816 0 : return NT_STATUS_INVALID_PARAMETER;
817 : }
818 :
819 0 : key = string_term_tdb_data(CONFIGKEY);
820 :
821 0 : state.mem_ctx = mem_ctx;
822 0 : state.configstr = NULL;
823 :
824 0 : status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
825 : &state);
826 0 : if (!NT_STATUS_IS_OK(status)) {
827 0 : DEBUG(1, ("Error while retrieving config: %s\n",
828 : nt_errstr(status)));
829 0 : return status;
830 : }
831 :
832 0 : if (state.configstr == NULL) {
833 0 : DEBUG(1, ("Error while retrieving config\n"));
834 0 : return NT_STATUS_NO_MEMORY;
835 : }
836 :
837 0 : DEBUG(5, ("found CONFIG: %s\n", state.configstr));
838 :
839 0 : *result = state.configstr;
840 0 : return NT_STATUS_OK;
841 : }
842 :
843 0 : bool idmap_autorid_parse_configstr(const char *configstr,
844 : struct autorid_global_config *cfg)
845 : {
846 0 : unsigned long minvalue, rangesize, maxranges;
847 :
848 0 : if (sscanf(configstr,
849 : "minvalue:%lu rangesize:%lu maxranges:%lu",
850 : &minvalue, &rangesize, &maxranges) != 3) {
851 0 : DEBUG(1,
852 : ("Found invalid configuration data. "
853 : "Creating new config\n"));
854 0 : return false;
855 : }
856 :
857 0 : cfg->minvalue = minvalue;
858 0 : cfg->rangesize = rangesize;
859 0 : cfg->maxranges = maxranges;
860 :
861 0 : return true;
862 : }
863 :
864 0 : NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
865 : struct autorid_global_config *result)
866 : {
867 0 : struct autorid_global_config cfg = {0};
868 0 : NTSTATUS status;
869 0 : bool ok;
870 0 : char *configstr = NULL;
871 :
872 0 : if (result == NULL) {
873 0 : return NT_STATUS_INVALID_PARAMETER;
874 : }
875 :
876 0 : status = idmap_autorid_getconfigstr(db, db, &configstr);
877 0 : if (!NT_STATUS_IS_OK(status)) {
878 0 : return status;
879 : }
880 :
881 0 : ok = idmap_autorid_parse_configstr(configstr, &cfg);
882 0 : TALLOC_FREE(configstr);
883 0 : if (!ok) {
884 0 : return NT_STATUS_INVALID_PARAMETER;
885 : }
886 :
887 0 : DEBUG(10, ("Loaded previously stored configuration "
888 : "minvalue:%d rangesize:%d\n",
889 : cfg.minvalue, cfg.rangesize));
890 :
891 0 : *result = cfg;
892 :
893 0 : return NT_STATUS_OK;
894 : }
895 :
896 0 : NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
897 : struct autorid_global_config *cfg)
898 : {
899 :
900 0 : struct autorid_global_config storedconfig = {0};
901 0 : NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
902 0 : TDB_DATA data;
903 0 : char *cfgstr;
904 0 : uint32_t hwm;
905 0 : TALLOC_CTX *frame = talloc_stackframe();
906 :
907 0 : DEBUG(10, ("New configuration provided for storing is "
908 : "minvalue:%d rangesize:%d maxranges:%d\n",
909 : cfg->minvalue, cfg->rangesize, cfg->maxranges));
910 :
911 0 : if (cfg->rangesize < 2000) {
912 0 : DEBUG(1, ("autorid rangesize must be at least 2000\n"));
913 0 : goto done;
914 : }
915 :
916 0 : if (cfg->maxranges == 0) {
917 0 : DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
918 : "Must have at least one range available.\n"));
919 0 : goto done;
920 : }
921 :
922 0 : status = idmap_autorid_loadconfig(db, &storedconfig);
923 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
924 0 : DEBUG(5, ("No configuration found. Storing initial "
925 : "configuration.\n"));
926 0 : storedconfig = *cfg;
927 0 : } else if (!NT_STATUS_IS_OK(status)) {
928 0 : DEBUG(1, ("Error loading configuration: %s\n",
929 : nt_errstr(status)));
930 0 : goto done;
931 : }
932 :
933 : /* did the minimum value or rangesize change? */
934 0 : if ((storedconfig.minvalue != cfg->minvalue) ||
935 0 : (storedconfig.rangesize != cfg->rangesize))
936 : {
937 0 : DEBUG(1, ("New configuration values for rangesize or "
938 : "minimum uid value conflict with previously "
939 : "used values! Not storing new config.\n"));
940 0 : status = NT_STATUS_INVALID_PARAMETER;
941 0 : goto done;
942 : }
943 :
944 0 : status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
945 0 : if (!NT_STATUS_IS_OK(status)) {
946 0 : DEBUG(1, ("Fatal error while fetching current "
947 : "HWM value: %s\n", nt_errstr(status)));
948 0 : status = NT_STATUS_INTERNAL_ERROR;
949 0 : goto done;
950 : }
951 :
952 : /*
953 : * has the highest uid value been reduced to setting that is not
954 : * sufficient any more for already existing ranges?
955 : */
956 0 : if (hwm > cfg->maxranges) {
957 0 : DEBUG(1, ("New upper uid limit is too low to cover "
958 : "existing mappings! Not storing new config.\n"));
959 0 : status = NT_STATUS_INVALID_PARAMETER;
960 0 : goto done;
961 : }
962 :
963 0 : cfgstr =
964 0 : talloc_asprintf(frame,
965 : "minvalue:%u rangesize:%u maxranges:%u",
966 : cfg->minvalue, cfg->rangesize, cfg->maxranges);
967 :
968 0 : if (cfgstr == NULL) {
969 0 : status = NT_STATUS_NO_MEMORY;
970 0 : goto done;
971 : }
972 :
973 0 : data = string_tdb_data(cfgstr);
974 :
975 0 : status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);
976 :
977 0 : done:
978 0 : TALLOC_FREE(frame);
979 0 : return status;
980 : }
981 :
982 0 : NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
983 : const char *configstr)
984 : {
985 0 : bool ok;
986 0 : NTSTATUS status;
987 0 : struct autorid_global_config cfg;
988 :
989 0 : ok = idmap_autorid_parse_configstr(configstr, &cfg);
990 0 : if (!ok) {
991 0 : return NT_STATUS_INVALID_PARAMETER;
992 : }
993 :
994 0 : status = idmap_autorid_saveconfig(db, &cfg);
995 0 : return status;
996 : }
997 :
998 :
999 : /*
1000 : * iteration: Work on all range mappings for a given domain
1001 : */
1002 :
1003 : struct domain_range_visitor_ctx {
1004 : const char *domsid;
1005 : NTSTATUS (*fn)(struct db_context *db,
1006 : const char *domsid,
1007 : uint32_t index,
1008 : uint32_t rangenum,
1009 : void *private_data);
1010 : void *private_data;
1011 : int count; /* number of records worked on */
1012 : };
1013 :
1014 0 : static int idmap_autorid_visit_domain_range(struct db_record *rec,
1015 : void *private_data)
1016 : {
1017 0 : struct domain_range_visitor_ctx *vi;
1018 0 : char *domsid;
1019 0 : char *sep;
1020 0 : uint32_t range_index = 0;
1021 0 : uint32_t rangenum = 0;
1022 0 : TDB_DATA key, value;
1023 0 : NTSTATUS status;
1024 0 : int ret = 0;
1025 0 : struct db_context *db;
1026 :
1027 0 : vi = talloc_get_type_abort(private_data,
1028 : struct domain_range_visitor_ctx);
1029 :
1030 0 : key = dbwrap_record_get_key(rec);
1031 :
1032 : /*
1033 : * split string "<sid>[#<index>]" into sid string and index number
1034 : */
1035 :
1036 0 : domsid = (char *)key.dptr;
1037 :
1038 0 : DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
1039 : domsid));
1040 :
1041 0 : sep = strrchr(domsid, '#');
1042 0 : if (sep != NULL) {
1043 0 : char *index_str;
1044 0 : *sep = '\0';
1045 0 : index_str = sep+1;
1046 0 : if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
1047 0 : DEBUG(10, ("Found separator '#' but '%s' is not a "
1048 : "valid range index. Skipping record\n",
1049 : index_str));
1050 0 : goto done;
1051 : }
1052 : }
1053 :
1054 0 : if (!idmap_autorid_validate_sid(domsid)) {
1055 0 : DEBUG(10, ("String '%s' is not a valid sid. "
1056 : "Skipping record.\n", domsid));
1057 0 : goto done;
1058 : }
1059 :
1060 0 : if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
1061 0 : DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
1062 : domsid, vi->domsid));
1063 0 : goto done;
1064 : }
1065 :
1066 0 : value = dbwrap_record_get_value(rec);
1067 :
1068 0 : if (value.dsize != sizeof(uint32_t)) {
1069 : /* it might be a mapping of a well known sid */
1070 0 : DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
1071 : "skipping.\n", (unsigned)value.dsize, vi->domsid));
1072 0 : goto done;
1073 : }
1074 :
1075 0 : rangenum = IVAL(value.dptr, 0);
1076 :
1077 0 : db = dbwrap_record_get_db(rec);
1078 :
1079 0 : status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
1080 0 : if (!NT_STATUS_IS_OK(status)) {
1081 0 : ret = -1;
1082 0 : goto done;
1083 : }
1084 :
1085 0 : vi->count++;
1086 0 : ret = 0;
1087 :
1088 0 : done:
1089 0 : return ret;
1090 : }
1091 :
1092 0 : static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
1093 : const char *domsid,
1094 : NTSTATUS (*fn)(struct db_context *db,
1095 : const char *domsid,
1096 : uint32_t index,
1097 : uint32_t rangnum,
1098 : void *private_data),
1099 : void *private_data,
1100 : int *count,
1101 : NTSTATUS (*traverse)(struct db_context *db,
1102 : int (*f)(struct db_record *, void *),
1103 : void *private_data,
1104 : int *count))
1105 : {
1106 0 : NTSTATUS status;
1107 0 : struct domain_range_visitor_ctx *vi;
1108 0 : TALLOC_CTX *frame = talloc_stackframe();
1109 :
1110 0 : if (domsid == NULL) {
1111 0 : DEBUG(10, ("No sid provided, operating on all ranges\n"));
1112 : }
1113 :
1114 0 : if (fn == NULL) {
1115 0 : DEBUG(1, ("Error: missing visitor callback\n"));
1116 0 : status = NT_STATUS_INVALID_PARAMETER;
1117 0 : goto done;
1118 : }
1119 :
1120 0 : vi = talloc_zero(frame, struct domain_range_visitor_ctx);
1121 0 : if (vi == NULL) {
1122 0 : status = NT_STATUS_NO_MEMORY;
1123 0 : goto done;
1124 : }
1125 :
1126 0 : vi->domsid = domsid;
1127 0 : vi->fn = fn;
1128 0 : vi->private_data = private_data;
1129 :
1130 0 : status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
1131 0 : if (!NT_STATUS_IS_OK(status)) {
1132 0 : goto done;
1133 : }
1134 :
1135 0 : if (count != NULL) {
1136 0 : *count = vi->count;
1137 : }
1138 :
1139 0 : done:
1140 0 : talloc_free(frame);
1141 0 : return status;
1142 : }
1143 :
1144 0 : NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
1145 : const char *domsid,
1146 : NTSTATUS (*fn)(struct db_context *db,
1147 : const char *domsid,
1148 : uint32_t index,
1149 : uint32_t rangenum,
1150 : void *private_data),
1151 : void *private_data,
1152 : int *count)
1153 : {
1154 0 : NTSTATUS status;
1155 :
1156 0 : status = idmap_autorid_iterate_domain_ranges_int(db,
1157 : domsid,
1158 : fn,
1159 : private_data,
1160 : count,
1161 : dbwrap_traverse);
1162 :
1163 0 : return status;
1164 : }
1165 :
1166 :
1167 0 : NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
1168 : const char *domsid,
1169 : NTSTATUS (*fn)(struct db_context *db,
1170 : const char *domsid,
1171 : uint32_t index,
1172 : uint32_t rangenum,
1173 : void *count),
1174 : void *private_data,
1175 : int *count)
1176 : {
1177 0 : NTSTATUS status;
1178 :
1179 0 : status = idmap_autorid_iterate_domain_ranges_int(db,
1180 : domsid,
1181 : fn,
1182 : private_data,
1183 : count,
1184 : dbwrap_traverse_read);
1185 :
1186 0 : return status;
1187 : }
1188 :
1189 :
1190 : /*
1191 : * Delete all ranges configured for a given domain
1192 : */
1193 :
1194 : struct delete_domain_ranges_visitor_ctx {
1195 : bool force;
1196 : };
1197 :
1198 0 : static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
1199 : struct db_context *db,
1200 : const char *domsid,
1201 : uint32_t domain_range_index,
1202 : uint32_t rangenum,
1203 : void *private_data)
1204 : {
1205 0 : struct delete_domain_ranges_visitor_ctx *ctx;
1206 0 : NTSTATUS status;
1207 :
1208 0 : ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
1209 :
1210 0 : status = idmap_autorid_delete_range_by_sid(
1211 0 : db, domsid, domain_range_index, ctx->force);
1212 0 : return status;
1213 : }
1214 :
1215 : struct idmap_autorid_delete_domain_ranges_ctx {
1216 : const char *domsid;
1217 : bool force;
1218 : int count; /* output: count records operated on */
1219 : };
1220 :
1221 0 : static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
1222 : void *private_data)
1223 : {
1224 0 : struct idmap_autorid_delete_domain_ranges_ctx *ctx;
1225 0 : struct delete_domain_ranges_visitor_ctx visitor_ctx;
1226 0 : int count;
1227 0 : NTSTATUS status;
1228 :
1229 0 : ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
1230 :
1231 0 : ZERO_STRUCT(visitor_ctx);
1232 0 : visitor_ctx.force = ctx->force;
1233 :
1234 0 : status = idmap_autorid_iterate_domain_ranges(db,
1235 : ctx->domsid,
1236 : idmap_autorid_delete_domain_ranges_visitor,
1237 : &visitor_ctx,
1238 : &count);
1239 0 : if (!NT_STATUS_IS_OK(status)) {
1240 0 : return status;
1241 : }
1242 :
1243 0 : ctx->count = count;
1244 :
1245 0 : return NT_STATUS_OK;
1246 : }
1247 :
1248 0 : NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
1249 : const char *domsid,
1250 : bool force,
1251 : int *count)
1252 : {
1253 0 : NTSTATUS status;
1254 0 : struct idmap_autorid_delete_domain_ranges_ctx ctx;
1255 :
1256 0 : ZERO_STRUCT(ctx);
1257 0 : ctx.domsid = domsid;
1258 0 : ctx.force = force;
1259 :
1260 0 : status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
1261 : &ctx);
1262 0 : if (!NT_STATUS_IS_OK(status)) {
1263 0 : return status;
1264 : }
1265 :
1266 0 : *count = ctx.count;
1267 :
1268 0 : return NT_STATUS_OK;
1269 : }
|