Final piece of support needed to find iconv libraries on FreeBSD.
[ira/wip.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 "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 /*****************************************************************************
41  Initialise auto-account database. 
42 *****************************************************************************/
43
44 static BOOL winbindd_accountdb_init(void)
45 {
46         /* see if we've already opened the tdb */
47         
48         if ( account_tdb )
49                 return True;
50                 
51         /* Nope.  Try to open it */
52
53         if (!(account_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0, 
54                 TDB_DEFAULT, O_RDWR | O_CREAT, 0600))) 
55         {
56                 /* last chance -- maybe idmap has already opened it */
57                 if ( !(account_tdb = idmap_tdb_handle()) ) {
58
59                         DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
60                         return False;
61                 }
62         }
63         
64         /* yeah! */
65         
66         return True;   
67 }
68
69 /**********************************************************************
70  Convert a string in /etc/passwd format to a struct passwd* entry
71 **********************************************************************/
72
73 static WINBINDD_PW* string2passwd( char *string )
74 {
75         static WINBINDD_PW pw;
76         char *p, *str;
77         char *fields[NUM_PW_FIELDS];
78         int i;
79         
80         if ( !string )
81                 return NULL;
82         
83         ZERO_STRUCTP( &pw );
84         
85         DEBUG(10,("string2passwd: converting \"%s\"\n", string));
86         
87         ZERO_STRUCT( fields );
88         
89         for ( i=0, str=string; i<NUM_PW_FIELDS-1; i++ ) {
90                 if ( !(p = strchr( str, ':' )) ) {
91                         DEBUG(0,("string2passwd: parsing failure\n"));
92                         return NULL;
93                 }
94                 *p = '\0';
95                 if ( str )
96                         fields[i] = str;
97                 str = p + 1;
98         }
99         if ( str ) 
100                 fields[i] = str;
101         
102         /* copy fields */
103         
104         fstrcpy( pw.pw_name,   fields[0] );
105         fstrcpy( pw.pw_passwd, fields[1] );
106         pw.pw_uid = atoi(      fields[2] );
107         pw.pw_gid = atoi(      fields[3] );
108         fstrcpy( pw.pw_gecos,  fields[4] );
109         fstrcpy( pw.pw_dir,    fields[5] );
110         fstrcpy( pw.pw_shell,  fields[6] );
111         
112         
113         /* last minute sanity checks */
114         
115         if ( pw.pw_uid==0 || pw.pw_gid==0 ) {
116                 DEBUG(0,("string2passwd: Failure! uid==%d, gid==%d\n",
117                         pw.pw_uid, pw.pw_gid));
118                 return NULL;
119         }
120         
121         DEBUG(10,("string2passwd: Success\n"));
122
123         return &pw;
124 }
125
126 /**********************************************************************
127  Convert a struct passwd* to a string formatted for /etc/passwd
128 **********************************************************************/
129
130 static char* passwd2string( const WINBINDD_PW *pw )
131 {
132         static pstring string;
133         int ret;
134         
135         if ( !pw || !pw->pw_name )
136                 return NULL;
137         
138         DEBUG(10,("passwd2string: converting passwd struct for %s\n", 
139                 pw->pw_name));
140
141         ret = snprintf( string, sizeof(string), "%s:%s:%d:%d:%s:%s:%s",
142                 pw->pw_name, 
143                 pw->pw_passwd ? pw->pw_passwd : "x",
144                 pw->pw_uid,
145                 pw->pw_gid,
146                 pw->pw_gecos,
147                 pw->pw_dir,
148                 pw->pw_shell );
149                 
150         if ( ret < 0 ) {
151                 DEBUG(0,("passwd2string: snprintf() failed!\n"));
152                 return NULL;
153         }
154                 
155         return string;  
156 }
157
158 /**********************************************************************
159  Convert a string in /etc/group format to a struct group* entry
160 **********************************************************************/
161
162 static WINBINDD_GR* string2group( char *string )
163 {
164         static WINBINDD_GR grp;
165         char *p, *str;
166         char *fields[NUM_GRP_FIELDS];
167         int i;
168         char **gr_members = NULL;
169         int num_gr_members = 0;
170         
171         if ( !string )
172                 return NULL;
173                 
174         ZERO_STRUCTP( &grp );
175         
176         DEBUG(10,("string2group: converting \"%s\"\n", string));
177         
178         ZERO_STRUCT( fields );
179         
180         for ( i=0, str=string; i<NUM_GRP_FIELDS-1; i++ ) {
181                 if ( !(p = strchr( str, ':' )) ) {
182                         DEBUG(0,("string2group: parsing failure\n"));
183                         return NULL;
184                 }
185                 *p = '\0';
186                 if ( str )
187                         fields[i] = str;
188                 str = p + 1;
189         }
190         
191         /* group members */
192         
193         if ( *str ) {
194                 /* we already know we have a non-empty string */
195
196                 num_gr_members = count_chars(str, ',') + 1;
197                 
198                 /* if there was at least one comma, then there 
199                    are n+1 members */
200                 if ( num_gr_members ) {
201                         fstring buffer;
202                         
203                         gr_members = (char**)smb_xmalloc(sizeof(char*)*num_gr_members+1);
204                         
205                         i = 0;
206                         while ( next_token(&str, buffer, ",", sizeof(buffer)) && i<num_gr_members ) {
207                                 gr_members[i++] = smb_xstrdup(buffer);
208                         }
209
210                         gr_members[i]   = NULL;
211                 }
212         }
213
214         
215         /* copy fields */
216         
217         fstrcpy( grp.gr_name,   fields[0] );
218         fstrcpy( grp.gr_passwd, fields[1] );
219         grp.gr_gid = atoi(      fields[2] );
220         
221         grp.num_gr_mem = num_gr_members;
222         grp.gr_mem     = gr_members;
223         
224         /* last minute sanity checks */
225         
226         if ( grp.gr_gid == 0 ) {
227                 DEBUG(0,("string2group: Failure! gid==%d\n", grp.gr_gid));
228                 SAFE_FREE( gr_members );
229                 return NULL;
230         }
231         
232         DEBUG(10,("string2group: Success\n"));
233
234         return &grp;
235 }
236
237 /**********************************************************************
238  Convert a struct group* to a string formatted for /etc/group
239 **********************************************************************/
240
241 static char* group2string( const WINBINDD_GR *grp )
242 {
243         static pstring string;
244         int ret;
245         char *member, *gr_mem_str;
246         int num_members;
247         int i, size;
248         
249         if ( !grp || !grp->gr_name )
250                 return NULL;
251         
252         DEBUG(10,("group2string: converting passwd struct for %s\n", 
253                 grp->gr_name));
254         
255         if ( grp->num_gr_mem ) {
256                 int idx = 0;
257
258                 member = grp->gr_mem[0];
259                 size = 0;
260                 num_members = 0;
261
262                 while ( member ) {
263                         size += strlen(member) + 1;
264                         num_members++;
265                         member = grp->gr_mem[num_members];
266                 }
267                 
268                 gr_mem_str = smb_xmalloc(size);
269         
270                 for ( i=0; i<num_members; i++ ) {
271                         snprintf( &gr_mem_str[idx], size-idx, "%s,", grp->gr_mem[i] );
272                         idx += strlen(grp->gr_mem[i]) + 1;
273                 }
274                 /* add trailing NULL (also removes trailing ',' */
275                 gr_mem_str[size-1] = '\0';
276         }
277         else {
278                 /* no members */
279                 gr_mem_str = smb_xmalloc(sizeof(fstring));
280                 fstrcpy( gr_mem_str, "" );
281         }
282
283         ret = snprintf( string, sizeof(string)-1, "%s:%s:%d:%s",
284                 grp->gr_name, 
285                 grp->gr_passwd ? grp->gr_passwd : "*",
286                 grp->gr_gid,
287                 gr_mem_str );
288                 
289         SAFE_FREE( gr_mem_str );
290                 
291         if ( ret < 0 ) {
292                 DEBUG(0,("group2string: snprintf() failed!\n"));
293                 return NULL;
294         }
295                 
296         return string;  
297 }
298
299 /**********************************************************************
300 **********************************************************************/
301
302 static char* acct_userkey_byname( const char *name )
303 {
304         static fstring key;
305         
306         snprintf( key, sizeof(key), "%s/NAME/%s", WBKEY_PASSWD, name );
307         
308         return key;             
309 }
310
311 /**********************************************************************
312 **********************************************************************/
313
314 static char* acct_userkey_byuid( uid_t uid )
315 {
316         static fstring key;
317         
318         snprintf( key, sizeof(key), "%s/UID/%d", WBKEY_PASSWD, uid );
319         
320         return key;             
321 }
322
323 /**********************************************************************
324 **********************************************************************/
325
326 static char* acct_groupkey_byname( const char *name )
327 {
328         static fstring key;
329         
330         snprintf( key, sizeof(key), "%s/NAME/%s", WBKEY_GROUP, name );
331         
332         return key;             
333 }
334
335 /**********************************************************************
336 **********************************************************************/
337
338 static char* acct_groupkey_bygid( gid_t gid )
339 {
340         static fstring key;
341         
342         snprintf( key, sizeof(key), "%s/GID/%d", WBKEY_GROUP, gid );
343         
344         return key;             
345 }
346
347 /**********************************************************************
348 **********************************************************************/
349
350 WINBINDD_PW* wb_getpwnam( const char * name )
351 {
352         char *keystr;
353         TDB_DATA data;
354         static WINBINDD_PW *pw;
355         
356         if ( !account_tdb && !winbindd_accountdb_init() ) {
357                 DEBUG(0,("wb_getpwnam: Failed to open winbindd account db\n"));
358                 return NULL;
359         }
360                 
361         
362         keystr = acct_userkey_byname( name );
363         
364         data = tdb_fetch_by_string( account_tdb, keystr );
365         
366         pw = NULL;
367         
368         if ( data.dptr ) {
369                 pw = string2passwd( data.dptr );
370                 SAFE_FREE( data.dptr );
371         }
372                 
373         DEBUG(5,("wb_getpwnam: %s user (%s)\n", 
374                 (pw ? "Found" : "Did not find"), name ));
375         
376         return pw;
377 }
378
379 /**********************************************************************
380 **********************************************************************/
381
382 WINBINDD_PW* wb_getpwuid( const uid_t uid )
383 {
384         char *keystr;
385         TDB_DATA data;
386         static WINBINDD_PW *pw;
387         
388         if ( !account_tdb && !winbindd_accountdb_init() ) {
389                 DEBUG(0,("wb_getpwuid: Failed to open winbindd account db\n"));
390                 return NULL;
391         }
392         
393         data = tdb_fetch_by_string( account_tdb, acct_userkey_byuid(uid) );
394         if ( !data.dptr ) {
395                 DEBUG(4,("wb_getpwuid: failed to locate uid == %d\n", uid));
396                 return NULL;
397         }
398         keystr = acct_userkey_byname( data.dptr );
399
400         SAFE_FREE( data.dptr );
401         
402         data = tdb_fetch_by_string( account_tdb, keystr );
403         
404         pw = NULL;
405         
406         if ( data.dptr ) {
407                 pw = string2passwd( data.dptr );
408                 SAFE_FREE( data.dptr );
409         }
410
411         DEBUG(5,("wb_getpwuid: %s user (uid == %d)\n", 
412                 (pw ? "Found" : "Did not find"), uid ));
413         
414         return pw;
415 }
416
417 /**********************************************************************
418 **********************************************************************/
419
420 BOOL wb_storepwnam( const WINBINDD_PW *pw )
421 {
422         char *namekey, *uidkey;
423         TDB_DATA data;
424         char *str;
425         int ret = 0;
426         fstring username;
427
428         if ( !account_tdb && !winbindd_accountdb_init() ) {
429                 DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
430                 return False;
431         }
432
433         namekey = acct_userkey_byname( pw->pw_name );
434         
435         /* lock the main entry first */
436         
437         if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
438                 DEBUG(0,("wb_storepwnam: Failed to lock %s\n", namekey));
439                 return False;
440         }
441         
442         str = passwd2string( pw );
443
444         data.dptr = str;
445         data.dsize = strlen(str) + 1;   
446
447         if ( (tdb_store_by_string(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
448                 DEBUG(0,("wb_storepwnam: Failed to store \"%s\"\n", str));
449                 ret = -1;
450                 goto done;
451         }
452         
453         /* store the uid index */
454         
455         uidkey = acct_userkey_byuid(pw->pw_uid);
456         
457         fstrcpy( username, pw->pw_name );
458         data.dptr = username;
459         data.dsize = strlen(username) + 1;
460         
461         if ( (tdb_store_by_string(account_tdb, uidkey, data, TDB_REPLACE)) == -1 ) {
462                 DEBUG(0,("wb_storepwnam: Failed to store uid key \"%s\"\n", str));
463                 tdb_delete_by_string(account_tdb, namekey);
464                 ret = -1;
465                 goto done;
466         }               
467         
468         DEBUG(10,("wb_storepwnam: Success -> \"%s\"\n", str));
469
470 done:   
471         tdb_unlock_bystring( account_tdb, namekey );
472         
473         return ( ret == 0 );
474 }
475
476 /**********************************************************************
477 **********************************************************************/
478
479 WINBINDD_GR* wb_getgrnam( const char * name )
480 {
481         char *keystr;
482         TDB_DATA data;
483         static WINBINDD_GR *grp;
484         
485         if ( !account_tdb && !winbindd_accountdb_init() ) {
486                 DEBUG(0,("wb_getgrnam: Failed to open winbindd account db\n"));
487                 return NULL;
488         }
489                 
490         
491         keystr = acct_groupkey_byname( name );
492         
493         data = tdb_fetch_by_string( account_tdb, keystr );
494         
495         grp = NULL;
496         
497         if ( data.dptr ) {
498                 grp = string2group( data.dptr );
499                 SAFE_FREE( data.dptr );
500         }
501                 
502         DEBUG(5,("wb_getgrnam: %s group (%s)\n", 
503                 (grp ? "Found" : "Did not find"), name ));
504         
505         return grp;
506 }
507
508 /**********************************************************************
509 **********************************************************************/
510
511 WINBINDD_GR* wb_getgrgid( gid_t gid )
512 {
513         char *keystr;
514         TDB_DATA data;
515         static WINBINDD_GR *grp;
516         
517         if ( !account_tdb && !winbindd_accountdb_init() ) {
518                 DEBUG(0,("wb_getgrgid: Failed to open winbindd account db\n"));
519                 return NULL;
520         }
521         
522         data = tdb_fetch_by_string( account_tdb, acct_groupkey_bygid(gid) );
523         if ( !data.dptr ) {
524                 DEBUG(4,("wb_getgrgid: failed to locate gid == %d\n", gid));
525                 return NULL;
526         }
527         keystr = acct_groupkey_byname( data.dptr );
528
529         SAFE_FREE( data.dptr );
530         
531         data = tdb_fetch_by_string( account_tdb, keystr );
532         
533         grp = NULL;
534         
535         if ( data.dptr ) {
536                 grp = string2group( data.dptr );
537                 SAFE_FREE( data.dptr );
538         }
539
540         DEBUG(5,("wb_getgrgid: %s group (gid == %d)\n", 
541                 (grp ? "Found" : "Did not find"), gid ));
542         
543         return grp;
544 }
545
546 /**********************************************************************
547 **********************************************************************/
548
549 BOOL wb_storegrnam( const WINBINDD_GR *grp )
550 {
551         char *namekey, *gidkey;
552         TDB_DATA data;
553         char *str;
554         int ret = 0;
555         fstring groupname;
556
557         if ( !account_tdb && !winbindd_accountdb_init() ) {
558                 DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
559                 return False;
560         }
561
562         namekey = acct_groupkey_byname( grp->gr_name );
563         
564         /* lock the main entry first */
565         
566         if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
567                 DEBUG(0,("wb_storegrnam: Failed to lock %s\n", namekey));
568                 return False;
569         }
570         
571         str = group2string( grp );
572
573         data.dptr = str;
574         data.dsize = strlen(str) + 1;   
575
576         if ( (tdb_store_by_string(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
577                 DEBUG(0,("wb_storegrnam: Failed to store \"%s\"\n", str));
578                 ret = -1;
579                 goto done;
580         }
581         
582         /* store the gid index */
583         
584         gidkey = acct_groupkey_bygid(grp->gr_gid);
585         
586         fstrcpy( groupname, grp->gr_name );
587         data.dptr = groupname;
588         data.dsize = strlen(groupname) + 1;
589         
590         if ( (tdb_store_by_string(account_tdb, gidkey, data, TDB_REPLACE)) == -1 ) {
591                 DEBUG(0,("wb_storegrnam: Failed to store gid key \"%s\"\n", str));
592                 tdb_delete_by_string(account_tdb, namekey);
593                 ret = -1;
594                 goto done;
595         }
596         
597         DEBUG(10,("wb_storegrnam: Success -> \"%s\"\n", str));
598
599 done:   
600         tdb_unlock_bystring( account_tdb, namekey );
601         
602         return ( ret == 0 );
603 }
604
605 /**********************************************************************
606 **********************************************************************/
607
608 static BOOL wb_addgrpmember( WINBINDD_GR *grp, const char *user )
609 {
610         int i;
611         char **members;
612         
613         if ( !grp || !user )
614                 return False;
615         
616         for ( i=0; i<grp->num_gr_mem; i++ ) {
617                 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 )
618                         return True;
619         }
620         
621         /* add one new slot and keep an extra for the terminating NULL */
622         members = Realloc( grp->gr_mem, (grp->num_gr_mem+2)*sizeof(char*) );
623         if ( !members )
624                 return False;
625                 
626         grp->gr_mem = members;
627         grp->gr_mem[grp->num_gr_mem++] = smb_xstrdup(user);
628         grp->gr_mem[grp->num_gr_mem]   = NULL;
629                 
630         return True;
631 }
632
633 /**********************************************************************
634 **********************************************************************/
635
636 static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user )
637 {
638         int i;
639         BOOL found = False;
640         
641         if ( !grp || !user )
642                 return False;
643         
644         for ( i=0; i<grp->num_gr_mem && !found; i++ ) {
645                 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 ) 
646                         found = True;
647         }
648         
649         if ( !found ) 
650                 return False;
651
652         memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) );
653         grp->num_gr_mem--;
654                                 
655         return True;
656 }
657
658 /**********************************************************************
659 **********************************************************************/
660
661 static void free_winbindd_gr( WINBINDD_GR *grp )
662 {
663         int i;
664
665         if ( !grp )
666                 return;
667                 
668         for ( i=0; i<grp->num_gr_mem; i++ )
669                 SAFE_FREE( grp->gr_mem[i] );
670
671         SAFE_FREE( grp->gr_mem );
672         
673         return;
674 }
675
676 /**********************************************************************
677  Create a new "UNIX" user for the system given a username
678 **********************************************************************/
679
680 enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
681 {
682         char *user, *group;
683         unid_t id;
684         WINBINDD_PW pw;
685         WINBINDD_GR *wb_grp;
686         struct group *unix_grp;
687         gid_t primary_gid;
688         
689         if ( !state->privileged ) {
690                 DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n"));
691                 return WINBINDD_ERROR;
692         }
693         
694         /* Ensure null termination */
695         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
696         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
697         
698         user  = state->request.data.acct_mgt.username;
699         group = state->request.data.acct_mgt.groupname;
700         
701         DEBUG(3, ("[%5d]: create_user user=>(%s), group=>(%s)\n", 
702                 state->pid, user, group));
703                 
704         if ( !*group )
705                 group = lp_template_primary_group();
706                 
707         /* validate the primary group
708            1) lookup in local tdb first
709            2) call getgrnam() as a last resort */
710            
711         if ( (wb_grp=wb_getgrnam(group)) != NULL ) {
712                 primary_gid = wb_grp->gr_gid;
713                 free_winbindd_gr( wb_grp );
714         }
715         else if ( (unix_grp=sys_getgrnam(group)) != NULL ) {
716                 primary_gid = unix_grp->gr_gid; 
717         }
718         else {
719                 DEBUG(2,("winbindd_create_user: Cannot validate gid for group (%s)\n", group));
720                 return WINBINDD_ERROR;
721         }
722
723         /* get a new uid */
724         
725         if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_USERID)) ) {
726                 DEBUG(0,("winbindd_create_user: idmap_allocate_id() failed!\n"));
727                 return WINBINDD_ERROR;
728         }
729         
730         /* The substitution of %U and %D in the 'template homedir' is done
731            by lp_string() calling standard_sub_basic(). */
732
733         fstrcpy( current_user_info.smb_name, user );
734         sub_set_smb_name( user );
735         fstrcpy( current_user_info.domain, get_global_sam_name() );
736         
737         /* fill in the passwd struct */
738                 
739         fstrcpy( pw.pw_name,   user );
740         fstrcpy( pw.pw_passwd, "x" );
741         fstrcpy( pw.pw_gecos,  user);
742         fstrcpy( pw.pw_dir,    lp_template_homedir() );
743         fstrcpy( pw.pw_shell,  lp_template_shell() );
744         
745         pw.pw_uid = id.uid;
746         pw.pw_gid = primary_gid;
747
748         return ( wb_storepwnam(&pw) ? WINBINDD_OK : WINBINDD_ERROR );
749 }
750
751 /**********************************************************************
752  Create a new "UNIX" group for the system given a username
753 **********************************************************************/
754
755 enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
756 {
757         char *group;
758         unid_t id;
759         WINBINDD_GR grp;
760         
761         if ( !state->privileged ) {
762                 DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n"));
763                 return WINBINDD_ERROR;
764         }
765         
766         /* Ensure null termination */
767         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
768         group = state->request.data.acct_mgt.groupname;
769         
770         DEBUG(3, ("[%5d]: create_group (%s)\n", state->pid, group));
771         
772         /* get a new uid */
773         
774         if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_GROUPID)) ) {
775                 DEBUG(0,("winbindd_create_group: idmap_allocate_id() failed!\n"));
776                 return WINBINDD_ERROR;
777         }
778         
779         /* fill in the group struct */
780                 
781         fstrcpy( grp.gr_name,   group );
782         fstrcpy( grp.gr_passwd, "*" );
783         
784         grp.gr_gid      = id.gid;
785         grp.gr_mem      = NULL; /* start with no members */
786         grp.num_gr_mem  = 0;
787
788         return ( wb_storegrnam(&grp) ? WINBINDD_OK : WINBINDD_ERROR );
789 }
790
791 /**********************************************************************
792  Add a user to the membership for a group.
793 **********************************************************************/
794
795 enum winbindd_result winbindd_add_user_to_group(struct winbindd_cli_state *state)
796 {
797         WINBINDD_PW *pw;
798         WINBINDD_GR *grp;
799         char *user, *group;
800         BOOL ret;
801         
802         if ( !state->privileged ) {
803                 DEBUG(2, ("winbindd_add_user_to_group: non-privileged access denied!\n"));
804                 return WINBINDD_ERROR;
805         }
806         
807         /* Ensure null termination */
808         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
809         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
810         group = state->request.data.acct_mgt.groupname;
811         user = state->request.data.acct_mgt.username;
812         
813         DEBUG(3, ("[%5d]:  add_user_to_group add %s to %s\n", state->pid, 
814                 user, group));
815         
816         /* make sure it is a valid user */
817         
818         if ( !(pw = wb_getpwnam( user )) ) {
819                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
820                 return WINBINDD_ERROR;
821         }
822         
823         /* make sure it is a valid group */
824         
825         if ( !(grp = wb_getgrnam( group )) ) {
826                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
827                 return WINBINDD_ERROR;  
828         }
829         
830         if ( !wb_addgrpmember( grp, user ) )
831                 return WINBINDD_ERROR;
832                 
833         ret = wb_storegrnam(grp);
834         
835         free_winbindd_gr( grp );
836         
837         return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
838 }
839
840 /**********************************************************************
841  Remove a user from the membership of a group
842 **********************************************************************/
843
844 enum winbindd_result winbindd_remove_user_from_group(struct winbindd_cli_state *state)
845 {
846         WINBINDD_GR *grp;
847         char *user, *group;
848         BOOL ret;
849
850         if ( !state->privileged ) {
851                 DEBUG(2, ("winbindd_remove_user_from_group: non-privileged access denied!\n"));
852                 return WINBINDD_ERROR;
853         }
854         
855         /* Ensure null termination */
856         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
857         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
858         group = state->request.data.acct_mgt.groupname;
859         user = state->request.data.acct_mgt.username;
860         
861         DEBUG(3, ("[%5d]:  remove_user_to_group delete %s from %s\n", state->pid, 
862                 user, group));
863         
864         /* don't worry about checking the username since we're removing it anyways */
865         
866         /* make sure it is a valid group */
867         
868         if ( !(grp = wb_getgrnam( group )) ) {
869                 DEBUG(4,("winbindd_remove_user_to_group: Cannot remove a user to a non-extistent group\n"));
870                 return WINBINDD_ERROR;  
871         }
872         
873         if ( !wb_delgrpmember( grp, user ) )
874                 return WINBINDD_ERROR;
875                 
876         ret = wb_storegrnam(grp);
877         
878         free_winbindd_gr( grp );
879         
880         return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
881 }
882
883 /**********************************************************************
884  Set the primary group membership of a user
885 **********************************************************************/
886
887 enum winbindd_result winbindd_set_user_primary_group(struct winbindd_cli_state *state)
888 {
889         WINBINDD_PW *pw;
890         WINBINDD_GR *grp;
891         char *user, *group;
892
893         if ( !state->privileged ) {
894                 DEBUG(2, ("winbindd_set_user_primary_group: non-privileged access denied!\n"));
895                 return WINBINDD_ERROR;
896         }
897         
898         /* Ensure null termination */
899         state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
900         state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
901         group = state->request.data.acct_mgt.groupname;
902         user = state->request.data.acct_mgt.username;
903         
904         DEBUG(3, ("[%5d]:  set_user_primary_group group %s for user %s\n", state->pid, 
905                 group, user));
906         
907         /* make sure it is a valid user */
908         
909         if ( !(pw = wb_getpwnam( user )) ) {
910                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
911                 return WINBINDD_ERROR;
912         }
913         
914         /* make sure it is a valid group */
915         
916         if ( !(grp = wb_getgrnam( group )) ) {
917                 DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
918                 return WINBINDD_ERROR;  
919         }
920         
921         pw->pw_gid = grp->gr_gid;
922
923         free_winbindd_gr( grp );
924                 
925         return ( wb_storepwnam(pw) ? WINBINDD_OK : WINBINDD_ERROR );
926 }
927
928 /**********************************************************************
929  Set the primary group membership of a user
930 **********************************************************************/
931
932 enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state)
933 {
934         return WINBINDD_ERROR;
935 }
936
937 /**********************************************************************
938  Set the primary group membership of a user
939 **********************************************************************/
940
941 enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
942 {
943         return WINBINDD_ERROR;
944 }
945
946