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