34c7238b846f78f2bb2aced5662e50db5330e224
[samba.git] / source3 / 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 = (char**)smb_xmalloc(sizeof(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(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(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 = Realloc( grp->gr_mem, (grp->num_gr_mem+2)*sizeof(char*) );
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 && !found; i++ ) {
665                 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 ) 
666                         found = True;
667         }
668         
669         if ( !found ) 
670                 return False;
671
672         /* still some remaining members */
673
674         if ( grp->num_gr_mem > 1 ) {
675                 memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) );
676                 grp->num_gr_mem--;
677         }
678         else {  /* last one */
679                 free_winbindd_gr( grp );
680                 grp->gr_mem = NULL;
681                 grp->num_gr_mem = 0;
682         }
683                                 
684         return True;
685 }
686
687 /**********************************************************************
688 **********************************************************************/
689
690 static int cleangroups_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
691                        void *state)
692 {
693         int len;
694         fstring key;
695         char *name = (char*)state;
696         
697         fstr_sprintf( key, "%s/NAME", WBKEY_GROUP );
698         len = strlen(key);
699         
700         /* if this is a group entry then, check the members */
701         
702         if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) {
703                 WINBINDD_GR *grp;
704                 
705                 if ( !(grp = string2group( dbuf.dptr )) ) {
706                         DEBUG(0,("cleangroups_traverse_fn: Failure to parse [%s]\n",
707                                 dbuf.dptr));
708                         return 0;
709                 }
710                 
711                 /* just try to delete the user and rely on wb_delgrpmember()
712                    to tell you whether or not the group changed.  This is more 
713                    effecient than testing group membership first since the 
714                    checks for deleting a user from a group is essentially the 
715                    same as checking if he/she is a member */
716                    
717                 if ( wb_delgrpmember( grp, name ) ) {
718                         DEBUG(10,("cleanupgroups_traverse_fn: Removed user (%s) from group (%s)\n",
719                                 name, grp->gr_name));
720                         wb_storegrnam( grp );
721                 }
722                 
723                 free_winbindd_gr( grp );
724         }
725
726         return 0;
727 }
728
729 /**********************************************************************
730 **********************************************************************/
731
732 static BOOL wb_delete_user( WINBINDD_PW *pw)
733 {
734         char *namekey;
735         char *uidkey;
736         
737         if ( !account_tdb && !winbindd_accountdb_init() ) {
738                 DEBUG(0,("wb_delete_user: Failed to open winbindd account db\n"));
739                 return False;
740         }
741
742         namekey = acct_userkey_byname( pw->pw_name );
743         
744         /* lock the main entry first */
745         
746         if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
747                 DEBUG(0,("wb_delete_user: Failed to lock %s\n", namekey));
748                 return False;
749         }
750         
751         /* remove user from all groups */
752         
753         tdb_traverse(account_tdb, cleangroups_traverse_fn, (void *)pw->pw_name);
754         
755         /* remove the user */
756         uidkey = acct_userkey_byuid( pw->pw_uid );
757         
758         tdb_delete_bystring( account_tdb, namekey );
759         tdb_delete_bystring( account_tdb, uidkey );
760         
761         tdb_unlock_bystring( account_tdb, namekey );
762         
763         return True;
764 }
765
766 /**********************************************************************
767 **********************************************************************/
768
769 static int isprimarygroup_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, 
770                                       TDB_DATA dbuf, void *params)
771 {
772         int len;
773         fstring key;
774         struct _check_primary_grp *check = (struct _check_primary_grp*)params;
775         
776         fstr_sprintf( key, "%s/NAME", WBKEY_PASSWD );
777         len = strlen(key);
778         
779         /* if this is a group entry then, check the members */
780         
781         if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) {
782                 WINBINDD_PW *pw;;
783                 
784                 if ( !(pw = string2passwd( dbuf.dptr )) ) {
785                         DEBUG(0,("isprimarygroup_traverse_fn: Failure to parse [%s]\n",
786                                 dbuf.dptr));
787                         return 0;
788                 }
789                 
790                 if ( check->gid == pw->pw_gid ) {
791                         check->found = True;
792                         return 1;
793                 }
794         }
795
796         return 0;
797 }
798
799
800 /**********************************************************************
801 **********************************************************************/
802
803 static BOOL wb_delete_group( WINBINDD_GR *grp )
804 {
805         struct _check_primary_grp check;
806         char *namekey;
807         char *gidkey;
808         
809         if ( !account_tdb && !winbindd_accountdb_init() ) {
810                 DEBUG(0,("wb_delete_group: Failed to open winbindd account db\n"));
811                 return False;
812         }
813         
814         /* lock the main entry first */
815         
816         namekey = acct_groupkey_byname( grp->gr_name ); 
817         if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
818                 DEBUG(0,("wb_delete_group: Failed to lock %s\n", namekey));
819                 return False;
820         }
821         
822         /* is this group the primary group for any user?  If 
823            so deny delete */
824            
825         check.found = False;    
826         tdb_traverse(account_tdb, isprimarygroup_traverse_fn, (void *)&check);
827         
828         if ( check.found ) {
829                 DEBUG(4,("wb_delete_group: Cannot delete group (%s) since it "
830                         "is the primary group for some users\n", grp->gr_name));
831                 return False;
832         }
833         
834         /* We're clear.  Delete the group */
835         
836         DEBUG(5,("wb_delete_group: Removing group (%s)\n", grp->gr_name));
837         
838         gidkey = acct_groupkey_bygid( grp->gr_gid );
839         
840         tdb_delete_bystring( account_tdb, namekey );
841         tdb_delete_bystring( account_tdb, gidkey );
842         
843         tdb_unlock_bystring( account_tdb, namekey );
844         
845         return True;
846 }
847
848 /**********************************************************************
849  Create a new "UNIX" user for the system given a username
850 **********************************************************************/
851
852 enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
853 {
854         char *user, *group;
855         unid_t id;
856         WINBINDD_PW pw, *pw_check;
857         WINBINDD_GR *wb_grp;
858         struct group *unix_grp;
859         gid_t primary_gid;
860         uint32 flags = state->request.flags;
861         uint32 rid;
862         
863         if ( !state->privileged ) {
864                 DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n"));
865                 return WINBINDD_ERROR;
866         }
867         
868         /* Ensure null termination */
869         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
870         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
871         
872         user  = state->request.data.acct_mgt.username;
873         group = state->request.data.acct_mgt.groupname;
874         
875         DEBUG(3, ("[%5lu]: create_user: user=>(%s), group=>(%s)\n", 
876                 (unsigned long)state->pid, user, group));
877
878         if ( (pw_check=wb_getpwnam(user)) != NULL ) {
879                 DEBUG(0,("winbindd_create_user: Refusing to create user that already exists (%s)\n", 
880                         user));
881                 return WINBINDD_ERROR;
882         }
883
884                 
885         if ( !*group )
886                 group = lp_template_primary_group();
887                 
888         /* validate the primary group
889            1) lookup in local tdb first
890            2) call getgrnam() as a last resort */
891            
892         if ( (wb_grp=wb_getgrnam(group)) != NULL ) {
893                 primary_gid = wb_grp->gr_gid;
894                 free_winbindd_gr( wb_grp );
895         }
896         else if ( (unix_grp=sys_getgrnam(group)) != NULL ) {
897                 primary_gid = unix_grp->gr_gid; 
898         }
899         else {
900                 DEBUG(2,("winbindd_create_user: Cannot validate gid for group (%s)\n", group));
901                 return WINBINDD_ERROR;
902         }
903
904         /* get a new uid */
905         
906         if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_USERID)) ) {
907                 DEBUG(0,("winbindd_create_user: idmap_allocate_id() failed!\n"));
908                 return WINBINDD_ERROR;
909         }
910         
911         /* The substitution of %U and %D in the 'template homedir' is done
912            by lp_string() calling standard_sub_basic(). */
913
914         fstrcpy( current_user_info.smb_name, user );
915         sub_set_smb_name( user );
916         fstrcpy( current_user_info.domain, get_global_sam_name() );
917         
918         /* fill in the passwd struct */
919                 
920         fstrcpy( pw.pw_name,   user );
921         fstrcpy( pw.pw_passwd, "x" );
922         fstrcpy( pw.pw_gecos,  user);
923         fstrcpy( pw.pw_dir,    lp_template_homedir() );
924         fstrcpy( pw.pw_shell,  lp_template_shell() );
925         
926         pw.pw_uid = id.uid;
927         pw.pw_gid = primary_gid;
928         
929         /* store the new entry */
930         
931         if ( !wb_storepwnam(&pw) )
932                 return WINBINDD_ERROR;
933                 
934         /* do we need a new RID? */
935         
936         if ( flags & WBFLAG_ALLOCATE_RID ) {
937                 if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, USER_RID_TYPE)) ) {
938                         DEBUG(0,("winbindd_create_user: RID allocation failure!  Cannot create user (%s)\n",
939                                 user));
940                         wb_delete_user( &pw );
941                         
942                         return WINBINDD_ERROR;
943                 }
944                 
945                 state->response.data.rid = rid;
946         }
947
948         return WINBINDD_OK;
949 }
950
951 /**********************************************************************
952  Create a new "UNIX" group for the system given a username
953 **********************************************************************/
954
955 enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
956 {
957         char *group;
958         unid_t id;
959         WINBINDD_GR grp, *grp_check;
960         uint32 flags = state->request.flags;
961         uint32 rid;
962         
963         if ( !state->privileged ) {
964                 DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n"));
965                 return WINBINDD_ERROR;
966         }
967         
968         /* Ensure null termination */
969         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
970         group = state->request.data.acct_mgt.groupname;
971         
972         DEBUG(3, ("[%5lu]: create_group: (%s)\n", (unsigned long)state->pid, group));
973         
974         if ( (grp_check=wb_getgrnam(group)) != NULL ) {
975                 DEBUG(0,("winbindd_create_group: Refusing to create group that already exists (%s)\n", 
976                         group));
977                 return WINBINDD_ERROR;
978         }
979         
980         /* get a new gid */
981         
982         if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_GROUPID)) ) {
983                 DEBUG(0,("winbindd_create_group: idmap_allocate_id() failed!\n"));
984                 return WINBINDD_ERROR;
985         }
986         
987         /* fill in the group struct */
988                 
989         fstrcpy( grp.gr_name,   group );
990         fstrcpy( grp.gr_passwd, "*" );
991         
992         grp.gr_gid      = id.gid;
993         grp.gr_mem      = NULL; /* start with no members */
994         grp.num_gr_mem  = 0;
995         
996         if ( !wb_storegrnam(&grp) )
997                 return WINBINDD_ERROR;
998                 
999         /* do we need a new RID? */
1000         
1001         if ( flags & WBFLAG_ALLOCATE_RID ) {
1002                 if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, GROUP_RID_TYPE)) ) {
1003                         DEBUG(0,("winbindd_create_group: RID allocation failure!  Cannot create group (%s)\n",
1004                                 group));
1005                         wb_delete_group( &grp );
1006                         
1007                         return WINBINDD_ERROR;
1008                 }
1009                 
1010                 state->response.data.rid = rid;
1011         }
1012
1013         return WINBINDD_OK;
1014 }
1015
1016 /**********************************************************************
1017  Add a user to the membership for a group.
1018 **********************************************************************/
1019
1020 enum winbindd_result winbindd_add_user_to_group(struct winbindd_cli_state *state)
1021 {
1022         WINBINDD_PW *pw;
1023         WINBINDD_GR *grp;
1024         char *user, *group;
1025         BOOL ret;
1026         
1027         if ( !state->privileged ) {
1028                 DEBUG(2, ("winbindd_add_user_to_group: non-privileged access denied!\n"));
1029                 return WINBINDD_ERROR;
1030         }
1031         
1032         /* Ensure null termination */
1033         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
1034         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
1035         group = state->request.data.acct_mgt.groupname;
1036         user = state->request.data.acct_mgt.username;
1037         
1038         DEBUG(3, ("[%5lu]:  add_user_to_group: add %s to %s\n", (unsigned long)state->pid, 
1039                 user, group));
1040         
1041         /* make sure it is a valid user */
1042         
1043         if ( !(pw = wb_getpwnam( user )) ) {
1044                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
1045                 return WINBINDD_ERROR;
1046         }
1047         
1048         /* make sure it is a valid group */
1049         
1050         if ( !(grp = wb_getgrnam( group )) ) {
1051                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
1052                 return WINBINDD_ERROR;  
1053         }
1054         
1055         if ( !wb_addgrpmember( grp, user ) )
1056                 return WINBINDD_ERROR;
1057                 
1058         ret = wb_storegrnam(grp);
1059         
1060         free_winbindd_gr( grp );
1061         
1062         return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
1063 }
1064
1065 /**********************************************************************
1066  Remove a user from the membership of a group
1067 **********************************************************************/
1068
1069 enum winbindd_result winbindd_remove_user_from_group(struct winbindd_cli_state *state)
1070 {
1071         WINBINDD_GR *grp;
1072         char *user, *group;
1073         BOOL ret;
1074
1075         if ( !state->privileged ) {
1076                 DEBUG(2, ("winbindd_remove_user_from_group: non-privileged access denied!\n"));
1077                 return WINBINDD_ERROR;
1078         }
1079         
1080         /* Ensure null termination */
1081         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
1082         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
1083         group = state->request.data.acct_mgt.groupname;
1084         user = state->request.data.acct_mgt.username;
1085         
1086         DEBUG(3, ("[%5lu]:  remove_user_to_group: delete %s from %s\n", (unsigned long)state->pid, 
1087                 user, group));
1088         
1089         /* don't worry about checking the username since we're removing it anyways */
1090         
1091         /* make sure it is a valid group */
1092         
1093         if ( !(grp = wb_getgrnam( group )) ) {
1094                 DEBUG(4,("winbindd_remove_user_to_group: Cannot remove a user to a non-extistent group\n"));
1095                 return WINBINDD_ERROR;  
1096         }
1097         
1098         if ( !wb_delgrpmember( grp, user ) )
1099                 return WINBINDD_ERROR;
1100                 
1101         ret = wb_storegrnam(grp);
1102         
1103         free_winbindd_gr( grp );
1104         
1105         return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
1106 }
1107
1108 /**********************************************************************
1109  Set the primary group membership of a user
1110 **********************************************************************/
1111
1112 enum winbindd_result winbindd_set_user_primary_group(struct winbindd_cli_state *state)
1113 {
1114         WINBINDD_PW *pw;
1115         WINBINDD_GR *grp;
1116         char *user, *group;
1117
1118         if ( !state->privileged ) {
1119                 DEBUG(2, ("winbindd_set_user_primary_group: non-privileged access denied!\n"));
1120                 return WINBINDD_ERROR;
1121         }
1122         
1123         /* Ensure null termination */
1124         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
1125         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
1126         group = state->request.data.acct_mgt.groupname;
1127         user = state->request.data.acct_mgt.username;
1128         
1129         DEBUG(3, ("[%5lu]:  set_user_primary_group: group %s for user %s\n", 
1130                   (unsigned long)state->pid, group, user));
1131         
1132         /* make sure it is a valid user */
1133         
1134         if ( !(pw = wb_getpwnam( user )) ) {
1135                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
1136                 return WINBINDD_ERROR;
1137         }
1138         
1139         /* make sure it is a valid group */
1140         
1141         if ( !(grp = wb_getgrnam( group )) ) {
1142                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
1143                 return WINBINDD_ERROR;  
1144         }
1145         
1146         pw->pw_gid = grp->gr_gid;
1147
1148         free_winbindd_gr( grp );
1149                 
1150         return ( wb_storepwnam(pw) ? WINBINDD_OK : WINBINDD_ERROR );
1151 }
1152
1153 /**********************************************************************
1154  Delete a user from the winbindd account tdb.
1155 **********************************************************************/
1156
1157 enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state)
1158 {
1159         WINBINDD_PW *pw;
1160         char *user;
1161
1162         if ( !state->privileged ) {
1163                 DEBUG(2, ("winbindd_delete_user: non-privileged access denied!\n"));
1164                 return WINBINDD_ERROR;
1165         }
1166         
1167         /* Ensure null termination */
1168         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
1169         user = state->request.data.acct_mgt.username;
1170         
1171         DEBUG(3, ("[%5lu]:  delete_user: %s\n", (unsigned long)state->pid, user));
1172         
1173         /* make sure it is a valid user */
1174         
1175         if ( !(pw = wb_getpwnam( user )) ) {
1176                 DEBUG(4,("winbindd_delete_user: Cannot delete a non-existent user\n"));
1177                 return WINBINDD_ERROR;
1178         }
1179         
1180         return ( wb_delete_user(pw) ? WINBINDD_OK : WINBINDD_ERROR );
1181 }
1182
1183 /**********************************************************************
1184  Delete a group from winbindd's account tdb. 
1185 **********************************************************************/
1186
1187 enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
1188 {
1189         WINBINDD_GR *grp;
1190         char *group;
1191         BOOL ret;
1192
1193         if ( !state->privileged ) {
1194                 DEBUG(2, ("winbindd_delete_group: non-privileged access denied!\n"));
1195                 return WINBINDD_ERROR;
1196         }
1197         
1198         /* Ensure null termination */
1199         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';   
1200         group = state->request.data.acct_mgt.groupname;
1201         
1202         DEBUG(3, ("[%5lu]:  delete_group: %s\n", (unsigned long)state->pid, group));
1203         
1204         /* make sure it is a valid group */
1205         
1206         if ( !(grp = wb_getgrnam( group )) ) {
1207                 DEBUG(4,("winbindd_delete_group: Cannot delete a non-existent group\n"));
1208                 return WINBINDD_ERROR;
1209         }
1210         
1211         ret = wb_delete_group(grp);
1212         
1213         free_winbindd_gr( grp );
1214         
1215         return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
1216 }
1217
1218
1219