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