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