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