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