1/*
2   Unix SMB/CIFS implementation.
3
4   Winbind account management functions
5
6   Copyright (C) by Gerald (Jerry) Carter       2003
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23#include "includes.h"
24#include "winbindd.h"
25
26#undef DBGC_CLASS
27#define DBGC_CLASS DBGC_WINBIND
28
29#define WBKEY_PASSWD	"WBA_PASSWD"
30#define WBKEY_GROUP	"WBA_GROUP"
31
32#define NUM_PW_FIELDS	7
33#define NUM_GRP_FIELDS	4
34
35/* Globals */
36
37static TDB_CONTEXT *account_tdb;
38
39extern userdom_struct current_user_info;
40
41struct _check_primary_grp {
42	gid_t	gid;
43	BOOL	found;
44};
45
46/**********************************************************************
47**********************************************************************/
48
49static void free_winbindd_gr( WINBINDD_GR *grp )
50{
51	int i;
52
53	if ( !grp )
54		return;
55
56	for ( i=0; i<grp->num_gr_mem; i++ )
57		SAFE_FREE( grp->gr_mem[i] );
58
59	SAFE_FREE( grp->gr_mem );
60
61	return;
62}
63
64/*****************************************************************************
65 Initialise auto-account database.
66*****************************************************************************/
67
68static BOOL winbindd_accountdb_init(void)
69{
70	/* see if we've already opened the tdb */
71
72	if ( account_tdb )
73		return True;
74
75	/* winbindd_idmap.tdb should always be opened by the idmap_init()
76	   code first */
77
78	if ( !(account_tdb = idmap_tdb_handle()) ) {
79		DEBUG(0, ("winbindd_accountdb_init: Unable to retreive handle for database\n"));
80		return False;
81	}
82
83	/* yeah! */
84
85	return True;
86}
87
88/**********************************************************************
89 Convert a string in /etc/passwd format to a struct passwd* entry
90**********************************************************************/
91
92static WINBINDD_PW* string2passwd( char *string )
93{
94	static WINBINDD_PW pw;
95	char *p, *str;
96	char *fields[NUM_PW_FIELDS];
97	int i;
98
99	if ( !string )
100		return NULL;
101
102	ZERO_STRUCTP( &pw );
103
104	DEBUG(10,("string2passwd: converting \"%s\"\n", string));
105
106	ZERO_STRUCT( fields );
107
108	for ( i=0, str=string; i<NUM_PW_FIELDS-1; i++ ) {
109		if ( !(p = strchr( str, ':' )) ) {
110			DEBUG(0,("string2passwd: parsing failure\n"));
111			return NULL;
112		}
113		*p = '\0';
114		if ( str )
115			fields[i] = str;
116		str = p + 1;
117	}
118	if ( str )
119		fields[i] = str;
120
121	/* copy fields */
122
123	fstrcpy( pw.pw_name,   fields[0] );
124	fstrcpy( pw.pw_passwd, fields[1] );
125	pw.pw_uid = atoi(      fields[2] );
126	pw.pw_gid = atoi(      fields[3] );
127	fstrcpy( pw.pw_gecos,  fields[4] );
128	fstrcpy( pw.pw_dir,    fields[5] );
129	fstrcpy( pw.pw_shell,  fields[6] );
130
131
132	/* last minute sanity checks */
133
134	if ( pw.pw_uid==0 || pw.pw_gid==0 ) {
135		DEBUG(0,("string2passwd: Failure! uid==%lu, gid==%lu\n",
136			(unsigned long)pw.pw_uid, (unsigned long)pw.pw_gid));
137		return NULL;
138	}
139
140	DEBUG(10,("string2passwd: Success\n"));
141
142	return &pw;
143}
144
145/**********************************************************************
146 Convert a struct passwd* to a string formatted for /etc/passwd
147**********************************************************************/
148
149static char* passwd2string( const WINBINDD_PW *pw )
150{
151	static pstring string;
152	int ret;
153
154	if ( !pw || !pw->pw_name )
155		return NULL;
156
157	DEBUG(10,("passwd2string: converting passwd struct for %s\n",
158		pw->pw_name));
159
160	ret = pstr_sprintf( string, "%s:%s:%lu:%lu:%s:%s:%s",
161		pw->pw_name,
162		pw->pw_passwd ? pw->pw_passwd : "x",
163		(unsigned long)pw->pw_uid,
164		(unsigned long)pw->pw_gid,
165		pw->pw_gecos,
166		pw->pw_dir,
167		pw->pw_shell );
168
169	if ( ret < 0 ) {
170		DEBUG(0,("passwd2string: pstr_sprintf() failed!\n"));
171		return NULL;
172	}
173
174	return string;
175}
176
177/**********************************************************************
178 Convert a string in /etc/group format to a struct group* entry
179**********************************************************************/
180
181static WINBINDD_GR* string2group( char *string )
182{
183	static WINBINDD_GR grp;
184	char *p, *str;
185	char *fields[NUM_GRP_FIELDS];
186	int i;
187	char **gr_members = NULL;
188	int num_gr_members = 0;
189
190	if ( !string )
191		return NULL;
192
193	ZERO_STRUCTP( &grp );
194
195	DEBUG(10,("string2group: converting \"%s\"\n", string));
196
197	ZERO_STRUCT( fields );
198
199	for ( i=0, str=string; i<NUM_GRP_FIELDS-1; i++ ) {
200		if ( !(p = strchr( str, ':' )) ) {
201			DEBUG(0,("string2group: parsing failure\n"));
202			return NULL;
203		}
204		*p = '\0';
205		if ( str )
206			fields[i] = str;
207		str = p + 1;
208	}
209
210	/* group members */
211
212	if ( *str ) {
213		/* we already know we have a non-empty string */
214
215		num_gr_members = count_chars(str, ',') + 1;
216
217		/* if there was at least one comma, then there
218		   are n+1 members */
219		if ( num_gr_members ) {
220			fstring buffer;
221
222			gr_members = SMB_XMALLOC_ARRAY(char*, num_gr_members+1);
223
224			i = 0;
225			while ( next_token(&str, buffer, ",", sizeof(buffer)) && i<num_gr_members ) {
226				gr_members[i++] = smb_xstrdup(buffer);
227			}
228
229			gr_members[i]   = NULL;
230		}
231	}
232
233
234	/* copy fields */
235
236	fstrcpy( grp.gr_name,   fields[0] );
237	fstrcpy( grp.gr_passwd, fields[1] );
238	grp.gr_gid = atoi(      fields[2] );
239
240	grp.num_gr_mem = num_gr_members;
241	grp.gr_mem     = gr_members;
242
243	/* last minute sanity checks */
244
245	if ( grp.gr_gid == 0 ) {
246		DEBUG(0,("string2group: Failure! gid==%lu\n", (unsigned long)grp.gr_gid));
247		SAFE_FREE( gr_members );
248		return NULL;
249	}
250
251	DEBUG(10,("string2group: Success\n"));
252
253	return &grp;
254}
255
256/**********************************************************************
257 Convert a struct group* to a string formatted for /etc/group
258**********************************************************************/
259
260static char* group2string( const WINBINDD_GR *grp )
261{
262	static pstring string;
263	int ret;
264	char *member, *gr_mem_str;
265	int num_members;
266	int i, size;
267
268	if ( !grp || !grp->gr_name )
269		return NULL;
270
271	DEBUG(10,("group2string: converting passwd struct for %s\n",
272		grp->gr_name));
273
274	if ( grp->num_gr_mem ) {
275		int idx = 0;
276
277		member = grp->gr_mem[0];
278		size = 0;
279		num_members = 0;
280
281		while ( member ) {
282			size += strlen(member) + 1;
283			num_members++;
284			member = grp->gr_mem[num_members];
285		}
286
287		gr_mem_str = SMB_XMALLOC_ARRAY(char, size);
288
289		for ( i=0; i<num_members; i++ ) {
290			snprintf( &gr_mem_str[idx], size-idx, "%s,", grp->gr_mem[i] );
291			idx += strlen(grp->gr_mem[i]) + 1;
292		}
293		/* add trailing NULL (also removes trailing ',' */
294		gr_mem_str[size-1] = '\0';
295	}
296	else {
297		/* no members */
298		gr_mem_str = SMB_XMALLOC_ARRAY(char, sizeof(fstring));
299		fstrcpy( gr_mem_str, "" );
300	}
301
302	ret = pstr_sprintf( string, "%s:%s:%lu:%s",
303		grp->gr_name,
304		grp->gr_passwd ? grp->gr_passwd : "*",
305		(unsigned long)grp->gr_gid,
306		gr_mem_str );
307
308	SAFE_FREE( gr_mem_str );
309
310	if ( ret < 0 ) {
311		DEBUG(0,("group2string: pstr_sprintf() failed!\n"));
312		return NULL;
313	}
314
315	return string;
316}
317
318/**********************************************************************
319**********************************************************************/
320
321static char* acct_userkey_byname( const char *name )
322{
323	static fstring key;
324
325	fstr_sprintf( key, "%s/NAME/%s", WBKEY_PASSWD, name );
326
327	return key;
328}
329
330/**********************************************************************
331**********************************************************************/
332
333static char* acct_userkey_byuid( uid_t uid )
334{
335	static fstring key;
336
337	fstr_sprintf( key, "%s/UID/%lu", WBKEY_PASSWD, (unsigned long)uid );
338
339	return key;
340}
341
342/**********************************************************************
343**********************************************************************/
344
345static char* acct_groupkey_byname( const char *name )
346{
347	static fstring key;
348
349	fstr_sprintf( key, "%s/NAME/%s", WBKEY_GROUP, name );
350
351	return key;
352}
353
354/**********************************************************************
355**********************************************************************/
356
357static char* acct_groupkey_bygid( gid_t gid )
358{
359	static fstring key;
360
361	fstr_sprintf( key, "%s/GID/%lu", WBKEY_GROUP, (unsigned long)gid );
362
363	return key;
364}
365
366/**********************************************************************
367**********************************************************************/
368
369WINBINDD_PW* wb_getpwnam( const char * name )
370{
371	char *keystr;
372	TDB_DATA data;
373	static WINBINDD_PW *pw;
374
375	if ( !account_tdb && !winbindd_accountdb_init() ) {
376		DEBUG(0,("wb_getpwnam: Failed to open winbindd account db\n"));
377		return NULL;
378	}
379
380
381	keystr = acct_userkey_byname( name );
382
383	data = tdb_fetch_bystring( account_tdb, keystr );
384
385	pw = NULL;
386
387	if ( data.dptr ) {
388		pw = string2passwd( data.dptr );
389		SAFE_FREE( data.dptr );
390	}
391
392	DEBUG(5,("wb_getpwnam: %s user (%s)\n",
393		(pw ? "Found" : "Did not find"), name ));
394
395	return pw;
396}
397
398/**********************************************************************
399**********************************************************************/
400
401WINBINDD_PW* wb_getpwuid( const uid_t uid )
402{
403	char *keystr;
404	TDB_DATA data;
405	static WINBINDD_PW *pw;
406
407	if ( !account_tdb && !winbindd_accountdb_init() ) {
408		DEBUG(0,("wb_getpwuid: Failed to open winbindd account db\n"));
409		return NULL;
410	}
411
412	data = tdb_fetch_bystring( account_tdb, acct_userkey_byuid(uid) );
413	if ( !data.dptr ) {
414		DEBUG(4,("wb_getpwuid: failed to locate uid == %lu\n", (unsigned long)uid));
415		return NULL;
416	}
417	keystr = acct_userkey_byname( data.dptr );
418
419	SAFE_FREE( data.dptr );
420
421	data = tdb_fetch_bystring( account_tdb, keystr );
422
423	pw = NULL;
424
425	if ( data.dptr ) {
426		pw = string2passwd( data.dptr );
427		SAFE_FREE( data.dptr );
428	}
429
430	DEBUG(5,("wb_getpwuid: %s user (uid == %lu)\n",
431		(pw ? "Found" : "Did not find"), (unsigned long)uid ));
432
433	return pw;
434}
435
436/**********************************************************************
437**********************************************************************/
438
439static BOOL wb_storepwnam( const WINBINDD_PW *pw )
440{
441	char *namekey, *uidkey;
442	TDB_DATA data;
443	char *str;
444	int ret = 0;
445	fstring username;
446
447	if ( !account_tdb && !winbindd_accountdb_init() ) {
448		DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
449		return False;
450	}
451
452	namekey = acct_userkey_byname( pw->pw_name );
453
454	/* lock the main entry first */
455
456	if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
457		DEBUG(0,("wb_storepwnam: Failed to lock %s\n", namekey));
458		return False;
459	}
460
461	str = passwd2string( pw );
462
463	data.dptr = str;
464	data.dsize = strlen(str) + 1;
465
466	if ( (tdb_store_bystring(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
467		DEBUG(0,("wb_storepwnam: Failed to store \"%s\"\n", str));
468		ret = -1;
469		goto done;
470	}
471
472	/* store the uid index */
473
474	uidkey = acct_userkey_byuid(pw->pw_uid);
475
476	fstrcpy( username, pw->pw_name );
477	data.dptr = username;
478	data.dsize = strlen(username) + 1;
479
480	if ( (tdb_store_bystring(account_tdb, uidkey, data, TDB_REPLACE)) == -1 ) {
481		DEBUG(0,("wb_storepwnam: Failed to store uid key \"%s\"\n", str));
482		tdb_delete_bystring(account_tdb, namekey);
483		ret = -1;
484		goto done;
485	}
486
487	DEBUG(10,("wb_storepwnam: Success -> \"%s\"\n", str));
488
489done:
490	tdb_unlock_bystring( account_tdb, namekey );
491
492	return ( ret == 0 );
493}
494
495/**********************************************************************
496**********************************************************************/
497
498WINBINDD_GR* wb_getgrnam( const char * name )
499{
500	char *keystr;
501	TDB_DATA data;
502	static WINBINDD_GR *grp;
503
504	if ( !account_tdb && !winbindd_accountdb_init() ) {
505		DEBUG(0,("wb_getgrnam: Failed to open winbindd account db\n"));
506		return NULL;
507	}
508
509
510	keystr = acct_groupkey_byname( name );
511
512	data = tdb_fetch_bystring( account_tdb, keystr );
513
514	grp = NULL;
515
516	if ( data.dptr ) {
517		grp = string2group( data.dptr );
518		SAFE_FREE( data.dptr );
519	}
520
521	DEBUG(5,("wb_getgrnam: %s group (%s)\n",
522		(grp ? "Found" : "Did not find"), name ));
523
524	return grp;
525}
526
527/**********************************************************************
528**********************************************************************/
529
530WINBINDD_GR* wb_getgrgid( gid_t gid )
531{
532	char *keystr;
533	TDB_DATA data;
534	static WINBINDD_GR *grp;
535
536	if ( !account_tdb && !winbindd_accountdb_init() ) {
537		DEBUG(0,("wb_getgrgid: Failed to open winbindd account db\n"));
538		return NULL;
539	}
540
541	data = tdb_fetch_bystring( account_tdb, acct_groupkey_bygid(gid) );
542	if ( !data.dptr ) {
543		DEBUG(4,("wb_getgrgid: failed to locate gid == %lu\n",
544			 (unsigned long)gid));
545		return NULL;
546	}
547	keystr = acct_groupkey_byname( data.dptr );
548
549	SAFE_FREE( data.dptr );
550
551	data = tdb_fetch_bystring( account_tdb, keystr );
552
553	grp = NULL;
554
555	if ( data.dptr ) {
556		grp = string2group( data.dptr );
557		SAFE_FREE( data.dptr );
558	}
559
560	DEBUG(5,("wb_getgrgid: %s group (gid == %lu)\n",
561		(grp ? "Found" : "Did not find"), (unsigned long)gid ));
562
563	return grp;
564}
565
566/**********************************************************************
567**********************************************************************/
568
569static BOOL wb_storegrnam( const WINBINDD_GR *grp )
570{
571	char *namekey, *gidkey;
572	TDB_DATA data;
573	char *str;
574	int ret = 0;
575	fstring groupname;
576
577	if ( !account_tdb && !winbindd_accountdb_init() ) {
578		DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
579		return False;
580	}
581
582	namekey = acct_groupkey_byname( grp->gr_name );
583
584	/* lock the main entry first */
585
586	if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
587		DEBUG(0,("wb_storegrnam: Failed to lock %s\n", namekey));
588		return False;
589	}
590
591	str = group2string( grp );
592
593	data.dptr = str;
594	data.dsize = strlen(str) + 1;
595
596	if ( (tdb_store_bystring(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
597		DEBUG(0,("wb_storegrnam: Failed to store \"%s\"\n", str));
598		ret = -1;
599		goto done;
600	}
601
602	/* store the gid index */
603
604	gidkey = acct_groupkey_bygid(grp->gr_gid);
605
606	fstrcpy( groupname, grp->gr_name );
607	data.dptr = groupname;
608	data.dsize = strlen(groupname) + 1;
609
610	if ( (tdb_store_bystring(account_tdb, gidkey, data, TDB_REPLACE)) == -1 ) {
611		DEBUG(0,("wb_storegrnam: Failed to store gid key \"%s\"\n", str));
612		tdb_delete_bystring(account_tdb, namekey);
613		ret = -1;
614		goto done;
615	}
616
617	DEBUG(10,("wb_storegrnam: Success -> \"%s\"\n", str));
618
619done:
620	tdb_unlock_bystring( account_tdb, namekey );
621
622	return ( ret == 0 );
623}
624
625/**********************************************************************
626**********************************************************************/
627
628static BOOL wb_addgrpmember( WINBINDD_GR *grp, const char *user )
629{
630	int i;
631	char **members;
632
633	if ( !grp || !user )
634		return False;
635
636	for ( i=0; i<grp->num_gr_mem; i++ ) {
637		if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 )
638			return True;
639	}
640
641	/* add one new slot and keep an extra for the terminating NULL */
642	members = SMB_REALLOC_ARRAY( grp->gr_mem, char *, grp->num_gr_mem+2);
643	if ( !members )
644		return False;
645
646	grp->gr_mem = members;
647	grp->gr_mem[grp->num_gr_mem++] = smb_xstrdup(user);
648	grp->gr_mem[grp->num_gr_mem]   = NULL;
649
650	return True;
651}
652
653/**********************************************************************
654**********************************************************************/
655
656static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user )
657{
658	int i;
659	BOOL found = False;
660
661	if ( !grp || !user )
662		return False;
663
664	for ( i=0; i<grp->num_gr_mem; i++ ) {
665		if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 ) {
666			found = True;
667			break;
668		}
669	}
670
671	if ( !found )
672		return False;
673
674	/* still some remaining members */
675
676	if ( grp->num_gr_mem > 1 ) {
677		SAFE_FREE(grp->gr_mem[i]);
678		grp->num_gr_mem--;
679		grp->gr_mem[i] = grp->gr_mem[grp->num_gr_mem];
680		grp->gr_mem[grp->num_gr_mem] = NULL;
681	}
682	else {	/* last one */
683		free_winbindd_gr( grp );
684		grp->gr_mem = NULL;
685		grp->num_gr_mem = 0;
686	}
687
688	return True;
689}
690
691/**********************************************************************
692**********************************************************************/
693
694static int cleangroups_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
695		       void *state)
696{
697	int len;
698	fstring key;
699	char *name = (char*)state;
700
701	fstr_sprintf( key, "%s/NAME", WBKEY_GROUP );
702	len = strlen(key);
703
704	/* if this is a group entry then, check the members */
705
706	if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) {
707		WINBINDD_GR *grp;
708
709		if ( !(grp = string2group( dbuf.dptr )) ) {
710			DEBUG(0,("cleangroups_traverse_fn: Failure to parse [%s]\n",
711				dbuf.dptr));
712			return 0;
713		}
714
715		/* just try to delete the user and rely on wb_delgrpmember()
716		   to tell you whether or not the group changed.  This is more
717		   effecient than testing group membership first since the
718		   checks for deleting a user from a group is essentially the
719		   same as checking if he/she is a member */
720
721		if ( wb_delgrpmember( grp, name ) ) {
722			DEBUG(10,("cleanupgroups_traverse_fn: Removed user (%s) from group (%s)\n",
723				name, grp->gr_name));
724			wb_storegrnam( grp );
725		}
726
727		free_winbindd_gr( grp );
728	}
729
730	return 0;
731}
732
733/**********************************************************************
734**********************************************************************/
735
736static BOOL wb_delete_user( WINBINDD_PW *pw)
737{
738	char *namekey;
739	char *uidkey;
740
741	if ( !account_tdb && !winbindd_accountdb_init() ) {
742		DEBUG(0,("wb_delete_user: Failed to open winbindd account db\n"));
743		return False;
744	}
745
746	namekey = acct_userkey_byname( pw->pw_name );
747
748	/* lock the main entry first */
749
750	if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
751		DEBUG(0,("wb_delete_user: Failed to lock %s\n", namekey));
752		return False;
753	}
754
755	/* remove user from all groups */
756
757	tdb_traverse(account_tdb, cleangroups_traverse_fn, (void *)pw->pw_name);
758
759	/* remove the user */
760	uidkey = acct_userkey_byuid( pw->pw_uid );
761
762	tdb_delete_bystring( account_tdb, namekey );
763	tdb_delete_bystring( account_tdb, uidkey );
764
765	tdb_unlock_bystring( account_tdb, namekey );
766
767	return True;
768}
769
770/**********************************************************************
771**********************************************************************/
772
773static int isprimarygroup_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
774                                      TDB_DATA dbuf, void *params)
775{
776	int len;
777	fstring key;
778	struct _check_primary_grp *check = (struct _check_primary_grp*)params;
779
780	fstr_sprintf( key, "%s/NAME", WBKEY_PASSWD );
781	len = strlen(key);
782
783	/* if this is a group entry then, check the members */
784
785	if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) {
786		WINBINDD_PW *pw;;
787
788		if ( !(pw = string2passwd( dbuf.dptr )) ) {
789			DEBUG(0,("isprimarygroup_traverse_fn: Failure to parse [%s]\n",
790				dbuf.dptr));
791			return 0;
792		}
793
794		if ( check->gid == pw->pw_gid ) {
795			check->found = True;
796			return 1;
797		}
798	}
799
800	return 0;
801}
802
803
804/**********************************************************************
805**********************************************************************/
806
807static BOOL wb_delete_group( WINBINDD_GR *grp )
808{
809	struct _check_primary_grp check;
810	char *namekey;
811	char *gidkey;
812
813	if ( !account_tdb && !winbindd_accountdb_init() ) {
814		DEBUG(0,("wb_delete_group: Failed to open winbindd account db\n"));
815		return False;
816	}
817
818	/* lock the main entry first */
819
820	namekey = acct_groupkey_byname( grp->gr_name );
821	if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
822		DEBUG(0,("wb_delete_group: Failed to lock %s\n", namekey));
823		return False;
824	}
825
826	/* is this group the primary group for any user?  If
827	   so deny delete */
828
829	check.found = False;
830	tdb_traverse(account_tdb, isprimarygroup_traverse_fn, (void *)&check);
831
832	if ( check.found ) {
833		DEBUG(4,("wb_delete_group: Cannot delete group (%s) since it "
834			"is the primary group for some users\n", grp->gr_name));
835		return False;
836	}
837
838	/* We're clear.  Delete the group */
839
840	DEBUG(5,("wb_delete_group: Removing group (%s)\n", grp->gr_name));
841
842	gidkey = acct_groupkey_bygid( grp->gr_gid );
843
844	tdb_delete_bystring( account_tdb, namekey );
845	tdb_delete_bystring( account_tdb, gidkey );
846
847	tdb_unlock_bystring( account_tdb, namekey );
848
849	return True;
850}
851
852/**********************************************************************
853 Create a new "UNIX" user for the system given a username
854**********************************************************************/
855
856enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
857{
858	char *user, *group;
859	unid_t id;
860	WINBINDD_PW pw, *pw_check;
861	WINBINDD_GR *wb_grp;
862	struct group *unix_grp;
863	gid_t primary_gid;
864	uint32 flags = state->request.flags;
865	uint32 rid;
866
867	if ( !state->privileged ) {
868		DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n"));
869		return WINBINDD_ERROR;
870	}
871
872	/* Ensure null termination */
873	state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
874	state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
875
876	user  = state->request.data.acct_mgt.username;
877	group = state->request.data.acct_mgt.groupname;
878
879	DEBUG(3, ("[%5lu]: create_user: user=>(%s), group=>(%s)\n",
880		(unsigned long)state->pid, user, group));
881
882	if ( (pw_check=wb_getpwnam(user)) != NULL ) {
883		DEBUG(0,("winbindd_create_user: Refusing to create user that already exists (%s)\n",
884			user));
885		return WINBINDD_ERROR;
886	}
887
888
889	if ( !*group )
890		group = lp_template_primary_group();
891
892	/* validate the primary group
893	   1) lookup in local tdb first
894	   2) call getgrnam() as a last resort */
895
896	if ( (wb_grp=wb_getgrnam(group)) != NULL ) {
897		primary_gid = wb_grp->gr_gid;
898		free_winbindd_gr( wb_grp );
899	}
900	else if ( (unix_grp=sys_getgrnam(group)) != NULL ) {
901		primary_gid = unix_grp->gr_gid;
902	}
903	else {
904		DEBUG(2,("winbindd_create_user: Cannot validate gid for group (%s)\n", group));
905		return WINBINDD_ERROR;
906	}
907
908	/* get a new uid */
909
910	if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_USERID)) ) {
911		DEBUG(0,("winbindd_create_user: idmap_allocate_id() failed!\n"));
912		return WINBINDD_ERROR;
913	}
914
915	/* The substitution of %U and %D in the 'template homedir' is done
916	   by lp_string() calling standard_sub_basic(). */
917
918	fstrcpy( current_user_info.smb_name, user );
919	sub_set_smb_name( user );
920	fstrcpy( current_user_info.domain, get_global_sam_name() );
921
922	/* fill in the passwd struct */
923
924	fstrcpy( pw.pw_name,   user );
925	fstrcpy( pw.pw_passwd, "x" );
926	fstrcpy( pw.pw_gecos,  user);
927	fstrcpy( pw.pw_dir,    lp_template_homedir() );
928	fstrcpy( pw.pw_shell,  lp_template_shell() );
929
930	pw.pw_uid = id.uid;
931	pw.pw_gid = primary_gid;
932
933	/* store the new entry */
934
935	if ( !wb_storepwnam(&pw) )
936		return WINBINDD_ERROR;
937
938	/* do we need a new RID? */
939
940	if ( flags & WBFLAG_ALLOCATE_RID ) {
941		if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, USER_RID_TYPE)) ) {
942			DEBUG(0,("winbindd_create_user: RID allocation failure!  Cannot create user (%s)\n",
943				user));
944			wb_delete_user( &pw );
945
946			return WINBINDD_ERROR;
947		}
948
949		state->response.data.rid = rid;
950	}
951
952	return WINBINDD_OK;
953}
954
955/**********************************************************************
956 Create a new "UNIX" group for the system given a username
957**********************************************************************/
958
959enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
960{
961	char *group;
962	unid_t id;
963	WINBINDD_GR grp, *grp_check;
964	uint32 flags = state->request.flags;
965	uint32 rid;
966
967	if ( !state->privileged ) {
968		DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n"));
969		return WINBINDD_ERROR;
970	}
971
972	/* Ensure null termination */
973	state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
974	group = state->request.data.acct_mgt.groupname;
975
976	DEBUG(3, ("[%5lu]: create_group: (%s)\n", (unsigned long)state->pid, group));
977
978	if ( (grp_check=wb_getgrnam(group)) != NULL ) {
979		DEBUG(0,("winbindd_create_group: Refusing to create group that already exists (%s)\n",
980			group));
981		return WINBINDD_ERROR;
982	}
983
984	/* get a new gid */
985
986	if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_GROUPID)) ) {
987		DEBUG(0,("winbindd_create_group: idmap_allocate_id() failed!\n"));
988		return WINBINDD_ERROR;
989	}
990
991	/* fill in the group struct */
992
993	fstrcpy( grp.gr_name,   group );
994	fstrcpy( grp.gr_passwd, "*" );
995
996	grp.gr_gid      = id.gid;
997	grp.gr_mem      = NULL;	/* start with no members */
998	grp.num_gr_mem  = 0;
999
1000	if ( !wb_storegrnam(&grp) )
1001		return WINBINDD_ERROR;
1002
1003	/* do we need a new RID? */
1004
1005	if ( flags & WBFLAG_ALLOCATE_RID ) {
1006		if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, GROUP_RID_TYPE)) ) {
1007			DEBUG(0,("winbindd_create_group: RID allocation failure!  Cannot create group (%s)\n",
1008				group));
1009			wb_delete_group( &grp );
1010
1011			return WINBINDD_ERROR;
1012		}
1013
1014		state->response.data.rid = rid;
1015	}
1016
1017	return WINBINDD_OK;
1018}
1019
1020/**********************************************************************
1021 Add a user to the membership for a group.
1022**********************************************************************/
1023
1024enum winbindd_result winbindd_add_user_to_group(struct winbindd_cli_state *state)
1025{
1026	WINBINDD_PW *pw;
1027	WINBINDD_GR *grp;
1028	char *user, *group;
1029	BOOL ret;
1030
1031	if ( !state->privileged ) {
1032		DEBUG(2, ("winbindd_add_user_to_group: non-privileged access denied!\n"));
1033		return WINBINDD_ERROR;
1034	}
1035
1036	/* Ensure null termination */
1037	state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
1038	state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
1039	group = state->request.data.acct_mgt.groupname;
1040	user = state->request.data.acct_mgt.username;
1041
1042	DEBUG(3, ("[%5lu]:  add_user_to_group: add %s to %s\n", (unsigned long)state->pid,
1043		user, group));
1044
1045	/* make sure it is a valid user */
1046
1047	if ( !(pw = wb_getpwnam( user )) ) {
1048		DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
1049		return WINBINDD_ERROR;
1050	}
1051
1052	/* make sure it is a valid group */
1053
1054	if ( !(grp = wb_getgrnam( group )) ) {
1055		DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
1056		return WINBINDD_ERROR;
1057	}
1058
1059	if ( !wb_addgrpmember( grp, user ) )
1060		return WINBINDD_ERROR;
1061
1062	ret = wb_storegrnam(grp);
1063
1064	free_winbindd_gr( grp );
1065
1066	return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
1067}
1068
1069/**********************************************************************
1070 Remove a user from the membership of a group
1071**********************************************************************/
1072
1073enum winbindd_result winbindd_remove_user_from_group(struct winbindd_cli_state *state)
1074{
1075	WINBINDD_GR *grp;
1076	char *user, *group;
1077	BOOL ret;
1078
1079	if ( !state->privileged ) {
1080		DEBUG(2, ("winbindd_remove_user_from_group: non-privileged access denied!\n"));
1081		return WINBINDD_ERROR;
1082	}
1083
1084	/* Ensure null termination */
1085	state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
1086	state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
1087	group = state->request.data.acct_mgt.groupname;
1088	user = state->request.data.acct_mgt.username;
1089
1090	DEBUG(3, ("[%5lu]:  remove_user_from_group: delete %s from %s\n", (unsigned long)state->pid,
1091		user, group));
1092
1093	/* don't worry about checking the username since we're removing it anyways */
1094
1095	/* make sure it is a valid group */
1096
1097	if ( !(grp = wb_getgrnam( group )) ) {
1098		DEBUG(4,("winbindd_remove_user_from_group: Cannot remove a user from a non-extistent group\n"));
1099		return WINBINDD_ERROR;
1100	}
1101
1102	if ( !wb_delgrpmember( grp, user ) )
1103		return WINBINDD_ERROR;
1104
1105	ret = wb_storegrnam(grp);
1106
1107	free_winbindd_gr( grp );
1108
1109	return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
1110}
1111
1112/**********************************************************************
1113 Set the primary group membership of a user
1114**********************************************************************/
1115
1116enum winbindd_result winbindd_set_user_primary_group(struct winbindd_cli_state *state)
1117{
1118	WINBINDD_PW *pw;
1119	WINBINDD_GR *grp;
1120	char *user, *group;
1121
1122	if ( !state->privileged ) {
1123		DEBUG(2, ("winbindd_set_user_primary_group: non-privileged access denied!\n"));
1124		return WINBINDD_ERROR;
1125	}
1126
1127	/* Ensure null termination */
1128	state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
1129	state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
1130	group = state->request.data.acct_mgt.groupname;
1131	user = state->request.data.acct_mgt.username;
1132
1133	DEBUG(3, ("[%5lu]:  set_user_primary_group: group %s for user %s\n",
1134		  (unsigned long)state->pid, group, user));
1135
1136	/* make sure it is a valid user */
1137
1138	if ( !(pw = wb_getpwnam( user )) ) {
1139		DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
1140		return WINBINDD_ERROR;
1141	}
1142
1143	/* make sure it is a valid group */
1144
1145	if ( !(grp = wb_getgrnam( group )) ) {
1146		DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
1147		return WINBINDD_ERROR;
1148	}
1149
1150	pw->pw_gid = grp->gr_gid;
1151
1152	free_winbindd_gr( grp );
1153
1154	return ( wb_storepwnam(pw) ? WINBINDD_OK : WINBINDD_ERROR );
1155}
1156
1157/**********************************************************************
1158 Delete a user from the winbindd account tdb.
1159**********************************************************************/
1160
1161enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state)
1162{
1163	WINBINDD_PW *pw;
1164	char *user;
1165
1166	if ( !state->privileged ) {
1167		DEBUG(2, ("winbindd_delete_user: non-privileged access denied!\n"));
1168		return WINBINDD_ERROR;
1169	}
1170
1171	/* Ensure null termination */
1172	state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
1173	user = state->request.data.acct_mgt.username;
1174
1175	DEBUG(3, ("[%5lu]:  delete_user: %s\n", (unsigned long)state->pid, user));
1176
1177	/* make sure it is a valid user */
1178
1179	if ( !(pw = wb_getpwnam( user )) ) {
1180		DEBUG(4,("winbindd_delete_user: Cannot delete a non-existent user\n"));
1181		return WINBINDD_ERROR;
1182	}
1183
1184	return ( wb_delete_user(pw) ? WINBINDD_OK : WINBINDD_ERROR );
1185}
1186
1187/**********************************************************************
1188 Delete a group from winbindd's account tdb.
1189**********************************************************************/
1190
1191enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
1192{
1193	WINBINDD_GR *grp;
1194	char *group;
1195	BOOL ret;
1196
1197	if ( !state->privileged ) {
1198		DEBUG(2, ("winbindd_delete_group: non-privileged access denied!\n"));
1199		return WINBINDD_ERROR;
1200	}
1201
1202	/* Ensure null termination */
1203	state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
1204	group = state->request.data.acct_mgt.groupname;
1205
1206	DEBUG(3, ("[%5lu]:  delete_group: %s\n", (unsigned long)state->pid, group));
1207
1208	/* make sure it is a valid group */
1209
1210	if ( !(grp = wb_getgrnam( group )) ) {
1211		DEBUG(4,("winbindd_delete_group: Cannot delete a non-existent group\n"));
1212		return WINBINDD_ERROR;
1213	}
1214
1215	ret = wb_delete_group(grp);
1216
1217	free_winbindd_gr( grp );
1218
1219	return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
1220}
1221
1222
1223
1224