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