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