2 Unix SMB/CIFS implementation.
4 Winbind account management functions
6 Copyright (C) by Gerald (Jerry) Carter 2003
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.
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.
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.
26 #define DBGC_CLASS DBGC_WINBIND
28 #define WBKEY_PASSWD "WBA_PASSWD"
29 #define WBKEY_GROUP "WBA_GROUP"
31 #define NUM_PW_FIELDS 7
32 #define NUM_GRP_FIELDS 4
36 static TDB_CONTEXT *account_tdb;
38 extern userdom_struct current_user_info;
40 /*****************************************************************************
41 Initialise auto-account database.
42 *****************************************************************************/
44 static BOOL winbindd_accountdb_init(void)
46 /* see if we've already opened the tdb */
51 /* Nope. Try to open it */
53 if (!(account_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
54 TDB_DEFAULT, O_RDWR | O_CREAT, 0600)))
56 /* last chance -- maybe idmap has already opened it */
57 if ( !(account_tdb = idmap_tdb_handle()) ) {
59 DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
69 /**********************************************************************
70 Convert a string in /etc/passwd format to a struct passwd* entry
71 **********************************************************************/
73 static WINBINDD_PW* string2passwd( char *string )
75 static WINBINDD_PW pw;
77 char *fields[NUM_PW_FIELDS];
85 DEBUG(10,("string2passwd: converting \"%s\"\n", string));
87 ZERO_STRUCT( fields );
89 for ( i=0, str=string; i<NUM_PW_FIELDS-1; i++ ) {
90 if ( !(p = strchr( str, ':' )) ) {
91 DEBUG(0,("string2passwd: parsing failure\n"));
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] );
113 /* last minute sanity checks */
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));
121 DEBUG(10,("string2passwd: Success\n"));
126 /**********************************************************************
127 Convert a struct passwd* to a string formatted for /etc/passwd
128 **********************************************************************/
130 static char* passwd2string( const WINBINDD_PW *pw )
132 static pstring string;
135 if ( !pw || !pw->pw_name )
138 DEBUG(10,("passwd2string: converting passwd struct for %s\n",
141 ret = snprintf( string, sizeof(string), "%s:%s:%d:%d:%s:%s:%s",
143 pw->pw_passwd ? pw->pw_passwd : "x",
151 DEBUG(0,("passwd2string: snprintf() failed!\n"));
158 /**********************************************************************
159 Convert a string in /etc/group format to a struct group* entry
160 **********************************************************************/
162 static WINBINDD_GR* string2group( char *string )
164 static WINBINDD_GR grp;
166 char *fields[NUM_GRP_FIELDS];
168 char **gr_members = NULL;
169 int num_gr_members = 0;
174 ZERO_STRUCTP( &grp );
176 DEBUG(10,("string2group: converting \"%s\"\n", string));
178 ZERO_STRUCT( fields );
180 for ( i=0, str=string; i<NUM_GRP_FIELDS-1; i++ ) {
181 if ( !(p = strchr( str, ':' )) ) {
182 DEBUG(0,("string2group: parsing failure\n"));
194 /* we already know we have a non-empty string */
196 num_gr_members = count_chars(str, ',') + 1;
198 /* if there was at least one comma, then there
200 if ( num_gr_members ) {
203 gr_members = (char**)smb_xmalloc(sizeof(char*)*num_gr_members+1);
206 while ( next_token(&str, buffer, ",", sizeof(buffer)) && i<num_gr_members ) {
207 gr_members[i++] = smb_xstrdup(buffer);
210 gr_members[i] = NULL;
217 fstrcpy( grp.gr_name, fields[0] );
218 fstrcpy( grp.gr_passwd, fields[1] );
219 grp.gr_gid = atoi( fields[2] );
221 grp.num_gr_mem = num_gr_members;
222 grp.gr_mem = gr_members;
224 /* last minute sanity checks */
226 if ( grp.gr_gid == 0 ) {
227 DEBUG(0,("string2group: Failure! gid==%d\n", grp.gr_gid));
228 SAFE_FREE( gr_members );
232 DEBUG(10,("string2group: Success\n"));
237 /**********************************************************************
238 Convert a struct group* to a string formatted for /etc/group
239 **********************************************************************/
241 static char* group2string( const WINBINDD_GR *grp )
243 static pstring string;
245 char *member, *gr_mem_str;
249 if ( !grp || !grp->gr_name )
252 DEBUG(10,("group2string: converting passwd struct for %s\n",
255 if ( grp->num_gr_mem ) {
258 member = grp->gr_mem[0];
263 size += strlen(member) + 1;
265 member = grp->gr_mem[num_members];
268 gr_mem_str = smb_xmalloc(size);
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;
274 /* add trailing NULL (also removes trailing ',' */
275 gr_mem_str[size-1] = '\0';
279 gr_mem_str = smb_xmalloc(sizeof(fstring));
280 fstrcpy( gr_mem_str, "" );
283 ret = snprintf( string, sizeof(string)-1, "%s:%s:%d:%s",
285 grp->gr_passwd ? grp->gr_passwd : "*",
289 SAFE_FREE( gr_mem_str );
292 DEBUG(0,("group2string: snprintf() failed!\n"));
299 /**********************************************************************
300 **********************************************************************/
302 static char* acct_userkey_byname( const char *name )
306 snprintf( key, sizeof(key), "%s/NAME/%s", WBKEY_PASSWD, name );
311 /**********************************************************************
312 **********************************************************************/
314 static char* acct_userkey_byuid( uid_t uid )
318 snprintf( key, sizeof(key), "%s/UID/%d", WBKEY_PASSWD, uid );
323 /**********************************************************************
324 **********************************************************************/
326 static char* acct_groupkey_byname( const char *name )
330 snprintf( key, sizeof(key), "%s/NAME/%s", WBKEY_GROUP, name );
335 /**********************************************************************
336 **********************************************************************/
338 static char* acct_groupkey_bygid( gid_t gid )
342 snprintf( key, sizeof(key), "%s/GID/%d", WBKEY_GROUP, gid );
347 /**********************************************************************
348 **********************************************************************/
350 WINBINDD_PW* wb_getpwnam( const char * name )
354 static WINBINDD_PW *pw;
356 if ( !account_tdb && !winbindd_accountdb_init() ) {
357 DEBUG(0,("wb_getpwnam: Failed to open winbindd account db\n"));
362 keystr = acct_userkey_byname( name );
364 data = tdb_fetch_by_string( account_tdb, keystr );
369 pw = string2passwd( data.dptr );
370 SAFE_FREE( data.dptr );
373 DEBUG(5,("wb_getpwnam: %s user (%s)\n",
374 (pw ? "Found" : "Did not find"), name ));
379 /**********************************************************************
380 **********************************************************************/
382 WINBINDD_PW* wb_getpwuid( const uid_t uid )
386 static WINBINDD_PW *pw;
388 if ( !account_tdb && !winbindd_accountdb_init() ) {
389 DEBUG(0,("wb_getpwuid: Failed to open winbindd account db\n"));
393 data = tdb_fetch_by_string( account_tdb, acct_userkey_byuid(uid) );
395 DEBUG(4,("wb_getpwuid: failed to locate uid == %d\n", uid));
398 keystr = acct_userkey_byname( data.dptr );
400 SAFE_FREE( data.dptr );
402 data = tdb_fetch_by_string( account_tdb, keystr );
407 pw = string2passwd( data.dptr );
408 SAFE_FREE( data.dptr );
411 DEBUG(5,("wb_getpwuid: %s user (uid == %d)\n",
412 (pw ? "Found" : "Did not find"), uid ));
417 /**********************************************************************
418 **********************************************************************/
420 BOOL wb_storepwnam( const WINBINDD_PW *pw )
422 char *namekey, *uidkey;
428 if ( !account_tdb && !winbindd_accountdb_init() ) {
429 DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
433 namekey = acct_userkey_byname( pw->pw_name );
435 /* lock the main entry first */
437 if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
438 DEBUG(0,("wb_storepwnam: Failed to lock %s\n", namekey));
442 str = passwd2string( pw );
445 data.dsize = strlen(str) + 1;
447 if ( (tdb_store_by_string(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
448 DEBUG(0,("wb_storepwnam: Failed to store \"%s\"\n", str));
453 /* store the uid index */
455 uidkey = acct_userkey_byuid(pw->pw_uid);
457 fstrcpy( username, pw->pw_name );
458 data.dptr = username;
459 data.dsize = strlen(username) + 1;
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);
468 DEBUG(10,("wb_storepwnam: Success -> \"%s\"\n", str));
471 tdb_unlock_bystring( account_tdb, namekey );
476 /**********************************************************************
477 **********************************************************************/
479 WINBINDD_GR* wb_getgrnam( const char * name )
483 static WINBINDD_GR *grp;
485 if ( !account_tdb && !winbindd_accountdb_init() ) {
486 DEBUG(0,("wb_getgrnam: Failed to open winbindd account db\n"));
491 keystr = acct_groupkey_byname( name );
493 data = tdb_fetch_by_string( account_tdb, keystr );
498 grp = string2group( data.dptr );
499 SAFE_FREE( data.dptr );
502 DEBUG(5,("wb_getgrnam: %s group (%s)\n",
503 (grp ? "Found" : "Did not find"), name ));
508 /**********************************************************************
509 **********************************************************************/
511 WINBINDD_GR* wb_getgrgid( gid_t gid )
515 static WINBINDD_GR *grp;
517 if ( !account_tdb && !winbindd_accountdb_init() ) {
518 DEBUG(0,("wb_getgrgid: Failed to open winbindd account db\n"));
522 data = tdb_fetch_by_string( account_tdb, acct_groupkey_bygid(gid) );
524 DEBUG(4,("wb_getgrgid: failed to locate gid == %d\n", gid));
527 keystr = acct_groupkey_byname( data.dptr );
529 SAFE_FREE( data.dptr );
531 data = tdb_fetch_by_string( account_tdb, keystr );
536 grp = string2group( data.dptr );
537 SAFE_FREE( data.dptr );
540 DEBUG(5,("wb_getgrgid: %s group (gid == %d)\n",
541 (grp ? "Found" : "Did not find"), gid ));
546 /**********************************************************************
547 **********************************************************************/
549 BOOL wb_storegrnam( const WINBINDD_GR *grp )
551 char *namekey, *gidkey;
557 if ( !account_tdb && !winbindd_accountdb_init() ) {
558 DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
562 namekey = acct_groupkey_byname( grp->gr_name );
564 /* lock the main entry first */
566 if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
567 DEBUG(0,("wb_storegrnam: Failed to lock %s\n", namekey));
571 str = group2string( grp );
574 data.dsize = strlen(str) + 1;
576 if ( (tdb_store_by_string(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
577 DEBUG(0,("wb_storegrnam: Failed to store \"%s\"\n", str));
582 /* store the gid index */
584 gidkey = acct_groupkey_bygid(grp->gr_gid);
586 fstrcpy( groupname, grp->gr_name );
587 data.dptr = groupname;
588 data.dsize = strlen(groupname) + 1;
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);
597 DEBUG(10,("wb_storegrnam: Success -> \"%s\"\n", str));
600 tdb_unlock_bystring( account_tdb, namekey );
605 /**********************************************************************
606 **********************************************************************/
608 static BOOL wb_addgrpmember( WINBINDD_GR *grp, const char *user )
616 for ( i=0; i<grp->num_gr_mem; i++ ) {
617 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 )
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*) );
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;
633 /**********************************************************************
634 **********************************************************************/
636 static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user )
644 for ( i=0; i<grp->num_gr_mem && !found; i++ ) {
645 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 )
652 memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) );
658 /**********************************************************************
659 **********************************************************************/
661 static void free_winbindd_gr( WINBINDD_GR *grp )
668 for ( i=0; i<grp->num_gr_mem; i++ )
669 SAFE_FREE( grp->gr_mem[i] );
671 SAFE_FREE( grp->gr_mem );
676 /**********************************************************************
677 Create a new "UNIX" user for the system given a username
678 **********************************************************************/
680 enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
686 struct group *unix_grp;
689 if ( !state->privileged ) {
690 DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n"));
691 return WINBINDD_ERROR;
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';
698 user = state->request.data.acct_mgt.username;
699 group = state->request.data.acct_mgt.groupname;
701 DEBUG(3, ("[%5d]: create_user user=>(%s), group=>(%s)\n",
702 state->pid, user, group));
705 group = lp_template_primary_group();
707 /* validate the primary group
708 1) lookup in local tdb first
709 2) call getgrnam() as a last resort */
711 if ( (wb_grp=wb_getgrnam(group)) != NULL ) {
712 primary_gid = wb_grp->gr_gid;
713 free_winbindd_gr( wb_grp );
715 else if ( (unix_grp=sys_getgrnam(group)) != NULL ) {
716 primary_gid = unix_grp->gr_gid;
719 DEBUG(2,("winbindd_create_user: Cannot validate gid for group (%s)\n", group));
720 return WINBINDD_ERROR;
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;
730 /* The substitution of %U and %D in the 'template homedir' is done
731 by lp_string() calling standard_sub_basic(). */
733 fstrcpy( current_user_info.smb_name, user );
734 sub_set_smb_name( user );
735 fstrcpy( current_user_info.domain, get_global_sam_name() );
737 /* fill in the passwd struct */
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() );
746 pw.pw_gid = primary_gid;
748 return ( wb_storepwnam(&pw) ? WINBINDD_OK : WINBINDD_ERROR );
751 /**********************************************************************
752 Create a new "UNIX" group for the system given a username
753 **********************************************************************/
755 enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
761 if ( !state->privileged ) {
762 DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n"));
763 return WINBINDD_ERROR;
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;
770 DEBUG(3, ("[%5d]: create_group (%s)\n", state->pid, group));
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;
779 /* fill in the group struct */
781 fstrcpy( grp.gr_name, group );
782 fstrcpy( grp.gr_passwd, "*" );
785 grp.gr_mem = NULL; /* start with no members */
788 return ( wb_storegrnam(&grp) ? WINBINDD_OK : WINBINDD_ERROR );
791 /**********************************************************************
792 Add a user to the membership for a group.
793 **********************************************************************/
795 enum winbindd_result winbindd_add_user_to_group(struct winbindd_cli_state *state)
802 if ( !state->privileged ) {
803 DEBUG(2, ("winbindd_add_user_to_group: non-privileged access denied!\n"));
804 return WINBINDD_ERROR;
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;
813 DEBUG(3, ("[%5d]: add_user_to_group add %s to %s\n", state->pid,
816 /* make sure it is a valid user */
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;
823 /* make sure it is a valid group */
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;
830 if ( !wb_addgrpmember( grp, user ) )
831 return WINBINDD_ERROR;
833 ret = wb_storegrnam(grp);
835 free_winbindd_gr( grp );
837 return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
840 /**********************************************************************
841 Remove a user from the membership of a group
842 **********************************************************************/
844 enum winbindd_result winbindd_remove_user_from_group(struct winbindd_cli_state *state)
850 if ( !state->privileged ) {
851 DEBUG(2, ("winbindd_remove_user_from_group: non-privileged access denied!\n"));
852 return WINBINDD_ERROR;
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;
861 DEBUG(3, ("[%5d]: remove_user_to_group delete %s from %s\n", state->pid,
864 /* don't worry about checking the username since we're removing it anyways */
866 /* make sure it is a valid group */
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;
873 if ( !wb_delgrpmember( grp, user ) )
874 return WINBINDD_ERROR;
876 ret = wb_storegrnam(grp);
878 free_winbindd_gr( grp );
880 return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
883 /**********************************************************************
884 Set the primary group membership of a user
885 **********************************************************************/
887 enum winbindd_result winbindd_set_user_primary_group(struct winbindd_cli_state *state)
893 if ( !state->privileged ) {
894 DEBUG(2, ("winbindd_set_user_primary_group: non-privileged access denied!\n"));
895 return WINBINDD_ERROR;
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;
904 DEBUG(3, ("[%5d]: set_user_primary_group group %s for user %s\n", state->pid,
907 /* make sure it is a valid user */
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;
914 /* make sure it is a valid group */
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;
921 pw->pw_gid = grp->gr_gid;
923 free_winbindd_gr( grp );
925 return ( wb_storepwnam(pw) ? WINBINDD_OK : WINBINDD_ERROR );
928 /**********************************************************************
929 Set the primary group membership of a user
930 **********************************************************************/
932 enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state)
934 return WINBINDD_ERROR;
937 /**********************************************************************
938 Set the primary group membership of a user
939 **********************************************************************/
941 enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
943 return WINBINDD_ERROR;