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