5e3b5bc61a24a1eae537afd54f7bf675953bc6f3
[kai/samba.git] / source3 / utils / net_groupmap.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Jean Fran├žois Micouleau      1998-2001.
6  *  Copyright (C) Gerald Carter                2003,
7  *  Copyright (C) Volker Lendecke              2004
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #include "includes.h"
25 #include "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(struct 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("%s\n%s\n", _("Usage: "), 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("%s\n%s\n", _("Usage:"), 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                 struct 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         struct 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("%s\n%s\n", _("Usage:\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_RID_ADMINS ) {
204                                 d_fprintf(stderr,
205                                           _("RID must be greater than %d\n"),
206                                           (uint32)DOMAIN_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("%s\n%s\n", _("Usage:\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         struct 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("%s\n%s\n", _("Usage:\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("%s\n%s\n", _("Usage:\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         struct 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("%s\n%s\n", _("Usage:\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("%s\n%s\n", _("Usage:\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("%s\n%s",
557                          _("Usage:"),
558                          _(" net groupmap set \"NT Group\" "
559                            "[\"unix group\"] [-C \"comment\"] [-L] [-D]\n"));
560                 return -1;
561         }
562
563         if ( c->opt_localgroup && c->opt_domaingroup ) {
564                 d_printf(_("Can only specify -L or -D, not both\n"));
565                 return -1;
566         }
567
568         ntgroup = argv[0];
569
570         if (argc == 2) {
571                 grp = getgrnam(argv[1]);
572
573                 if (grp == NULL) {
574                         d_fprintf(stderr, _("Could not find unix group %s\n"),
575                                   argv[1]);
576                         return -1;
577                 }
578         }
579
580         have_map = pdb_getgrnam(&map, ntgroup);
581
582         if (!have_map) {
583                 struct dom_sid sid;
584                 have_map = ( (strncmp(ntgroup, "S-", 2) == 0) &&
585                              string_to_sid(&sid, ntgroup) &&
586                              pdb_getgrsid(&map, sid) );
587         }
588
589         if (!have_map) {
590
591                 /* Ok, add it */
592
593                 if (grp == NULL) {
594                         d_fprintf(stderr,
595                                   _("Could not find group mapping for %s\n"),
596                                   ntgroup);
597                         return -1;
598                 }
599
600                 map.gid = grp->gr_gid;
601
602                 if (c->opt_rid == 0) {
603                         if ( pdb_capabilities() & PDB_CAP_STORE_RIDS ) {
604                                 if ( !pdb_new_rid((uint32*)&c->opt_rid) ) {
605                                         d_fprintf( stderr,
606                                             _("Could not allocate new RID\n"));
607                                         return -1;
608                                 }
609                         } else {
610                                 c->opt_rid = algorithmic_pdb_gid_to_group_rid(map.gid);
611                         }
612                 }
613
614                 sid_compose(&map.sid, get_global_sam_sid(), c->opt_rid);
615
616                 map.sid_name_use = SID_NAME_DOM_GRP;
617                 fstrcpy(map.nt_name, ntgroup);
618                 fstrcpy(map.comment, "");
619
620                 if (!NT_STATUS_IS_OK(pdb_add_group_mapping_entry(&map))) {
621                         d_fprintf(stderr,
622                                   _("Could not add mapping entry for %s\n"),
623                                   ntgroup);
624                         return -1;
625                 }
626         }
627
628         /* Now we have a mapping entry, update that stuff */
629
630         if ( c->opt_localgroup || c->opt_domaingroup ) {
631                 if (map.sid_name_use == SID_NAME_WKN_GRP) {
632                         d_fprintf(stderr,
633                                   _("Can't change type of the BUILTIN "
634                                     "group %s\n"),
635                                   map.nt_name);
636                         return -1;
637                 }
638         }
639
640         if (c->opt_localgroup)
641                 map.sid_name_use = SID_NAME_ALIAS;
642
643         if (c->opt_domaingroup)
644                 map.sid_name_use = SID_NAME_DOM_GRP;
645
646         /* The case (opt_domaingroup && opt_localgroup) was tested for above */
647
648         if ((c->opt_comment != NULL) && (strlen(c->opt_comment) > 0)) {
649                 fstrcpy(map.comment, c->opt_comment);
650         }
651
652         if ((c->opt_newntname != NULL) && (strlen(c->opt_newntname) > 0)) {
653                 fstrcpy(map.nt_name, c->opt_newntname);
654         }
655
656         if (grp != NULL)
657                 map.gid = grp->gr_gid;
658
659         if (!NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map))) {
660                 d_fprintf(stderr, _("Could not update group mapping for %s\n"),
661                           ntgroup);
662                 return -1;
663         }
664
665         return 0;
666 }
667
668 static int net_groupmap_cleanup(struct net_context *c, int argc, const char **argv)
669 {
670         GROUP_MAP *map = NULL;
671         size_t i, entries;
672
673         if (c->display_usage) {
674                 d_printf(  "%s\n"
675                            "net groupmap cleanup\n"
676                            "    %s\n",
677                          _("Usage:"),
678                          _("Delete all group mappings"));
679                 return 0;
680         }
681
682         if (!pdb_enum_group_mapping(NULL, SID_NAME_UNKNOWN, &map, &entries,
683                                     ENUM_ALL_MAPPED)) {
684                 d_fprintf(stderr, _("Could not list group mappings\n"));
685                 return -1;
686         }
687
688         for (i=0; i<entries; i++) {
689
690                 if (map[i].gid == -1)
691                         printf(_("Group %s is not mapped\n"), map[i].nt_name);
692
693                 if (!sid_check_is_in_our_domain(&map[i].sid)) {
694                         printf(_("Deleting mapping for NT Group %s, sid %s\n"),
695                                map[i].nt_name,
696                                sid_string_tos(&map[i].sid));
697                         pdb_delete_group_mapping_entry(map[i].sid);
698                 }
699         }
700
701         SAFE_FREE(map);
702
703         return 0;
704 }
705
706 static int net_groupmap_addmem(struct net_context *c, int argc, const char **argv)
707 {
708         struct dom_sid alias, member;
709
710         if ( (argc != 2) ||
711              c->display_usage ||
712              !string_to_sid(&alias, argv[0]) ||
713              !string_to_sid(&member, argv[1]) ) {
714                 d_printf("%s\n%s",
715                          _("Usage:"),
716                          _("net groupmap addmem alias-sid member-sid\n"));
717                 return -1;
718         }
719
720         if (!NT_STATUS_IS_OK(pdb_add_aliasmem(&alias, &member))) {
721                 d_fprintf(stderr, _("Could not add sid %s to alias %s\n"),
722                          argv[1], argv[0]);
723                 return -1;
724         }
725
726         return 0;
727 }
728
729 static int net_groupmap_delmem(struct net_context *c, int argc, const char **argv)
730 {
731         struct dom_sid alias, member;
732
733         if ( (argc != 2) ||
734              c->display_usage ||
735              !string_to_sid(&alias, argv[0]) ||
736              !string_to_sid(&member, argv[1]) ) {
737                 d_printf("%s\n%s",
738                          _("Usage:"),
739                          _("net groupmap delmem alias-sid member-sid\n"));
740                 return -1;
741         }
742
743         if (!NT_STATUS_IS_OK(pdb_del_aliasmem(&alias, &member))) {
744                 d_fprintf(stderr, _("Could not delete sid %s from alias %s\n"),
745                          argv[1], argv[0]);
746                 return -1;
747         }
748
749         return 0;
750 }
751
752 static int net_groupmap_listmem(struct net_context *c, int argc, const char **argv)
753 {
754         struct dom_sid alias;
755         struct dom_sid *members;
756         size_t i, num;
757
758         if ( (argc != 1) ||
759              c->display_usage ||
760              !string_to_sid(&alias, argv[0]) ) {
761                 d_printf("%s\n%s",
762                          _("Usage:"),
763                          _("net groupmap listmem alias-sid\n"));
764                 return -1;
765         }
766
767         members = NULL;
768         num = 0;
769
770         if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(&alias, talloc_tos(),
771                                                &members, &num))) {
772                 d_fprintf(stderr, _("Could not list members for sid %s\n"),
773                           argv[0]);
774                 return -1;
775         }
776
777         for (i = 0; i < num; i++) {
778                 printf("%s\n", sid_string_tos(&(members[i])));
779         }
780
781         TALLOC_FREE(members);
782
783         return 0;
784 }
785
786 static bool print_alias_memberships(TALLOC_CTX *mem_ctx,
787                                     const struct dom_sid *domain_sid,
788                                     const struct dom_sid *member)
789 {
790         uint32 *alias_rids;
791         size_t i, num_alias_rids;
792
793         alias_rids = NULL;
794         num_alias_rids = 0;
795
796         if (!NT_STATUS_IS_OK(pdb_enum_alias_memberships(
797                                      mem_ctx, domain_sid, member, 1,
798                                      &alias_rids, &num_alias_rids))) {
799                 d_fprintf(stderr, _("Could not list memberships for sid %s\n"),
800                          sid_string_tos(member));
801                 return false;
802         }
803
804         for (i = 0; i < num_alias_rids; i++) {
805                 struct dom_sid alias;
806                 sid_compose(&alias, domain_sid, alias_rids[i]);
807                 printf("%s\n", sid_string_tos(&alias));
808         }
809
810         return true;
811 }
812
813 static int net_groupmap_memberships(struct net_context *c, int argc, const char **argv)
814 {
815         TALLOC_CTX *mem_ctx;
816         struct dom_sid *domain_sid, member;
817
818         if ( (argc != 1) ||
819              c->display_usage ||
820              !string_to_sid(&member, argv[0]) ) {
821                 d_printf("%s\n%s",
822                          _("Usage:"),
823                          _("net groupmap memberof sid\n"));
824                 return -1;
825         }
826
827         mem_ctx = talloc_init("net_groupmap_memberships");
828         if (mem_ctx == NULL) {
829                 d_fprintf(stderr, _("talloc_init failed\n"));
830                 return -1;
831         }
832
833         domain_sid = get_global_sam_sid();
834         if (domain_sid == NULL) {
835                 d_fprintf(stderr, _("Could not get domain sid\n"));
836                 return -1;
837         }
838
839         if (!print_alias_memberships(mem_ctx, domain_sid, &member) ||
840             !print_alias_memberships(mem_ctx, &global_sid_Builtin, &member))
841                 return -1;
842
843         talloc_destroy(mem_ctx);
844
845         return 0;
846 }
847
848 /***********************************************************
849  migrated functionality from smbgroupedit
850  **********************************************************/
851 int net_groupmap(struct net_context *c, int argc, const char **argv)
852 {
853         struct functable func[] = {
854                 {
855                         "add",
856                         net_groupmap_add,
857                         NET_TRANSPORT_LOCAL,
858                         N_("Create a new group mapping"),
859                         N_("net groupmap add\n"
860                            "    Create a new group mapping")
861                 },
862                 {
863                         "modify",
864                         net_groupmap_modify,
865                         NET_TRANSPORT_LOCAL,
866                         N_("Update a group mapping"),
867                         N_("net groupmap modify\n"
868                            "    Modify an existing group mapping")
869                 },
870                 {
871                         "delete",
872                         net_groupmap_delete,
873                         NET_TRANSPORT_LOCAL,
874                         N_("Remove a group mapping"),
875                         N_("net groupmap delete\n"
876                            "    Remove a group mapping")
877                 },
878                 {
879                         "set",
880                         net_groupmap_set,
881                         NET_TRANSPORT_LOCAL,
882                         N_("Set group mapping"),
883                         N_("net groupmap set\n"
884                            "    Set a group mapping")
885                 },
886                 {
887                         "cleanup",
888                         net_groupmap_cleanup,
889                         NET_TRANSPORT_LOCAL,
890                         N_("Remove foreign group mapping entries"),
891                         N_("net groupmap cleanup\n"
892                            "    Remove foreign group mapping entries")
893                 },
894                 {
895                         "addmem",
896                         net_groupmap_addmem,
897                         NET_TRANSPORT_LOCAL,
898                         N_("Add a foreign alias member"),
899                         N_("net groupmap addmem\n"
900                            "    Add a foreign alias member")
901                 },
902                 {
903                         "delmem",
904                         net_groupmap_delmem,
905                         NET_TRANSPORT_LOCAL,
906                         N_("Delete foreign alias member"),
907                         N_("net groupmap delmem\n"
908                            "    Delete foreign alias member")
909                 },
910                 {
911                         "listmem",
912                         net_groupmap_listmem,
913                         NET_TRANSPORT_LOCAL,
914                         N_("List foreign group members"),
915                         N_("net groupmap listmem\n"
916                            "    List foreign alias members")
917                 },
918                 {
919                         "memberships",
920                         net_groupmap_memberships,
921                         NET_TRANSPORT_LOCAL,
922                         N_("List foreign group memberships"),
923                         N_("net groupmap memberships\n"
924                            "    List foreign group memberships")
925                 },
926                 {
927                         "list",
928                         net_groupmap_list,
929                         NET_TRANSPORT_LOCAL,
930                         N_("List current group map"),
931                         N_("net groupmap list\n"
932                            "    List current group map")
933                 },
934                 {NULL, NULL, 0, NULL, NULL}
935         };
936
937         return net_run_function(c,argc, argv, "net groupmap", func);
938 }
939