r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
[tprouty/samba.git] / source / nsswitch / winbindd_acct.c
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
37 static TDB_CONTEXT *account_tdb;
38
39 extern userdom_struct current_user_info;
40
41 struct _check_primary_grp {
42         gid_t   gid;
43         BOOL    found;
44 };
45
46 /**********************************************************************
47 **********************************************************************/
48
49 static 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
68 static 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
92 static 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
149 static 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
181 static 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
260 static 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
321 static 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
333 static 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
345 static 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
357 static 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
369 WINBINDD_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
401 WINBINDD_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
439 static 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
489 done:   
490         tdb_unlock_bystring( account_tdb, namekey );
491         
492         return ( ret == 0 );
493 }
494
495 /**********************************************************************
496 **********************************************************************/
497
498 WINBINDD_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
530 WINBINDD_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
569 static 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
619 done:   
620         tdb_unlock_bystring( account_tdb, namekey );
621         
622         return ( ret == 0 );
623 }
624
625 /**********************************************************************
626 **********************************************************************/
627
628 static 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
656 static 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
694 static 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
736 static 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
773 static 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
807 static 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
856 enum 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
959 enum 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
1024 enum 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
1073 enum 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
1116 enum 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
1161 enum 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
1191 enum 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