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