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