s3:utils: Use C99 initializer for poptOption in mvxattr
[garming/samba-autobuild/.git] / source3 / utils / net_groupmap.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Jean François Micouleau      1998-2001.
6  *  Copyright (C) Gerald Carter                2003,
7  *  Copyright (C) Volker Lendecke              2004
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #include "includes.h"
25 #include "system/passwd.h"
26 #include "utils/net.h"
27 #include "../libcli/security/security.h"
28 #include "passdb.h"
29
30 /*********************************************************
31  Figure out if the input was an NT group or a SID string.
32  Return the SID.
33 **********************************************************/
34 static bool get_sid_from_input(struct dom_sid *sid, char *input)
35 {
36         GROUP_MAP *map;
37
38         map = talloc_zero(NULL, GROUP_MAP);
39         if (!map) {
40                 return false;
41         }
42
43         if (strncasecmp_m( input, "S-", 2)) {
44                 /* Perhaps its the NT group name? */
45                 if (!pdb_getgrnam(map, input)) {
46                         printf(_("NT Group %s doesn't exist in mapping DB\n"),
47                                input);
48                         TALLOC_FREE(map);
49                         return false;
50                 } else {
51                         *sid = map->sid;
52                 }
53         } else {
54                 if (!string_to_sid(sid, input)) {
55                         printf(_("converting sid %s from a string failed!\n"),
56                                input);
57                         TALLOC_FREE(map);
58                         return false;
59                 }
60         }
61         TALLOC_FREE(map);
62         return true;
63 }
64
65 /*********************************************************
66  Dump a GROUP_MAP entry to stdout (long or short listing)
67 **********************************************************/
68
69 static void print_map_entry (const GROUP_MAP *map, bool long_list)
70 {
71         struct dom_sid_buf buf;
72
73         if (!long_list)
74                 d_printf("%s (%s) -> %s\n", map->nt_name,
75                          dom_sid_str_buf(&map->sid, &buf),
76                          gidtoname(map->gid));
77         else {
78                 d_printf("%s\n", map->nt_name);
79                 d_printf(_("\tSID       : %s\n"),
80                          dom_sid_str_buf(&map->sid, &buf));
81                 d_printf(_("\tUnix gid  : %u\n"), (unsigned int)map->gid);
82                 d_printf(_("\tUnix group: %s\n"), gidtoname(map->gid));
83                 d_printf(_("\tGroup type: %s\n"),
84                          sid_type_lookup(map->sid_name_use));
85                 d_printf(_("\tComment   : %s\n"), map->comment);
86         }
87
88 }
89 /*********************************************************
90  List the groups.
91 **********************************************************/
92 static int net_groupmap_list(struct net_context *c, int argc, const char **argv)
93 {
94         size_t entries;
95         bool long_list = false;
96         size_t i;
97         fstring ntgroup = "";
98         fstring sid_string = "";
99         const char list_usage_str[] = N_("net groupmap list [verbose] "
100                                          "[ntgroup=NT group] [sid=SID]\n"
101                                          "    verbose\tPrint verbose list\n"
102                                          "    ntgroup\tNT group to list\n"
103                                          "    sid\tSID of group to list");
104
105         if (c->display_usage) {
106                 d_printf("%s\n%s\n", _("Usage: "), list_usage_str);
107                 return 0;
108         }
109
110         if (c->opt_verbose || c->opt_long_list_entries)
111                 long_list = true;
112
113         /* get the options */
114         for ( i=0; i<argc; i++ ) {
115                 if ( !strcasecmp_m(argv[i], "verbose")) {
116                         long_list = true;
117                 }
118                 else if ( !strncasecmp_m(argv[i], "ntgroup", strlen("ntgroup")) ) {
119                         fstrcpy( ntgroup, get_string_param( argv[i] ) );
120                         if ( !ntgroup[0] ) {
121                                 d_fprintf(stderr, _("must supply a name\n"));
122                                 return -1;
123                         }
124                 }
125                 else if ( !strncasecmp_m(argv[i], "sid", strlen("sid")) ) {
126                         fstrcpy( sid_string, get_string_param( argv[i] ) );
127                         if ( !sid_string[0] ) {
128                                 d_fprintf(stderr, _("must supply a SID\n"));
129                                 return -1;
130                         }
131                 }
132                 else {
133                         d_fprintf(stderr, _("Bad option: %s\n"), argv[i]);
134                         d_printf("%s\n%s\n", _("Usage:"), list_usage_str);
135                         return -1;
136                 }
137         }
138
139         /* list a single group is given a name */
140         if ( ntgroup[0] || sid_string[0] ) {
141                 struct dom_sid sid;
142                 GROUP_MAP *map;
143
144                 if ( sid_string[0] )
145                         strlcpy(ntgroup, sid_string, sizeof(ntgroup));
146
147                 if (!get_sid_from_input(&sid, ntgroup)) {
148                         return -1;
149                 }
150
151                 map = talloc_zero(NULL, GROUP_MAP);
152                 if (!map) {
153                         return -1;
154                 }
155
156                 /* Get the current mapping from the database */
157                 if(!pdb_getgrsid(map, sid)) {
158                         d_fprintf(stderr,
159                                   _("Failure to local group SID in the "
160                                     "database\n"));
161                         TALLOC_FREE(map);
162                         return -1;
163                 }
164
165                 print_map_entry(map, long_list );
166                 TALLOC_FREE(map);
167         }
168         else {
169                 GROUP_MAP **maps = NULL;
170                 bool ok = false;
171                 /* enumerate all group mappings */
172                 ok = pdb_enum_group_mapping(NULL, SID_NAME_UNKNOWN,
173                                             &maps, &entries,
174                                             ENUM_ALL_MAPPED);
175                 if (!ok) {
176                         return -1;
177                 }
178
179                 for (i=0; i<entries; i++) {
180                         print_map_entry(maps[i], long_list);
181                 }
182
183                 TALLOC_FREE(maps);
184         }
185
186         return 0;
187 }
188
189 /*********************************************************
190  Add a new group mapping entry
191 **********************************************************/
192
193 static int net_groupmap_add(struct net_context *c, int argc, const char **argv)
194 {
195         struct dom_sid sid;
196         fstring ntgroup = "";
197         fstring unixgrp = "";
198         fstring string_sid = "";
199         fstring type = "";
200         fstring ntcomment = "";
201         enum lsa_SidType sid_type = SID_NAME_DOM_GRP;
202         uint32_t rid = 0;
203         gid_t gid;
204         int i;
205         GROUP_MAP *map;
206
207         const char *name_type;
208         const char add_usage_str[] = N_("net groupmap add "
209                                         "{rid=<int>|sid=<string>}"
210                                         " unixgroup=<string> "
211                                         "[type=<domain|local|builtin>] "
212                                         "[ntgroup=<string>] "
213                                         "[comment=<string>]");
214
215         name_type = "domain group";
216
217         if (c->display_usage) {
218                 d_printf("%s\n%s\n", _("Usage:\n"), add_usage_str);
219                 return 0;
220         }
221
222         /* get the options */
223         for ( i=0; i<argc; i++ ) {
224                 if ( !strncasecmp_m(argv[i], "rid", strlen("rid")) ) {
225                         rid = get_int_param(argv[i]);
226                         if ( rid < DOMAIN_RID_ADMINS ) {
227                                 d_fprintf(stderr,
228                                           _("RID must be greater than %d\n"),
229                                           (uint32_t)DOMAIN_RID_ADMINS-1);
230                                 return -1;
231                         }
232                 }
233                 else if ( !strncasecmp_m(argv[i], "unixgroup", strlen("unixgroup")) ) {
234                         fstrcpy( unixgrp, get_string_param( argv[i] ) );
235                         if ( !unixgrp[0] ) {
236                                 d_fprintf(stderr,_( "must supply a name\n"));
237                                 return -1;
238                         }
239                 }
240                 else if ( !strncasecmp_m(argv[i], "ntgroup", strlen("ntgroup")) ) {
241                         fstrcpy( ntgroup, get_string_param( argv[i] ) );
242                         if ( !ntgroup[0] ) {
243                                 d_fprintf(stderr, _("must supply a name\n"));
244                                 return -1;
245                         }
246                 }
247                 else if ( !strncasecmp_m(argv[i], "sid", strlen("sid")) ) {
248                         fstrcpy( string_sid, get_string_param( argv[i] ) );
249                         if ( !string_sid[0] ) {
250                                 d_fprintf(stderr, _("must supply a SID\n"));
251                                 return -1;
252                         }
253                 }
254                 else if ( !strncasecmp_m(argv[i], "comment", strlen("comment")) ) {
255                         fstrcpy( ntcomment, get_string_param( argv[i] ) );
256                         if ( !ntcomment[0] ) {
257                                 d_fprintf(stderr,
258                                           _("must supply a comment string\n"));
259                                 return -1;
260                         }
261                 }
262                 else if ( !strncasecmp_m(argv[i], "type", strlen("type")) )  {
263                         fstrcpy( type, get_string_param( argv[i] ) );
264                         switch ( type[0] ) {
265                                 case 'b':
266                                 case 'B':
267                                         sid_type = SID_NAME_WKN_GRP;
268                                         name_type = "wellknown group";
269                                         break;
270                                 case 'd':
271                                 case 'D':
272                                         sid_type = SID_NAME_DOM_GRP;
273                                         name_type = "domain group";
274                                         break;
275                                 case 'l':
276                                 case 'L':
277                                         sid_type = SID_NAME_ALIAS;
278                                         name_type = "alias (local) group";
279                                         break;
280                                 default:
281                                         d_fprintf(stderr,
282                                                   _("unknown group type %s\n"),
283                                                   type);
284                                         return -1;
285                         }
286                 }
287                 else {
288                         d_fprintf(stderr, _("Bad option: %s\n"), argv[i]);
289                         return -1;
290                 }
291         }
292
293         if ( !unixgrp[0] ) {
294                 d_printf("%s\n%s\n", _("Usage:\n"), add_usage_str);
295                 return -1;
296         }
297
298         if ( (gid = nametogid(unixgrp)) == (gid_t)-1 ) {
299                 d_fprintf(stderr, _("Can't lookup UNIX group %s\n"), unixgrp);
300                 return -1;
301         }
302
303         map = talloc_zero(NULL, GROUP_MAP);
304         if (!map) {
305                 return -1;
306         }
307         /* Default is domain group. */
308         map->sid_name_use = SID_NAME_DOM_GRP;
309         if (pdb_getgrgid(map, gid)) {
310                 struct dom_sid_buf buf;
311                 d_printf(_("Unix group %s already mapped to SID %s\n"),
312                          unixgrp, dom_sid_str_buf(&map->sid, &buf));
313                 TALLOC_FREE(map);
314                 return -1;
315         }
316         TALLOC_FREE(map);
317
318         if ( (rid == 0) && (string_sid[0] == '\0') ) {
319                 d_printf(_("No rid or sid specified, choosing a RID\n"));
320                 if (pdb_capabilities() & PDB_CAP_STORE_RIDS) {
321                         if (!pdb_new_rid(&rid)) {
322                                 d_printf(_("Could not get new RID\n"));
323                         }
324                 } else {
325                         rid = algorithmic_pdb_gid_to_group_rid(gid);
326                 }
327                 d_printf(_("Got RID %d\n"), rid);
328         }
329
330         /* append the rid to our own domain/machine SID if we don't have a full SID */
331         if ( !string_sid[0] ) {
332                 sid_compose(&sid, get_global_sam_sid(), rid);
333                 sid_to_fstring(string_sid, &sid);
334         }
335
336         if (!ntcomment[0]) {
337                 switch (sid_type) {
338                 case SID_NAME_WKN_GRP:
339                         fstrcpy(ntcomment, "Wellknown Unix group");
340                         break;
341                 case SID_NAME_DOM_GRP:
342                         fstrcpy(ntcomment, "Domain Unix group");
343                         break;
344                 case SID_NAME_ALIAS:
345                         fstrcpy(ntcomment, "Local Unix group");
346                         break;
347                 default:
348                         fstrcpy(ntcomment, "Unix group");
349                         break;
350                 }
351         }
352
353         if (!ntgroup[0] )
354                 strlcpy(ntgroup, unixgrp, sizeof(ntgroup));
355
356         if (!NT_STATUS_IS_OK(add_initial_entry(gid, string_sid, sid_type, ntgroup, ntcomment))) {
357                 d_fprintf(stderr, _("adding entry for group %s failed!\n"), ntgroup);
358                 return -1;
359         }
360
361         d_printf(_("Successfully added group %s to the mapping db as a %s\n"),
362                  ntgroup, name_type);
363         return 0;
364 }
365
366 static int net_groupmap_modify(struct net_context *c, int argc, const char **argv)
367 {
368         struct dom_sid sid;
369         GROUP_MAP *map = NULL;
370         fstring ntcomment = "";
371         fstring type = "";
372         fstring ntgroup = "";
373         fstring unixgrp = "";
374         fstring sid_string = "";
375         enum lsa_SidType sid_type = SID_NAME_UNKNOWN;
376         int i;
377         gid_t gid;
378         const char modify_usage_str[] = N_("net groupmap modify "
379                                            "{ntgroup=<string>|sid=<SID>} "
380                                            "[comment=<string>] "
381                                            "[unixgroup=<string>] "
382                                            "[type=<domain|local>]");
383
384         if (c->display_usage) {
385                 d_printf("%s\n%s\n", _("Usage:\n"), modify_usage_str);
386                 return 0;
387         }
388
389         /* get the options */
390         for ( i=0; i<argc; i++ ) {
391                 if ( !strncasecmp_m(argv[i], "ntgroup", strlen("ntgroup")) ) {
392                         fstrcpy( ntgroup, get_string_param( argv[i] ) );
393                         if ( !ntgroup[0] ) {
394                                 d_fprintf(stderr, _("must supply a name\n"));
395                                 return -1;
396                         }
397                 }
398                 else if ( !strncasecmp_m(argv[i], "sid", strlen("sid")) ) {
399                         fstrcpy( sid_string, get_string_param( argv[i] ) );
400                         if ( !sid_string[0] ) {
401                                 d_fprintf(stderr, _("must supply a name\n"));
402                                 return -1;
403                         }
404                 }
405                 else if ( !strncasecmp_m(argv[i], "comment", strlen("comment")) ) {
406                         fstrcpy( ntcomment, get_string_param( argv[i] ) );
407                         if ( !ntcomment[0] ) {
408                                 d_fprintf(stderr,
409                                           _("must supply a comment string\n"));
410                                 return -1;
411                         }
412                 }
413                 else if ( !strncasecmp_m(argv[i], "unixgroup", strlen("unixgroup")) ) {
414                         fstrcpy( unixgrp, get_string_param( argv[i] ) );
415                         if ( !unixgrp[0] ) {
416                                 d_fprintf(stderr,
417                                           _("must supply a group name\n"));
418                                 return -1;
419                         }
420                 }
421                 else if ( !strncasecmp_m(argv[i], "type", strlen("type")) )  {
422                         fstrcpy( type, get_string_param( argv[i] ) );
423                         switch ( type[0] ) {
424                                 case 'd':
425                                 case 'D':
426                                         sid_type = SID_NAME_DOM_GRP;
427                                         break;
428                                 case 'l':
429                                 case 'L':
430                                         sid_type = SID_NAME_ALIAS;
431                                         break;
432                         }
433                 }
434                 else {
435                         d_fprintf(stderr, _("Bad option: %s\n"), argv[i]);
436                         return -1;
437                 }
438         }
439
440         if ( !ntgroup[0] && !sid_string[0] ) {
441                 d_printf("%s\n%s\n", _("Usage:\n"), modify_usage_str);
442                 return -1;
443         }
444
445         /* give preference to the SID; if both the ntgroup name and SID
446            are defined, use the SID and assume that the group name could be a
447            new name */
448
449         if ( sid_string[0] ) {
450                 if (!get_sid_from_input(&sid, sid_string)) {
451                         return -1;
452                 }
453         }
454         else {
455                 if (!get_sid_from_input(&sid, ntgroup)) {
456                         return -1;
457                 }
458         }
459
460         map = talloc_zero(NULL, GROUP_MAP);
461         if (!map) {
462                 return -1;
463         }
464
465         /* Get the current mapping from the database */
466         if(!pdb_getgrsid(map, sid)) {
467                 d_fprintf(stderr,
468                          _("Failed to find local group SID in the database\n"));
469                 TALLOC_FREE(map);
470                 return -1;
471         }
472
473         /*
474          * Allow changing of group type only between domain and local
475          * We disallow changing Builtin groups !!! (SID problem)
476          */
477         if (sid_type == SID_NAME_UNKNOWN) {
478                 d_fprintf(stderr, _("Can't map to an unknown group type.\n"));
479                 TALLOC_FREE(map);
480                 return -1;
481         }
482
483         if (map->sid_name_use == SID_NAME_WKN_GRP) {
484                 d_fprintf(stderr,
485                           _("You can only change between domain and local "
486                             "groups.\n"));
487                 TALLOC_FREE(map);
488                 return -1;
489         }
490
491         map->sid_name_use = sid_type;
492
493         /* Change comment if new one */
494         if (ntcomment[0]) {
495                 map->comment = talloc_strdup(map, ntcomment);
496                 if (!map->comment) {
497                         d_fprintf(stderr, _("Out of memory!\n"));
498                         return -1;
499                 }
500         }
501
502         if (ntgroup[0]) {
503                 map->nt_name = talloc_strdup(map, ntgroup);
504                 if (!map->nt_name) {
505                         d_fprintf(stderr, _("Out of memory!\n"));
506                         return -1;
507                 }
508         }
509
510         if ( unixgrp[0] ) {
511                 gid = nametogid( unixgrp );
512                 if ( gid == -1 ) {
513                         d_fprintf(stderr, _("Unable to lookup UNIX group %s.  "
514                                             "Make sure the group exists.\n"),
515                                 unixgrp);
516                         TALLOC_FREE(map);
517                         return -1;
518                 }
519
520                 map->gid = gid;
521         }
522
523         if (!NT_STATUS_IS_OK(pdb_update_group_mapping_entry(map))) {
524                 d_fprintf(stderr, _("Could not update group database\n"));
525                 TALLOC_FREE(map);
526                 return -1;
527         }
528
529         d_printf(_("Updated mapping entry for %s\n"), map->nt_name);
530
531         TALLOC_FREE(map);
532         return 0;
533 }
534
535 static int net_groupmap_delete(struct net_context *c, int argc, const char **argv)
536 {
537         struct dom_sid sid;
538         fstring ntgroup = "";
539         fstring sid_string = "";
540         int i;
541         const char delete_usage_str[] = N_("net groupmap delete "
542                                            "{ntgroup=<string>|sid=<SID>}");
543
544         if (c->display_usage) {
545                 d_printf("%s\n%s\n", _("Usage:\n"), delete_usage_str);
546                 return 0;
547         }
548
549         /* get the options */
550         for ( i=0; i<argc; i++ ) {
551                 if ( !strncasecmp_m(argv[i], "ntgroup", strlen("ntgroup")) ) {
552                         fstrcpy( ntgroup, get_string_param( argv[i] ) );
553                         if ( !ntgroup[0] ) {
554                                 d_fprintf(stderr, _("must supply a name\n"));
555                                 return -1;
556                         }
557                 }
558                 else if ( !strncasecmp_m(argv[i], "sid", strlen("sid")) ) {
559                         fstrcpy( sid_string, get_string_param( argv[i] ) );
560                         if ( !sid_string[0] ) {
561                                 d_fprintf(stderr, _("must supply a SID\n"));
562                                 return -1;
563                         }
564                 }
565                 else {
566                         d_fprintf(stderr, _("Bad option: %s\n"), argv[i]);
567                         return -1;
568                 }
569         }
570
571         if ( !ntgroup[0] && !sid_string[0]) {
572                 d_printf("%s\n%s\n", _("Usage:\n"), delete_usage_str);
573                 return -1;
574         }
575
576         /* give preference to the SID if we have that */
577
578         if ( sid_string[0] )
579                 strlcpy(ntgroup, sid_string, sizeof(ntgroup));
580
581         if ( !get_sid_from_input(&sid, ntgroup) ) {
582                 d_fprintf(stderr, _("Unable to resolve group %s to a SID\n"),
583                           ntgroup);
584                 return -1;
585         }
586
587         if ( !NT_STATUS_IS_OK(pdb_delete_group_mapping_entry(sid)) ) {
588                 d_fprintf(stderr,
589                           _("Failed to remove group %s from the mapping db!\n"),
590                           ntgroup);
591                 return -1;
592         }
593
594         d_printf(_("Successfully removed %s from the mapping db\n"), ntgroup);
595
596         return 0;
597 }
598
599 static int net_groupmap_set(struct net_context *c, int argc, const char **argv)
600 {
601         const char *ntgroup = NULL;
602         struct group *grp = NULL;
603         GROUP_MAP *map;
604         bool have_map = false;
605
606         if ((argc < 1) || (argc > 2) || c->display_usage) {
607                 d_printf("%s\n%s",
608                          _("Usage:"),
609                          _(" net groupmap set \"NT Group\" "
610                            "[\"unix group\"] [-C \"comment\"] [-L] [-D]\n"));
611                 return -1;
612         }
613
614         if ( c->opt_localgroup && c->opt_domaingroup ) {
615                 d_printf(_("Can only specify -L or -D, not both\n"));
616                 return -1;
617         }
618
619         ntgroup = argv[0];
620
621         if (argc == 2) {
622                 grp = getgrnam(argv[1]);
623
624                 if (grp == NULL) {
625                         d_fprintf(stderr, _("Could not find unix group %s\n"),
626                                   argv[1]);
627                         return -1;
628                 }
629         }
630
631         map = talloc_zero(NULL, GROUP_MAP);
632         if (!map) {
633                 d_printf(_("Out of memory!\n"));
634                 return -1;
635         }
636
637         have_map = pdb_getgrnam(map, ntgroup);
638
639         if (!have_map) {
640                 struct dom_sid sid;
641                 have_map = ( (strncmp(ntgroup, "S-", 2) == 0) &&
642                              string_to_sid(&sid, ntgroup) &&
643                              pdb_getgrsid(map, sid) );
644         }
645
646         if (!have_map) {
647
648                 /* Ok, add it */
649
650                 if (grp == NULL) {
651                         d_fprintf(stderr,
652                                   _("Could not find group mapping for %s\n"),
653                                   ntgroup);
654                         TALLOC_FREE(map);
655                         return -1;
656                 }
657
658                 map->gid = grp->gr_gid;
659
660                 if (c->opt_rid == 0) {
661                         if ( pdb_capabilities() & PDB_CAP_STORE_RIDS ) {
662                                 if ( !pdb_new_rid((uint32_t *)&c->opt_rid) ) {
663                                         d_fprintf( stderr,
664                                             _("Could not allocate new RID\n"));
665                                         TALLOC_FREE(map);
666                                         return -1;
667                                 }
668                         } else {
669                                 c->opt_rid = algorithmic_pdb_gid_to_group_rid(map->gid);
670                         }
671                 }
672
673                 sid_compose(&map->sid, get_global_sam_sid(), c->opt_rid);
674
675                 map->sid_name_use = SID_NAME_DOM_GRP;
676                 map->nt_name = talloc_strdup(map, ntgroup);
677                 map->comment = talloc_strdup(map, "");
678                 if (!map->nt_name || !map->comment) {
679                         d_printf(_("Out of memory!\n"));
680                         TALLOC_FREE(map);
681                         return -1;
682                 }
683
684                 if (!NT_STATUS_IS_OK(pdb_add_group_mapping_entry(map))) {
685                         d_fprintf(stderr,
686                                   _("Could not add mapping entry for %s\n"),
687                                   ntgroup);
688                         TALLOC_FREE(map);
689                         return -1;
690                 }
691         }
692
693         /* Now we have a mapping entry, update that stuff */
694
695         if ( c->opt_localgroup || c->opt_domaingroup ) {
696                 if (map->sid_name_use == SID_NAME_WKN_GRP) {
697                         d_fprintf(stderr,
698                                   _("Can't change type of the BUILTIN "
699                                     "group %s\n"),
700                                   map->nt_name);
701                         TALLOC_FREE(map);
702                         return -1;
703                 }
704         }
705
706         if (c->opt_localgroup)
707                 map->sid_name_use = SID_NAME_ALIAS;
708
709         if (c->opt_domaingroup)
710                 map->sid_name_use = SID_NAME_DOM_GRP;
711
712         /* The case (opt_domaingroup && opt_localgroup) was tested for above */
713
714         if ((c->opt_comment != NULL) && (strlen(c->opt_comment) > 0)) {
715                 map->comment = talloc_strdup(map, c->opt_comment);
716                 if (!map->comment) {
717                         d_printf(_("Out of memory!\n"));
718                         TALLOC_FREE(map);
719                         return -1;
720                 }
721         }
722
723         if ((c->opt_newntname != NULL) && (strlen(c->opt_newntname) > 0)) {
724                 map->nt_name = talloc_strdup(map, c->opt_newntname);
725                 if (!map->nt_name) {
726                         d_printf(_("Out of memory!\n"));
727                         TALLOC_FREE(map);
728                         return -1;
729                 }
730         }
731
732         if (grp != NULL)
733                 map->gid = grp->gr_gid;
734
735         if (!NT_STATUS_IS_OK(pdb_update_group_mapping_entry(map))) {
736                 d_fprintf(stderr, _("Could not update group mapping for %s\n"),
737                           ntgroup);
738                 TALLOC_FREE(map);
739                 return -1;
740         }
741
742         TALLOC_FREE(map);
743         return 0;
744 }
745
746 static int net_groupmap_cleanup(struct net_context *c, int argc, const char **argv)
747 {
748         GROUP_MAP **maps = NULL;
749         size_t i, entries;
750
751         if (c->display_usage) {
752                 d_printf(  "%s\n"
753                            "net groupmap cleanup\n"
754                            "    %s\n",
755                          _("Usage:"),
756                          _("Delete all group mappings"));
757                 return 0;
758         }
759
760         if (!pdb_enum_group_mapping(NULL, SID_NAME_UNKNOWN, &maps, &entries,
761                                     ENUM_ALL_MAPPED)) {
762                 d_fprintf(stderr, _("Could not list group mappings\n"));
763                 return -1;
764         }
765
766         for (i=0; i<entries; i++) {
767
768                 if (maps[i]->gid == -1)
769                         printf(_("Group %s is not mapped\n"),
770                                 maps[i]->nt_name);
771
772                 if (!sid_check_is_in_our_sam(&maps[i]->sid) &&
773                     !sid_check_is_in_builtin(&maps[i]->sid))
774                 {
775                         struct dom_sid_buf buf;
776                         printf(_("Deleting mapping for NT Group %s, sid %s\n"),
777                                 maps[i]->nt_name,
778                                 dom_sid_str_buf(&maps[i]->sid, &buf));
779                         pdb_delete_group_mapping_entry(maps[i]->sid);
780                 }
781         }
782
783         TALLOC_FREE(maps);
784         return 0;
785 }
786
787 static int net_groupmap_addmem(struct net_context *c, int argc, const char **argv)
788 {
789         struct dom_sid alias, member;
790
791         if ( (argc != 2) ||
792              c->display_usage ||
793              !string_to_sid(&alias, argv[0]) ||
794              !string_to_sid(&member, argv[1]) ) {
795                 d_printf("%s\n%s",
796                          _("Usage:"),
797                          _("net groupmap addmem alias-sid member-sid\n"));
798                 return -1;
799         }
800
801         if (!NT_STATUS_IS_OK(pdb_add_aliasmem(&alias, &member))) {
802                 d_fprintf(stderr, _("Could not add sid %s to alias %s\n"),
803                          argv[1], argv[0]);
804                 return -1;
805         }
806
807         return 0;
808 }
809
810 static int net_groupmap_delmem(struct net_context *c, int argc, const char **argv)
811 {
812         struct dom_sid alias, member;
813
814         if ( (argc != 2) ||
815              c->display_usage ||
816              !string_to_sid(&alias, argv[0]) ||
817              !string_to_sid(&member, argv[1]) ) {
818                 d_printf("%s\n%s",
819                          _("Usage:"),
820                          _("net groupmap delmem alias-sid member-sid\n"));
821                 return -1;
822         }
823
824         if (!NT_STATUS_IS_OK(pdb_del_aliasmem(&alias, &member))) {
825                 d_fprintf(stderr, _("Could not delete sid %s from alias %s\n"),
826                          argv[1], argv[0]);
827                 return -1;
828         }
829
830         return 0;
831 }
832
833 static int net_groupmap_listmem(struct net_context *c, int argc, const char **argv)
834 {
835         struct dom_sid alias;
836         struct dom_sid *members;
837         size_t i, num;
838
839         if ( (argc != 1) ||
840              c->display_usage ||
841              !string_to_sid(&alias, argv[0]) ) {
842                 d_printf("%s\n%s",
843                          _("Usage:"),
844                          _("net groupmap listmem alias-sid\n"));
845                 return -1;
846         }
847
848         members = NULL;
849         num = 0;
850
851         if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(&alias, talloc_tos(),
852                                                &members, &num))) {
853                 d_fprintf(stderr, _("Could not list members for sid %s\n"),
854                           argv[0]);
855                 return -1;
856         }
857
858         for (i = 0; i < num; i++) {
859                 struct dom_sid_buf buf;
860                 printf("%s\n", dom_sid_str_buf(&(members[i]), &buf));
861         }
862
863         TALLOC_FREE(members);
864
865         return 0;
866 }
867
868 static bool print_alias_memberships(TALLOC_CTX *mem_ctx,
869                                     const struct dom_sid *domain_sid,
870                                     const struct dom_sid *member)
871 {
872         uint32_t *alias_rids;
873         size_t i, num_alias_rids;
874         struct dom_sid_buf buf;
875
876         alias_rids = NULL;
877         num_alias_rids = 0;
878
879         if (!NT_STATUS_IS_OK(pdb_enum_alias_memberships(
880                                      mem_ctx, domain_sid, member, 1,
881                                      &alias_rids, &num_alias_rids))) {
882                 d_fprintf(stderr, _("Could not list memberships for sid %s\n"),
883                           dom_sid_str_buf(member, &buf));
884                 return false;
885         }
886
887         for (i = 0; i < num_alias_rids; i++) {
888                 struct dom_sid alias;
889                 sid_compose(&alias, domain_sid, alias_rids[i]);
890                 printf("%s\n", dom_sid_str_buf(&alias, &buf));
891         }
892
893         return true;
894 }
895
896 static int net_groupmap_memberships(struct net_context *c, int argc, const char **argv)
897 {
898         TALLOC_CTX *mem_ctx;
899         struct dom_sid *domain_sid, member;
900
901         if ( (argc != 1) ||
902              c->display_usage ||
903              !string_to_sid(&member, argv[0]) ) {
904                 d_printf("%s\n%s",
905                          _("Usage:"),
906                          _("net groupmap memberships sid\n"));
907                 return -1;
908         }
909
910         mem_ctx = talloc_init("net_groupmap_memberships");
911         if (mem_ctx == NULL) {
912                 d_fprintf(stderr, _("talloc_init failed\n"));
913                 return -1;
914         }
915
916         domain_sid = get_global_sam_sid();
917         if (domain_sid == NULL) {
918                 d_fprintf(stderr, _("Could not get domain sid\n"));
919                 return -1;
920         }
921
922         if (!print_alias_memberships(mem_ctx, domain_sid, &member) ||
923             !print_alias_memberships(mem_ctx, &global_sid_Builtin, &member))
924                 return -1;
925
926         talloc_destroy(mem_ctx);
927
928         return 0;
929 }
930
931 /***********************************************************
932  migrated functionality from smbgroupedit
933  **********************************************************/
934 int net_groupmap(struct net_context *c, int argc, const char **argv)
935 {
936         struct functable func[] = {
937                 {
938                         "add",
939                         net_groupmap_add,
940                         NET_TRANSPORT_LOCAL,
941                         N_("Create a new group mapping"),
942                         N_("net groupmap add\n"
943                            "    Create a new group mapping")
944                 },
945                 {
946                         "modify",
947                         net_groupmap_modify,
948                         NET_TRANSPORT_LOCAL,
949                         N_("Update a group mapping"),
950                         N_("net groupmap modify\n"
951                            "    Modify an existing group mapping")
952                 },
953                 {
954                         "delete",
955                         net_groupmap_delete,
956                         NET_TRANSPORT_LOCAL,
957                         N_("Remove a group mapping"),
958                         N_("net groupmap delete\n"
959                            "    Remove a group mapping")
960                 },
961                 {
962                         "set",
963                         net_groupmap_set,
964                         NET_TRANSPORT_LOCAL,
965                         N_("Set group mapping"),
966                         N_("net groupmap set\n"
967                            "    Set a group mapping")
968                 },
969                 {
970                         "cleanup",
971                         net_groupmap_cleanup,
972                         NET_TRANSPORT_LOCAL,
973                         N_("Remove foreign group mapping entries"),
974                         N_("net groupmap cleanup\n"
975                            "    Remove foreign group mapping entries")
976                 },
977                 {
978                         "addmem",
979                         net_groupmap_addmem,
980                         NET_TRANSPORT_LOCAL,
981                         N_("Add a foreign alias member"),
982                         N_("net groupmap addmem\n"
983                            "    Add a foreign alias member")
984                 },
985                 {
986                         "delmem",
987                         net_groupmap_delmem,
988                         NET_TRANSPORT_LOCAL,
989                         N_("Delete foreign alias member"),
990                         N_("net groupmap delmem\n"
991                            "    Delete foreign alias member")
992                 },
993                 {
994                         "listmem",
995                         net_groupmap_listmem,
996                         NET_TRANSPORT_LOCAL,
997                         N_("List foreign group members"),
998                         N_("net groupmap listmem\n"
999                            "    List foreign alias members")
1000                 },
1001                 {
1002                         "memberships",
1003                         net_groupmap_memberships,
1004                         NET_TRANSPORT_LOCAL,
1005                         N_("List foreign group memberships"),
1006                         N_("net groupmap memberships\n"
1007                            "    List foreign group memberships")
1008                 },
1009                 {
1010                         "list",
1011                         net_groupmap_list,
1012                         NET_TRANSPORT_LOCAL,
1013                         N_("List current group map"),
1014                         N_("net groupmap list\n"
1015                            "    List current group map")
1016                 },
1017                 {NULL, NULL, 0, NULL, NULL}
1018         };
1019
1020         return net_run_function(c,argc, argv, "net groupmap", func);
1021 }
1022