dbwrap: add a dbwrap_flags argument to db_open()
[samba.git] / source3 / utils / net_idmap.c
1 /*
2    Samba Unix/Linux SMB client library
3    Distributed SMB/CIFS Server Management Utility
4    Copyright (C) 2003 Andrew Bartlett (abartlet@samba.org)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "utils/net.h"
23 #include "secrets.h"
24 #include "idmap.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "../libcli/security/security.h"
28 #include "net_idmap_check.h"
29 #include "util_tdb.h"
30 #include "idmap_autorid_tdb.h"
31
32 #define ALLOC_CHECK(mem) do { \
33         if (!mem) { \
34                 d_fprintf(stderr, _("Out of memory!\n")); \
35                 talloc_free(ctx); \
36                 return -1; \
37         } } while(0)
38
39 enum idmap_dump_backend {
40         TDB,
41         AUTORID
42 };
43
44 struct net_idmap_ctx {
45         enum idmap_dump_backend backend;
46 };
47
48 static int net_idmap_dump_one_autorid_entry(struct db_record *rec,
49                                             void *unused)
50 {
51         TDB_DATA key;
52         TDB_DATA value;
53
54         key = dbwrap_record_get_key(rec);
55         value = dbwrap_record_get_value(rec);
56
57         if (strncmp((char *)key.dptr, "CONFIG", 6) == 0) {
58                 char *config = talloc_array(talloc_tos(), char, value.dsize+1);
59                 memcpy(config, value.dptr, value.dsize);
60                 config[value.dsize] = '\0';
61                 printf("CONFIG: %s\n", config);
62                 talloc_free(config);
63                 return 0;
64         }
65
66         if (strncmp((char *)key.dptr, "NEXT RANGE", 10) == 0) {
67                 printf("RANGE HWM: %"PRIu32"\n", IVAL(value.dptr, 0));
68                 return 0;
69         }
70
71         if (strncmp((char *)key.dptr, "NEXT ALLOC UID", 14) == 0) {
72                 printf("UID HWM: %"PRIu32"\n", IVAL(value.dptr, 0));
73                 return 0;
74         }
75
76         if (strncmp((char *)key.dptr, "NEXT ALLOC GID", 14) == 0) {
77                 printf("GID HWM: %"PRIu32"\n", IVAL(value.dptr, 0));
78                 return 0;
79         }
80
81         if (strncmp((char *)key.dptr, "UID", 3) == 0 ||
82             strncmp((char *)key.dptr, "GID", 3) == 0)
83         {
84                 /* mapped entry from allocation pool */
85                 printf("%s %s\n", value.dptr, key.dptr);
86                 return 0;
87         }
88
89         if ((strncmp((char *)key.dptr, "S-1-5-", 6) == 0 ||
90              strncmp((char *)key.dptr, "ALLOC", 5) == 0) &&
91             value.dsize == sizeof(uint32_t))
92         {
93                 /* this is a domain range assignment */
94                 uint32_t range = IVAL(value.dptr, 0);
95                 printf("RANGE %"PRIu32": %s\n", range, key.dptr);
96                 return 0;
97         }
98
99         return 0;
100 }
101
102 /***********************************************************
103  Helper function for net_idmap_dump. Dump one entry.
104  **********************************************************/
105 static int net_idmap_dump_one_tdb_entry(struct db_record *rec,
106                                         void *unused)
107 {
108         TDB_DATA key;
109         TDB_DATA value;
110
111         key = dbwrap_record_get_key(rec);
112         value = dbwrap_record_get_value(rec);
113
114         if (strcmp((char *)key.dptr, "USER HWM") == 0) {
115                 printf(_("USER HWM %d\n"), IVAL(value.dptr,0));
116                 return 0;
117         }
118
119         if (strcmp((char *)key.dptr, "GROUP HWM") == 0) {
120                 printf(_("GROUP HWM %d\n"), IVAL(value.dptr,0));
121                 return 0;
122         }
123
124         if (strncmp((char *)key.dptr, "S-", 2) != 0) {
125                 return 0;
126         }
127
128         printf("%s %s\n", value.dptr, key.dptr);
129         return 0;
130 }
131
132 static const char* net_idmap_dbfile(struct net_context *c,
133                                     struct net_idmap_ctx *ctx)
134 {
135         const char* dbfile = NULL;
136         const char *backend = NULL;
137
138         backend = lp_idmap_default_backend();
139         if (!backend) {
140                 d_printf(_("Internal error: 'idmap config * : backend' is not set!\n"));
141                 return NULL;
142         }
143
144         if (c->opt_db != NULL) {
145                 dbfile = talloc_strdup(talloc_tos(), c->opt_db);
146                 if (dbfile == NULL) {
147                         d_fprintf(stderr, _("Out of memory!\n"));
148                 }
149         } else if (strequal(backend, "tdb")) {
150                 dbfile = state_path("winbindd_idmap.tdb");
151                 if (dbfile == NULL) {
152                         d_fprintf(stderr, _("Out of memory!\n"));
153                 }
154                 ctx->backend = TDB;
155         } else if (strequal(backend, "tdb2")) {
156                 dbfile = talloc_asprintf(talloc_tos(), "%s/idmap2.tdb",
157                                          lp_private_dir());
158                 if (dbfile == NULL) {
159                         d_fprintf(stderr, _("Out of memory!\n"));
160                 }
161                 ctx->backend = TDB;
162         } else if (strequal(backend, "autorid")) {
163                 dbfile = state_path("autorid.tdb");
164                 if (dbfile == NULL) {
165                         d_fprintf(stderr, _("Out of memory!\n"));
166                 }
167                 ctx->backend = AUTORID;
168         } else {
169                 char *_backend = talloc_strdup(talloc_tos(), backend);
170                 char* args = strchr(_backend, ':');
171                 if (args != NULL) {
172                         *args = '\0';
173                 }
174
175                 d_printf(_("Sorry, 'idmap backend = %s' is currently not supported\n"),
176                            _backend);
177
178                 talloc_free(_backend);
179         }
180
181         return dbfile;
182 }
183
184 static bool net_idmap_opendb_autorid(TALLOC_CTX *mem_ctx,
185                                      struct net_context *c,
186                                      bool readonly,
187                                      struct db_context **db)
188 {
189         bool ret = false;
190         const char *dbfile;
191         struct net_idmap_ctx ctx = { .backend = AUTORID };
192
193         if (c == NULL) {
194                 goto done;
195         }
196
197         dbfile = net_idmap_dbfile(c, &ctx);
198         if (dbfile == NULL) {
199                 goto done;
200         }
201
202         if (ctx.backend != AUTORID) {
203                 d_fprintf(stderr, _("Unsupported backend\n"));
204                 goto done;
205         }
206
207         if (readonly) {
208                 *db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDONLY, 0,
209                              DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
210                 if (*db == NULL) {
211                         d_fprintf(stderr,
212                                   _("Could not open autorid db (%s): %s\n"),
213                                  dbfile, strerror(errno));
214                         goto done;
215                 }
216         } else {
217                 NTSTATUS status;
218                 status = idmap_autorid_db_init(dbfile, mem_ctx, db);
219                 if (!NT_STATUS_IS_OK(status)) {
220                         d_fprintf(stderr,
221                                 _("Error calling idmap_autorid_db_init: %s\n"),
222                                 nt_errstr(status));
223                         goto done;
224                 }
225         }
226
227         ret = true;
228
229 done:
230         return ret;
231 }
232
233
234 /***********************************************************
235  Dump the current idmap
236  **********************************************************/
237 static int net_idmap_dump(struct net_context *c, int argc, const char **argv)
238 {
239         struct db_context *db;
240         TALLOC_CTX *mem_ctx;
241         const char* dbfile;
242         NTSTATUS status;
243         int ret = -1;
244         struct net_idmap_ctx ctx = { .backend = TDB };
245
246         if ( argc > 1  || c->display_usage) {
247                 d_printf("%s\n%s",
248                          _("Usage:"),
249                          _("net idmap dump [[--db=]<inputfile>]\n"
250                            "  Dump current ID mapping.\n"
251                            "    inputfile\tTDB file to read mappings from.\n"));
252                 return c->display_usage?0:-1;
253         }
254
255         mem_ctx = talloc_stackframe();
256
257         dbfile = (argc > 0) ? argv[0] : net_idmap_dbfile(c, &ctx);
258         if (dbfile == NULL) {
259                 goto done;
260         }
261         d_fprintf(stderr, _("dumping id mapping from %s\n"), dbfile);
262
263         db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDONLY, 0,
264                      DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
265         if (db == NULL) {
266                 d_fprintf(stderr, _("Could not open idmap db (%s): %s\n"),
267                           dbfile, strerror(errno));
268                 goto done;
269         }
270
271         if (ctx.backend == AUTORID) {
272                 status = dbwrap_traverse_read(db,
273                                               net_idmap_dump_one_autorid_entry,
274                                               NULL, NULL);
275         } else {
276                 status = dbwrap_traverse_read(db,
277                                               net_idmap_dump_one_tdb_entry,
278                                               NULL, NULL);
279         }
280         if (!NT_STATUS_IS_OK(status)) {
281                 d_fprintf(stderr, _("error traversing the database\n"));
282                 ret = -1;
283                 goto done;
284         }
285
286         ret = 0;
287
288 done:
289         talloc_free(mem_ctx);
290         return ret;
291 }
292
293 /***********************************************************
294  Write entries from stdin to current local idmap
295  **********************************************************/
296
297 static int net_idmap_store_id_mapping(struct db_context *db,
298                                       enum id_type type,
299                                       unsigned long idval,
300                                       const char *sid_string)
301 {
302         NTSTATUS status;
303         char *idstr = NULL;
304
305         switch(type) {
306         case ID_TYPE_UID:
307                 idstr = talloc_asprintf(talloc_tos(), "UID %lu", idval);
308                 break;
309         case ID_TYPE_GID:
310                 idstr = talloc_asprintf(talloc_tos(), "GID %lu", idval);
311                 break;
312         default:
313                 d_fprintf(stderr, "Invalid id mapping type: %d\n", type);
314                 return -1;
315         }
316
317         status = dbwrap_store_bystring(db, idstr,
318                                        string_term_tdb_data(sid_string),
319                                        TDB_REPLACE);
320         if (!NT_STATUS_IS_OK(status)) {
321                 d_fprintf(stderr, "Error storing ID -> SID: "
322                          "%s\n", nt_errstr(status));
323                 talloc_free(idstr);
324                 return -1;
325         }
326         status = dbwrap_store_bystring(db, sid_string,
327                                        string_term_tdb_data(idstr),
328                                        TDB_REPLACE);
329         if (!NT_STATUS_IS_OK(status)) {
330                 d_fprintf(stderr, "Error storing SID -> ID: "
331                          "%s\n", nt_errstr(status));
332                 talloc_free(idstr);
333                 return -1;
334         }
335
336         return 0;
337 }
338
339 static int net_idmap_restore(struct net_context *c, int argc, const char **argv)
340 {
341         TALLOC_CTX *mem_ctx;
342         FILE *input = NULL;
343         struct db_context *db;
344         const char *dbfile = NULL;
345         int ret = 0;
346         struct net_idmap_ctx ctx = { .backend = TDB };
347
348         if (c->display_usage) {
349                 d_printf("%s\n%s",
350                          _("Usage:"),
351                          _("net idmap restore [--db=<TDB>] [<inputfile>]\n"
352                            "  Restore ID mappings from file\n"
353                            "    TDB\tFile to store ID mappings to."
354                            "    inputfile\tFile to load ID mappings from. If not "
355                            "given, load data from stdin.\n"));
356                 return 0;
357         }
358
359         mem_ctx = talloc_stackframe();
360
361         dbfile = net_idmap_dbfile(c, &ctx);
362
363         if (dbfile == NULL) {
364                 ret = -1;
365                 goto done;
366         }
367
368         if (ctx.backend != TDB) {
369                 d_fprintf(stderr, _("Sorry, restoring of non-TDB databases is "
370                                     "currently not supported\n"));
371                 ret = -1;
372                 goto done;
373         }
374
375         d_fprintf(stderr, _("restoring id mapping to %s\n"), dbfile);
376
377         if (argc == 1) {
378                 input = fopen(argv[0], "r");
379                 if (input == NULL) {
380                         d_fprintf(stderr, _("Could not open input file (%s): %s\n"),
381                                   argv[0], strerror(errno));
382                         ret = -1;
383                         goto done;
384                 }
385         } else {
386                 input = stdin;
387         }
388
389         db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644,
390                      DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
391         if (db == NULL) {
392                 d_fprintf(stderr, _("Could not open idmap db (%s): %s\n"),
393                           dbfile, strerror(errno));
394                 ret = -1;
395                 goto done;
396         }
397
398         if (dbwrap_transaction_start(db) != 0) {
399                 d_fprintf(stderr, _("Failed to start transaction.\n"));
400                 ret = -1;
401                 goto done;
402         }
403
404         while (!feof(input)) {
405                 char line[128], sid_string[128];
406                 int len;
407                 unsigned long idval;
408                 NTSTATUS status;
409
410                 if (fgets(line, 127, input) == NULL)
411                         break;
412
413                 len = strlen(line);
414
415                 if ( (len > 0) && (line[len-1] == '\n') )
416                         line[len-1] = '\0';
417
418                 if (sscanf(line, "GID %lu %128s", &idval, sid_string) == 2)
419                 {
420                         ret = net_idmap_store_id_mapping(db, ID_TYPE_GID,
421                                                          idval, sid_string);
422                         if (ret != 0) {
423                                 break;
424                         }
425                 } else if (sscanf(line, "UID %lu %128s", &idval, sid_string) == 2)
426                 {
427                         ret = net_idmap_store_id_mapping(db, ID_TYPE_UID,
428                                                          idval, sid_string);
429                         if (ret != 0) {
430                                 break;
431                         }
432                 } else if (sscanf(line, "USER HWM %lu", &idval) == 1) {
433                         status = dbwrap_store_int32_bystring(
434                                 db, "USER HWM", idval);
435                         if (!NT_STATUS_IS_OK(status)) {
436                                 d_fprintf(stderr,
437                                           _("Could not store USER HWM: %s\n"),
438                                           nt_errstr(status));
439                                 break;
440                         }
441                 } else if (sscanf(line, "GROUP HWM %lu", &idval) == 1) {
442                         status = dbwrap_store_int32_bystring(
443                                 db, "GROUP HWM", idval);
444                         if (!NT_STATUS_IS_OK(status)) {
445                                 d_fprintf(stderr,
446                                           _("Could not store GROUP HWM: %s\n"),
447                                           nt_errstr(status));
448                                 break;
449                         }
450                 } else {
451                         d_fprintf(stderr, _("ignoring invalid line [%s]\n"),
452                                   line);
453                         continue;
454                 }
455         }
456
457         if (ret == 0) {
458                 if(dbwrap_transaction_commit(db) != 0) {
459                         d_fprintf(stderr, _("Failed to commit transaction.\n"));
460                         ret = -1;
461                 }
462         } else {
463                 if (dbwrap_transaction_cancel(db) != 0) {
464                         d_fprintf(stderr, _("Failed to cancel transaction.\n"));
465                 }
466         }
467
468 done:
469         if ((input != NULL) && (input != stdin)) {
470                 fclose(input);
471         }
472
473         talloc_free(mem_ctx);
474         return ret;
475 }
476
477 static
478 NTSTATUS dbwrap_delete_mapping(struct db_context *db, TDB_DATA key1, bool force)
479 {
480         TALLOC_CTX *mem_ctx = talloc_stackframe();
481         bool is_valid_mapping;
482         NTSTATUS status = NT_STATUS_OK;
483         TDB_DATA val1, val2;
484
485         ZERO_STRUCT(val1);
486         ZERO_STRUCT(val2);
487
488         status = dbwrap_fetch(db, mem_ctx, key1, &val1);
489         if (!NT_STATUS_IS_OK(status)) {
490                 DEBUG(1, ("failed to fetch: %.*s\n", (int)key1.dsize, key1.dptr));
491                 goto done;
492         }
493
494         if (val1.dptr == NULL) {
495                 DEBUG(1, ("invalid mapping: %.*s -> empty value\n",
496                           (int)key1.dsize, key1.dptr));
497                 status = NT_STATUS_FILE_INVALID;
498                 goto done;
499         }
500
501         DEBUG(2, ("mapping: %.*s -> %.*s\n",
502                   (int)key1.dsize, key1.dptr, (int)val1.dsize, val1.dptr));
503
504         status = dbwrap_fetch(db, mem_ctx, val1, &val2);
505         if (!NT_STATUS_IS_OK(status)) {
506                 DEBUG(1, ("failed to fetch: %.*s\n", (int)val1.dsize, val1.dptr));
507                 goto done;
508         }
509
510         is_valid_mapping = tdb_data_equal(key1, val2);
511
512         if (!is_valid_mapping) {
513                 DEBUG(1, ("invalid mapping: %.*s -> %.*s -> %.*s\n",
514                           (int)key1.dsize, key1.dptr,
515                           (int)val1.dsize, val1.dptr,
516                           (int)val2.dsize, val2.dptr));
517                 if ( !force ) {
518                         status = NT_STATUS_FILE_INVALID;
519                         goto done;
520                 }
521         }
522
523         status = dbwrap_delete(db, key1);
524         if (!NT_STATUS_IS_OK(status)) {
525                 DEBUG(1, ("failed to delete: %.*s\n", (int)key1.dsize, key1.dptr));
526                 goto done;
527         }
528
529         if (!is_valid_mapping) {
530                 goto done;
531         }
532
533         status = dbwrap_delete(db, val1);
534         if (!NT_STATUS_IS_OK(status)) {
535                 DEBUG(1, ("failed to delete: %.*s\n", (int)val1.dsize, val1.dptr));
536         }
537
538 done:
539         talloc_free(mem_ctx);
540         return status;
541 }
542
543 static
544 NTSTATUS delete_mapping_action(struct db_context *db, void* data)
545 {
546         return dbwrap_delete_mapping(db, *(TDB_DATA*)data, false);
547 }
548 static
549 NTSTATUS delete_mapping_action_force(struct db_context *db, void* data)
550 {
551         return dbwrap_delete_mapping(db, *(TDB_DATA*)data, true);
552 }
553
554 /***********************************************************
555  Delete a SID mapping from a winbindd_idmap.tdb
556  **********************************************************/
557 static bool delete_args_ok(int argc, const char **argv)
558 {
559         if (argc != 1)
560                 return false;
561         if (strncmp(argv[0], "S-", 2) == 0)
562                 return true;
563         if (strncmp(argv[0], "GID ", 4) == 0)
564                 return true;
565         if (strncmp(argv[0], "UID ", 4) == 0)
566                 return true;
567         return false;
568 }
569
570 static int net_idmap_delete_mapping(struct net_context *c, int argc,
571                                     const char **argv)
572 {
573         int ret = -1;
574         struct db_context *db;
575         TALLOC_CTX *mem_ctx;
576         TDB_DATA key;
577         NTSTATUS status;
578         const char* dbfile;
579         struct net_idmap_ctx ctx = { .backend = TDB };
580
581         if ( !delete_args_ok(argc,argv) || c->display_usage) {
582                 d_printf("%s\n%s",
583                          _("Usage:"),
584                          _("net idmap delete mapping [-f] [--db=<TDB>] <ID>\n"
585                            "  Delete mapping of ID from TDB.\n"
586                            "    -f\tforce\n"
587                            "    TDB\tidmap database\n"
588                            "    ID\tSID|GID|UID\n"));
589                 return c->display_usage ? 0 : -1;
590         }
591
592         mem_ctx = talloc_stackframe();
593
594         dbfile = net_idmap_dbfile(c, &ctx);
595         if (dbfile == NULL) {
596                 goto done;
597         }
598         d_fprintf(stderr, _("deleting id mapping from %s\n"), dbfile);
599
600         db = db_open(mem_ctx, dbfile, 0, TDB_DEFAULT, O_RDWR, 0,
601                      DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
602         if (db == NULL) {
603                 d_fprintf(stderr, _("Could not open idmap db (%s): %s\n"),
604                           dbfile, strerror(errno));
605                 goto done;
606         }
607
608         key = string_term_tdb_data(argv[0]);
609
610         status = dbwrap_trans_do(db, (c->opt_force
611                                       ? delete_mapping_action_force
612                                       : delete_mapping_action),  &key);
613
614         if (!NT_STATUS_IS_OK(status)) {
615                 d_fprintf(stderr, _("could not delete mapping: %s\n"),
616                           nt_errstr(status));
617                 goto done;
618         }
619         ret = 0;
620 done:
621         talloc_free(mem_ctx);
622         return ret;
623 }
624
625 static bool parse_uint32(const char *str, uint32_t *result)
626 {
627         unsigned long val;
628         char *endptr;
629
630         val = strtoul(str, &endptr, 10);
631
632         if (str == endptr) {
633                 return false;
634         }
635         if (*endptr != '\0') {
636                 return false;
637         }
638         if ((val == ULONG_MAX) && (errno == ERANGE)) {
639                 return false;
640         }
641         if ((val & UINT32_MAX) != val) {
642                 /* overflow */
643                 return false;
644         }
645         *result = val;          /* Potential crop */
646         return true;
647 }
648
649 static void net_idmap_autorid_delete_range_usage(void)
650 {
651         d_printf("%s\n%s",
652                  _("Usage:"),
653                  _("net idmap delete range [-f] [--db=<TDB>] <RANGE>|(<SID>[ <INDEX>])\n"
654                    "  Delete a domain range mapping from the database.\n"
655                    "    -f\tforce\n"
656                    "    TDB\tidmap database\n"
657                    "    RANGE\tthe range number to delete\n"
658                    "    SID\t\tSID of the domain\n"
659                    "    INDEX\trange index number do delete for the domain\n"));
660 }
661
662 static int net_idmap_autorid_delete_range(struct net_context *c, int argc,
663                                           const char **argv)
664 {
665         int ret = -1;
666         struct db_context *db = NULL;
667         NTSTATUS status;
668         uint32_t rangenum;
669         uint32_t range_index;
670         const char *domsid;
671         TALLOC_CTX *mem_ctx = NULL;
672         bool ok;
673         bool force = (c->opt_force != 0);
674
675         if (c->display_usage) {
676                 net_idmap_autorid_delete_range_usage();
677                 return 0;
678         }
679
680         if (argc < 1 || argc > 2) {
681                 net_idmap_autorid_delete_range_usage();
682                 return -1;
683         }
684
685         mem_ctx = talloc_stackframe();
686         if (!net_idmap_opendb_autorid(mem_ctx, c, false, &db)) {
687                 goto done;
688         }
689
690         ok = parse_uint32(argv[0], &rangenum);
691         if (ok) {
692                 d_printf("%s: %"PRIu32"\n", _("Deleting range number"),
693                          rangenum);
694
695                 status = idmap_autorid_delete_range_by_num(db, rangenum,
696                                                            force);
697                 if (!NT_STATUS_IS_OK(status)) {
698                         d_fprintf(stderr, "%s: %s\n",
699                                   _("Failed to delete domain range mapping"),
700                                   nt_errstr(status));
701                 } else {
702                         ret = 0;
703                 }
704
705                 goto done;
706         }
707
708         domsid = argv[0];
709         range_index = 0;
710
711         if (argc == 2) {
712                 ok = parse_uint32(argv[1], &range_index);
713                 if (!ok) {
714                         d_printf("%s: %s\n",
715                                  _("Invalid index specification"), argv[1]);
716                         net_idmap_autorid_delete_range_usage();
717                         goto done;
718                 }
719         }
720
721         status = idmap_autorid_delete_range_by_sid(db, domsid, range_index,
722                                                    force);
723         if (!NT_STATUS_IS_OK(status)) {
724                 d_fprintf(stderr, "%s: %s\n",
725                           _("Failed to delete domain range mapping"),
726                           nt_errstr(status));
727                 goto done;
728         }
729
730         ret = 0;
731
732 done:
733         talloc_free(mem_ctx);
734         return ret;
735 }
736
737 static void net_idmap_autorid_delete_ranges_usage(void)
738 {
739         d_printf("%s\n%s",
740                  _("Usage:"),
741                  _("net idmap delete ranges [-f] [--db=<TDB>] <SID>\n"
742                    "  Delete all domain range mappings for a given domain.\n"
743                    "    -f\tforce\n"
744                    "    TDB\tidmap database\n"
745                    "    SID\t\tSID of the domain\n"));
746 }
747
748 static int net_idmap_autorid_delete_ranges(struct net_context *c, int argc,
749                                            const char **argv)
750 {
751         int ret = -1;
752         struct db_context *db = NULL;
753         NTSTATUS status;
754         const char *domsid;
755         TALLOC_CTX *mem_ctx = NULL;
756         bool force = (c->opt_force != 0);
757         int count = 0;
758
759         if (c->display_usage) {
760                 net_idmap_autorid_delete_ranges_usage();
761                 return 0;
762         }
763
764         if (argc != 1) {
765                 net_idmap_autorid_delete_ranges_usage();
766                 return -1;
767         }
768
769         domsid = argv[0];
770
771         mem_ctx = talloc_stackframe();
772         if (!net_idmap_opendb_autorid(mem_ctx, c, false, &db)) {
773                 goto done;
774         }
775
776         status = idmap_autorid_delete_domain_ranges(db, domsid, force, &count);
777         if (!NT_STATUS_IS_OK(status)) {
778                 d_fprintf(stderr, "%s %s: %s\n",
779                           _("Failed to delete domain range mappings for "
780                             "domain"),
781                           domsid,
782                           nt_errstr(status));
783                 goto done;
784         }
785
786         d_printf(_("deleted %d domain mappings\n"), count);
787
788         ret = 0;
789
790 done:
791         talloc_free(mem_ctx);
792         return ret;
793 }
794
795 static int net_idmap_delete(struct net_context *c, int argc, const char **argv)
796 {
797         struct functable func[] = {
798                 {
799                         "mapping",
800                         net_idmap_delete_mapping,
801                         NET_TRANSPORT_LOCAL,
802                         N_("Delete ID mapping"),
803                         N_("net idmap delete mapping <ID>\n"
804                            "  Delete ID mapping")
805                 },
806                 {
807                         "range",
808                         net_idmap_autorid_delete_range,
809                         NET_TRANSPORT_LOCAL,
810                         N_("Delete a domain range mapping"),
811                         N_("net idmap delete range <RANGE>|(<SID>[ <INDEX>])\n"
812                            "  Delete a domain range mapping")
813                 },
814                 {
815                         "ranges",
816                         net_idmap_autorid_delete_ranges,
817                         NET_TRANSPORT_LOCAL,
818                         N_("Delete all domain range mappings for a given "
819                            "domain"),
820                         N_("net idmap delete ranges <SID>\n"
821                            "  Delete a domain range mapping")
822                 },
823                 {NULL, NULL, 0, NULL, NULL}
824         };
825
826         return net_run_function(c, argc, argv, "net idmap delete", func);
827 }
828
829
830 static int net_idmap_set_mapping(struct net_context *c,
831                                  int argc, const char **argv)
832 {
833         d_printf("%s\n", _("Not implemented yet"));
834         return -1;
835 }
836
837 static void net_idmap_autorid_set_range_usage(void)
838 {
839         d_printf("%s\n%s",
840                  _("Usage:"),
841                  _("net idmap set range"
842                    " <range> <SID> [<index>] [--db=<inputfile>]\n"
843                    "  Store a domain-range mapping for a given domain.\n"
844                    "    range\tRange number to be set for the domain\n"
845                    "    SID\t\tSID of the domain\n"
846                    "    index\trange-index number to be set for the domain\n"
847                    "    inputfile\tTDB file to add mapping to.\n"));
848 }
849
850 static int net_idmap_autorid_set_range(struct net_context *c,
851                                        int argc, const char **argv)
852 {
853         int ret = -1;
854         TALLOC_CTX *mem_ctx;
855         struct db_context *db = NULL;
856         const char *domsid;
857         uint32_t rangenum;
858         uint32_t range_index = 0;
859         NTSTATUS status;
860         bool ok;
861
862         if (c->display_usage) {
863                 net_idmap_autorid_set_range_usage();
864                 return 0;
865         }
866
867         if (argc < 2  || argc > 3) {
868                 net_idmap_autorid_set_range_usage();
869                 return -1;
870         }
871
872         ok = parse_uint32(argv[0], &rangenum);
873         if (!ok) {
874                 d_printf("%s: %s\n", _("Invalid range specification"),
875                          argv[0]);
876                 net_idmap_autorid_set_range_usage();
877                 return -1;
878         }
879
880         domsid = argv[1];
881
882         if (argc == 3) {
883                 ok = parse_uint32(argv[2], &range_index);
884                 if (!ok) {
885                         d_printf("%s: %s\n",
886                                  _("Invalid index specification"), argv[2]);
887                         net_idmap_autorid_set_range_usage();
888                         return -1;
889                 }
890         }
891
892         mem_ctx = talloc_stackframe();
893         if (!net_idmap_opendb_autorid(mem_ctx, c, false, &db)) {
894                 goto done;
895         }
896
897         status = idmap_autorid_setrange(db, domsid, range_index, rangenum);
898         if (!NT_STATUS_IS_OK(status)) {
899                 d_fprintf(stderr, "%s: %s\n",
900                           _("Failed to save domain mapping"),
901                           nt_errstr(status));
902                 goto done;
903         }
904
905         ret = 0;
906
907 done:
908         TALLOC_FREE(mem_ctx);
909         return ret;
910 }
911
912 static bool idmap_store_secret(const char *backend,
913                                const char *domain,
914                                const char *identity,
915                                const char *secret)
916 {
917         char *tmp;
918         int r;
919         bool ret;
920
921         r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
922
923         if (r < 0) return false;
924
925         /* make sure the key is case insensitive */
926         if (!strupper_m(tmp)) {
927                 free(tmp);
928                 return false;
929         }
930         ret = secrets_store_generic(tmp, identity, secret);
931
932         free(tmp);
933         return ret;
934 }
935
936
937 static int net_idmap_secret(struct net_context *c, int argc, const char **argv)
938 {
939         TALLOC_CTX *ctx;
940         const char *secret;
941         const char *dn;
942         char *domain;
943         char *backend;
944         char *opt = NULL;
945         bool ret;
946
947         if (argc != 2 || c->display_usage) {
948                 d_printf("%s\n%s",
949                          _("Usage:\n"),
950                          _("net idmap set secret <DOMAIN> <secret>\n"
951                            "  Set the secret for the specified domain\n"
952                            "    DOMAIN\tDomain to set secret for.\n"
953                            "    secret\tNew secret to set.\n"));
954                 return c->display_usage?0:-1;
955         }
956
957         secret = argv[1];
958
959         ctx = talloc_new(NULL);
960         ALLOC_CHECK(ctx);
961
962         domain = talloc_strdup(ctx, argv[0]);
963         ALLOC_CHECK(domain);
964
965         opt = talloc_asprintf(ctx, "idmap config %s", domain);
966         ALLOC_CHECK(opt);
967
968         backend = talloc_strdup(ctx, lp_parm_const_string(-1, opt, "backend", "tdb"));
969         ALLOC_CHECK(backend);
970
971         if ((!backend) || (!strequal(backend, "ldap") &&
972                            !strequal(backend, "rfc2307"))) {
973                 d_fprintf(stderr,
974                           _("The only currently supported backend are LDAP "
975                             "and rfc2307\n"));
976                 talloc_free(ctx);
977                 return -1;
978         }
979
980         dn = lp_parm_const_string(-1, opt, "ldap_user_dn", NULL);
981         if ( ! dn) {
982                 d_fprintf(stderr,
983                           _("Missing ldap_user_dn option for domain %s\n"),
984                           domain);
985                 talloc_free(ctx);
986                 return -1;
987         }
988
989         ret = idmap_store_secret("ldap", domain, dn, secret);
990
991         if ( ! ret) {
992                 d_fprintf(stderr, _("Failed to store secret\n"));
993                 talloc_free(ctx);
994                 return -1;
995         }
996
997         d_printf(_("Secret stored\n"));
998         return 0;
999 }
1000
1001 static int net_idmap_autorid_set_config(struct net_context *c,
1002                                         int argc, const char **argv)
1003 {
1004         int ret = -1;
1005         NTSTATUS status;
1006         TALLOC_CTX *mem_ctx;
1007         struct db_context *db = NULL;
1008
1009         if (argc != 1 || c->display_usage) {
1010                 d_printf("%s\n%s",
1011                          _("Usage:"),
1012                          _("net idmap set config <config>"
1013                            " [--db=<inputfile>]\n"
1014                            " Update CONFIG entry in autorid.\n"
1015                            "    config\tConfig string to be stored\n"
1016                            "    inputfile\tTDB file to update config.\n"));
1017                 return c->display_usage ? 0 : -1;
1018         }
1019
1020         mem_ctx = talloc_stackframe();
1021
1022         if (!net_idmap_opendb_autorid(mem_ctx, c, false, &db)) {
1023                 goto done;
1024         }
1025
1026         status = idmap_autorid_saveconfigstr(db, argv[0]);
1027         if (!NT_STATUS_IS_OK(status)) {
1028                 printf("Error storing the config in the database: %s\n",
1029                        nt_errstr(status));
1030                 goto done;
1031         }
1032
1033         ret = 0;
1034
1035 done:
1036         TALLOC_FREE(mem_ctx);
1037         return ret;
1038 }
1039
1040 static int net_idmap_set(struct net_context *c, int argc, const char **argv)
1041 {
1042         struct functable func[] = {
1043                 {
1044                         "mapping",
1045                         net_idmap_set_mapping,
1046                         NET_TRANSPORT_LOCAL,
1047                         N_("Not implemented yet"),
1048                         N_("net idmap set mapping\n"
1049                            "  Not implemented yet")
1050                 },
1051                 {
1052                         "range",
1053                         net_idmap_autorid_set_range,
1054                         NET_TRANSPORT_LOCAL,
1055                         N_("Store a domain-range mapping"),
1056                         N_("net idmap set range\n"
1057                            "  Store a domain-range mapping")
1058                 },
1059                 {
1060                         "config",
1061                         net_idmap_autorid_set_config,
1062                         NET_TRANSPORT_LOCAL,
1063                         N_("Save the global configuration in the autorid database"),
1064                         N_("net idmap set config \n"
1065                            "  Save the global configuration in the autorid database ")
1066                 },
1067                 {
1068                         "secret",
1069                         net_idmap_secret,
1070                         NET_TRANSPORT_LOCAL,
1071                         N_("Set secret for specified domain"),
1072                         N_("net idmap set secret <DOMAIN> <secret>\n"
1073                            "  Set secret for specified domain")
1074                 },
1075                 {NULL, NULL, 0, NULL, NULL}
1076         };
1077
1078         return net_run_function(c, argc, argv, "net idmap set", func);
1079 }
1080
1081 static void net_idmap_autorid_get_range_usage(void)
1082 {
1083         d_printf("%s\n%s",
1084                  _("Usage:"),
1085                  _("net idmap get range <SID> [<index>] [--db=<inputfile>]\n"
1086                    "  Get the range for a given domain and index.\n"
1087                    "    SID\t\tSID of the domain\n"
1088                    "    index\trange-index number to be retrieved\n"
1089                    "    inputfile\tTDB file to add mapping to.\n"));
1090 }
1091
1092
1093 static int net_idmap_autorid_get_range(struct net_context *c, int argc,
1094                                        const char **argv)
1095 {
1096         int ret = -1;
1097         TALLOC_CTX *mem_ctx;
1098         struct db_context *db = NULL;
1099         const char *domsid;
1100         uint32_t rangenum;
1101         uint32_t range_index = 0;
1102         uint32_t low_id;
1103         NTSTATUS status;
1104         char *keystr;
1105         bool ok;
1106
1107         if (c->display_usage) {
1108                 net_idmap_autorid_get_range_usage();
1109                 return 0;
1110         }
1111
1112         if (argc < 1  || argc > 2) {
1113                 net_idmap_autorid_get_range_usage();
1114                 return -1;
1115         }
1116
1117         domsid = argv[0];
1118
1119         if (argc == 2) {
1120                 ok = parse_uint32(argv[1], &range_index);
1121                 if (!ok) {
1122                         d_printf("%s: %s\n",
1123                                  _("Invalid index specification"), argv[1]);
1124                         net_idmap_autorid_get_range_usage();
1125                         return -1;
1126                 }
1127         }
1128
1129         mem_ctx = talloc_stackframe();
1130         if (!net_idmap_opendb_autorid(mem_ctx, c, true, &db)) {
1131                 goto done;
1132         }
1133
1134         status = idmap_autorid_getrange(db, domsid, range_index, &rangenum,
1135                                         &low_id);
1136         if (!NT_STATUS_IS_OK(status)) {
1137                 d_fprintf(stderr, "%s: %s\n",
1138                           _("Failed to load domain range"), nt_errstr(status));
1139                 goto done;
1140         }
1141
1142         if (range_index == 0) {
1143                 keystr = talloc_strdup(mem_ctx, domsid);
1144         } else {
1145                 keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
1146                                          range_index);
1147         }
1148
1149         printf("RANGE %"PRIu32": %s (low id: %"PRIu32")\n",
1150                rangenum, keystr, low_id);
1151
1152         ret = 0;
1153
1154 done:
1155         TALLOC_FREE(mem_ctx);
1156         return ret;
1157 }
1158
1159 static NTSTATUS net_idmap_autorid_print_range(struct db_context *db,
1160                                               const char *domsid,
1161                                               uint32_t range_index,
1162                                               uint32_t rangenum,
1163                                               void *private_data)
1164 {
1165         if (range_index == 0) {
1166                 printf("RANGE %"PRIu32": %s\n", rangenum, domsid);
1167         } else {
1168                 printf("RANGE %"PRIu32": %s#%"PRIu32"\n", rangenum, domsid,
1169                        range_index);
1170         }
1171
1172         return NT_STATUS_OK;
1173 }
1174
1175 static void net_idmap_autorid_get_ranges_usage(void)
1176 {
1177         d_printf("%s\n%s",
1178                  _("Usage:"),
1179                  _("net idmap get ranges [<SID>] [--db=<inputfile>]\n"
1180                    "  Get all ranges for a given domain.\n"
1181                    "    SID\t\tSID of the domain - list all ranges if omitted\n"
1182                    "    inputfile\tTDB file to add mapping to.\n"));
1183 }
1184
1185 static int net_idmap_autorid_get_ranges(struct net_context *c, int argc,
1186                                         const char **argv)
1187 {
1188         int ret = -1;
1189         TALLOC_CTX *mem_ctx;
1190         struct db_context *db = NULL;
1191         const char *domsid;
1192         NTSTATUS status;
1193
1194         if (c->display_usage) {
1195                 net_idmap_autorid_get_ranges_usage();
1196                 return 0;
1197         }
1198
1199         if (argc == 0) {
1200                 domsid = NULL;
1201         } else if (argc == 1) {
1202                 domsid = argv[0];
1203         } else {
1204                 net_idmap_autorid_get_ranges_usage();
1205                 return -1;
1206         }
1207
1208         mem_ctx = talloc_stackframe();
1209         if (!net_idmap_opendb_autorid(mem_ctx, c, true, &db)) {
1210                 goto done;
1211         }
1212
1213         status = idmap_autorid_iterate_domain_ranges_read(db,
1214                                                 domsid,
1215                                                 net_idmap_autorid_print_range,
1216                                                 NULL, /* private_data */
1217                                                 NULL  /* count */);
1218         if (!NT_STATUS_IS_OK(status)) {
1219                 d_fprintf(stderr, "%s: %s\n",
1220                           _("Error getting domain ranges"), nt_errstr(status));
1221                 goto done;
1222         }
1223
1224         ret = 0;
1225
1226 done:
1227         talloc_free(mem_ctx);
1228         return ret;
1229 }
1230
1231 static int net_idmap_autorid_get_config(struct net_context *c, int argc,
1232                                         const char **argv)
1233 {
1234         int ret = -1;
1235         char *config;
1236         TALLOC_CTX *mem_ctx;
1237         NTSTATUS status;
1238         struct db_context *db = NULL;
1239
1240         if (argc > 0 || c->display_usage) {
1241                 d_printf("%s\n%s",
1242                          _("Usage:"),
1243                          _("net idmap get config"
1244                            " [--db=<inputfile>]\n"
1245                            " Get CONFIG entry from autorid database\n"
1246                            "    inputfile\tTDB file to read config from.\n"));
1247                 return c->display_usage ? 0 : -1;
1248         }
1249
1250         mem_ctx = talloc_stackframe();
1251
1252         if (!net_idmap_opendb_autorid(mem_ctx, c, true, &db)) {
1253                 goto done;
1254         }
1255
1256         status = idmap_autorid_getconfigstr(db, mem_ctx, &config);
1257         if (!NT_STATUS_IS_OK(status)) {
1258                 d_fprintf(stderr, "%s: %s\n",
1259                           _("Error: unable to read config entry"),
1260                           nt_errstr(status));
1261                 goto done;
1262         }
1263
1264         printf("CONFIG: %s\n", config);
1265         ret = 0;
1266
1267 done:
1268         TALLOC_FREE(mem_ctx);
1269         return ret;
1270 }
1271
1272
1273 static int net_idmap_get(struct net_context *c, int argc, const char **argv)
1274 {
1275         struct functable func[] = {
1276                 {
1277                         "range",
1278                         net_idmap_autorid_get_range,
1279                         NET_TRANSPORT_LOCAL,
1280                         N_("Get the range for a domain and range-index"),
1281                         N_("net idmap get range\n"
1282                            "  Get the range for a domain and range-index")
1283                 },
1284                 {
1285                         "ranges",
1286                         net_idmap_autorid_get_ranges,
1287                         NET_TRANSPORT_LOCAL,
1288                         N_("Get all ranges for a domain"),
1289                         N_("net idmap get ranges <SID>\n"
1290                            "  Get all ranges for a domain")
1291                 },
1292                 {
1293                         "config",
1294                         net_idmap_autorid_get_config,
1295                         NET_TRANSPORT_LOCAL,
1296                         N_("Get the global configuration from the autorid database"),
1297                         N_("net idmap get config \n"
1298                            "  Get the global configuration from the autorid database ")
1299                 },
1300                 {NULL, NULL, 0, NULL, NULL}
1301         };
1302
1303         return net_run_function(c, argc, argv, "net idmap get", func);
1304 }
1305
1306 static int net_idmap_check(struct net_context *c, int argc, const char **argv)
1307 {
1308         const char* dbfile;
1309         struct check_options opts;
1310         struct net_idmap_ctx ctx = { .backend = TDB };
1311
1312         if ( argc > 1 || c->display_usage) {
1313                 d_printf("%s\n%s",
1314                          _("Usage:"),
1315                          _("net idmap check  [-v] [-r] [-a] [-T] [-f] [-l] [[--db=]<TDB>]\n"
1316                            "  Check an idmap database.\n"
1317                            "    --verbose,-v\tverbose\n"
1318                            "    --repair,-r\trepair\n"
1319                            "    --auto,-a\tnoninteractive mode\n"
1320                            "    --test,-T\tdry run\n"
1321                            "    --fore,-f\tforce\n"
1322                            "    --lock,-l\tlock db while doing the check\n"
1323                            "    TDB\tidmap database\n"));
1324                 return c->display_usage ? 0 : -1;
1325         }
1326
1327         dbfile = (argc > 0) ? argv[0] : net_idmap_dbfile(c, &ctx);
1328         if (dbfile == NULL) {
1329                 return -1;
1330         }
1331
1332         if (ctx.backend != TDB) {
1333                 d_fprintf(stderr, _("Sorry, checking of non-TDB databases is "
1334                                     "currently not supported\n"));
1335                 return -1;
1336         }
1337
1338         d_fprintf(stderr, _("check database: %s\n"), dbfile);
1339
1340         opts = (struct check_options) {
1341                 .lock = c->opt_lock || c->opt_long_list_entries,
1342                 .test = c->opt_testmode,
1343                 .automatic = c->opt_auto,
1344                 .verbose = c->opt_verbose,
1345                 .force = c->opt_force,
1346                 .repair = c->opt_repair || c->opt_reboot,
1347         };
1348
1349         return net_idmap_check_db(dbfile, &opts);
1350 }
1351
1352 /***********************************************************
1353  Look at the current idmap
1354  **********************************************************/
1355 int net_idmap(struct net_context *c, int argc, const char **argv)
1356 {
1357         struct functable func[] = {
1358                 {
1359                         "dump",
1360                         net_idmap_dump,
1361                         NET_TRANSPORT_LOCAL,
1362                         N_("Dump the current ID mapping database"),
1363                         N_("net idmap dump\n"
1364                            "  Dump the current ID mappings")
1365                 },
1366                 {
1367                         "restore",
1368                         net_idmap_restore,
1369                         NET_TRANSPORT_LOCAL,
1370                         N_("Restore entries from a file or stdin"),
1371                         N_("net idmap restore\n"
1372                            "  Restore entries from stdin")
1373                 },
1374                 {
1375                         "get",
1376                         net_idmap_get,
1377                         NET_TRANSPORT_LOCAL,
1378                         N_("Read data from the ID mapping database"),
1379                         N_("net idmap get\n"
1380                            "  Read data from the ID mapping database")
1381                 },
1382                 {
1383                         "set",
1384                         net_idmap_set,
1385                         NET_TRANSPORT_LOCAL,
1386                         N_("Write data to the ID mapping database"),
1387                         N_("net idmap set\n"
1388                            "  Write data to the ID mapping database")
1389                 },
1390                 {
1391                         "delete",
1392                         net_idmap_delete,
1393                         NET_TRANSPORT_LOCAL,
1394                         N_("Delete entries from the ID mapping database"),
1395                         N_("net idmap delete\n"
1396                            "  Delete entries from the ID mapping database")
1397                 },
1398                 {
1399                         "check",
1400                         net_idmap_check,
1401                         NET_TRANSPORT_LOCAL,
1402                         N_("Check id mappings"),
1403                         N_("net idmap check\n"
1404                            "  Check id mappings")
1405                 },
1406                 {NULL, NULL, 0, NULL, NULL}
1407         };
1408
1409         return net_run_function(c, argc, argv, "net idmap", func);
1410 }
1411
1412