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