From 03d5867d529f126da368ebda70bf2d997aa602e0 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 11 Jul 2003 05:33:40 +0000 Subject: moving more code around. * move rid allocation into IDMAP. See comments in _api_samr_create_user() * add winbind delete user/group functions I'm checking this in to sync up with everyone. But I'm going to split the add a separate winbindd_allocate_rid() function for systems that have an 'add user script' but need idmap to give them a RID. Life would be so much simplier without 'enable rid algorithm'. The current RID allocation is horrible due to this one fact. Tested idmap_tdb but not idmap_ldap yet. Will do that tomorrow. Nothing has changed in the way a samba domain is represented, stored, or search in the directory so things should be ok with previous installations. going to bed now. (This used to be commit 0463045cc7ff177fab44b25faffad5bf7140244d) --- source3/nsswitch/winbindd_acct.c | 226 +++++++++++++++++++++++++++++++++++---- 1 file changed, 203 insertions(+), 23 deletions(-) (limited to 'source3/nsswitch/winbindd_acct.c') diff --git a/source3/nsswitch/winbindd_acct.c b/source3/nsswitch/winbindd_acct.c index 2a3a6eb2bb..a1cd1d5f19 100644 --- a/source3/nsswitch/winbindd_acct.c +++ b/source3/nsswitch/winbindd_acct.c @@ -37,6 +37,29 @@ static TDB_CONTEXT *account_tdb; extern userdom_struct current_user_info; +struct _check_primary_grp { + gid_t gid; + BOOL found; +}; + +/********************************************************************** +**********************************************************************/ + +static void free_winbindd_gr( WINBINDD_GR *grp ) +{ + int i; + + if ( !grp ) + return; + + for ( i=0; inum_gr_mem; i++ ) + SAFE_FREE( grp->gr_mem[i] ); + + SAFE_FREE( grp->gr_mem ); + + return; +} + /***************************************************************************** Initialise auto-account database. *****************************************************************************/ @@ -649,8 +672,17 @@ static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user ) if ( !found ) return False; - memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) ); - grp->num_gr_mem--; + /* still some remaining members */ + + if ( grp->num_gr_mem > 1 ) { + memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) ); + grp->num_gr_mem--; + } + else { /* last one */ + free_winbindd_gr( grp ); + grp->gr_mem = NULL; + grp->num_gr_mem = 0; + } return True; } @@ -658,34 +690,59 @@ static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user ) /********************************************************************** **********************************************************************/ -static void free_winbindd_gr( WINBINDD_GR *grp ) +static int cleangroups_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, + void *state) { - int i; - - if ( !grp ) - return; + int len; + fstring key; + char *name = (char*)state; + + snprintf( key, sizeof(key), "%s/NAME", WBKEY_GROUP ); + len = strlen(key); + + /* if this is a group entry then, check the members */ + + if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) { + WINBINDD_GR *grp; - for ( i=0; inum_gr_mem; i++ ) - SAFE_FREE( grp->gr_mem[i] ); + if ( !(grp = string2group( dbuf.dptr )) ) { + DEBUG(0,("cleangroups_traverse_fn: Failure to parse [%s]\n", + dbuf.dptr)); + return 0; + } + + /* just try to delete the user and rely on wb_delgrpmember() + to tell you whether or not the group changed. This is more + effecient than testing group membership first since the + checks for deleting a user from a group is essentially the + same as checking if he/she is a member */ + + if ( wb_delgrpmember( grp, name ) ) { + DEBUG(10,("cleanupgroups_traverse_fn: Removed user (%s) from group (%s)\n", + name, grp->gr_name)); + wb_storegrnam( grp ); + } + + free_winbindd_gr( grp ); + } - SAFE_FREE( grp->gr_mem ); - - return; + return 0; } /********************************************************************** **********************************************************************/ -static BOOL wb_delete_user( const char *name) +static BOOL wb_delete_user( WINBINDD_PW *pw) { char *namekey; + char *uidkey; if ( !account_tdb && !winbindd_accountdb_init() ) { - DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n")); + DEBUG(0,("wb_delete_user: Failed to open winbindd account db\n")); return False; } - namekey = acct_userkey_byname( name ); + namekey = acct_userkey_byname( pw->pw_name ); /* lock the main entry first */ @@ -694,20 +751,101 @@ static BOOL wb_delete_user( const char *name) return False; } + /* remove user from all groups */ + + tdb_traverse(account_tdb, cleangroups_traverse_fn, (void *)pw->pw_name); + + /* remove the user */ + uidkey = acct_userkey_byuid( pw->pw_uid ); tdb_delete_bystring( account_tdb, namekey ); + tdb_delete_bystring( account_tdb, uidkey ); + tdb_unlock_bystring( account_tdb, namekey ); return True; } +/********************************************************************** +**********************************************************************/ + +static int isprimarygroup_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, + TDB_DATA dbuf, void *params) +{ + int len; + fstring key; + struct _check_primary_grp *check = (struct _check_primary_grp*)params; + + snprintf( key, sizeof(key), "%s/NAME", WBKEY_PASSWD ); + len = strlen(key); + + /* if this is a group entry then, check the members */ + + if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) { + WINBINDD_PW *pw;; + + if ( !(pw = string2passwd( dbuf.dptr )) ) { + DEBUG(0,("isprimarygroup_traverse_fn: Failure to parse [%s]\n", + dbuf.dptr)); + return 0; + } + + if ( check->gid == pw->pw_gid ) { + check->found = True; + return 1; + } + } + + return 0; +} + /********************************************************************** **********************************************************************/ -static BOOL wb_delete_group( const char *name) +static BOOL wb_delete_group( WINBINDD_GR *grp ) { - return False; + struct _check_primary_grp check; + char *namekey; + char *gidkey; + + if ( !account_tdb && !winbindd_accountdb_init() ) { + DEBUG(0,("wb_delete_group: Failed to open winbindd account db\n")); + return False; + } + + /* lock the main entry first */ + + namekey = acct_groupkey_byname( grp->gr_name ); + if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) { + DEBUG(0,("wb_delete_group: Failed to lock %s\n", namekey)); + return False; + } + + /* is this group the primary group for any user? If + so deny delete */ + + check.found = False; + tdb_traverse(account_tdb, isprimarygroup_traverse_fn, (void *)&check); + + if ( check.found ) { + DEBUG(4,("wb_delete_group: Cannot delete group (%s) since it " + "is the primary group for some users\n", grp->gr_name)); + return False; + } + + /* We're clear. Delete the group */ + + DEBUG(5,("wb_delete_group: Removing group (%s)\n", grp->gr_name)); + + gidkey = acct_groupkey_bygid( grp->gr_gid ); + + tdb_delete_bystring( account_tdb, namekey ); + tdb_delete_bystring( account_tdb, gidkey ); + + tdb_unlock_bystring( account_tdb, namekey ); + + return True; } /********************************************************************** @@ -722,6 +860,8 @@ enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state) WINBINDD_GR *wb_grp; struct group *unix_grp; gid_t primary_gid; + uint32 flags = state->request.flags; + uint32 rid; if ( !state->privileged ) { DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n")); @@ -781,8 +921,27 @@ enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state) pw.pw_uid = id.uid; pw.pw_gid = primary_gid; + + /* store the new entry */ + + if ( !wb_storepwnam(&pw) ) + return WINBINDD_ERROR; + + /* do we need a new RID? */ + + if ( flags & WBFLAG_ALLOCATE_RID ) { + if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, USER_RID_TYPE)) ) { + DEBUG(0,("winbindd_create_user: RID allocation failure! Cannot create user (%s)\n", + user)); + wb_delete_user( &pw ); + + return WINBINDD_ERROR; + } + + state->response.data.rid = rid; + } - return ( wb_storepwnam(&pw) ? WINBINDD_OK : WINBINDD_ERROR ); + return WINBINDD_OK; } /********************************************************************** @@ -794,6 +953,8 @@ enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state) char *group; unid_t id; WINBINDD_GR grp; + uint32 flags = state->request.flags; + uint32 rid; if ( !state->privileged ) { DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n")); @@ -821,8 +982,25 @@ enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state) grp.gr_gid = id.gid; grp.gr_mem = NULL; /* start with no members */ grp.num_gr_mem = 0; + + if ( !wb_storegrnam(&grp) ) + return WINBINDD_ERROR; + + /* do we need a new RID? */ + + if ( flags & WBFLAG_ALLOCATE_RID ) { + if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, GROUP_RID_TYPE)) ) { + DEBUG(0,("winbindd_create_group: RID allocation failure! Cannot create group (%s)\n", + group)); + wb_delete_group( &grp ); + + return WINBINDD_ERROR; + } + + state->response.data.rid = rid; + } - return ( wb_storegrnam(&grp) ? WINBINDD_OK : WINBINDD_ERROR ); + return WINBINDD_OK; } /********************************************************************** @@ -989,8 +1167,7 @@ enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - - return ( wb_delete_user(user) ? WINBINDD_OK : WINBINDD_ERROR ); + return ( wb_delete_user(pw) ? WINBINDD_OK : WINBINDD_ERROR ); } /********************************************************************** @@ -1001,6 +1178,7 @@ enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state) { WINBINDD_GR *grp; char *group; + BOOL ret; if ( !state->privileged ) { DEBUG(2, ("winbindd_delete_group: non-privileged access denied!\n")); @@ -1016,13 +1194,15 @@ enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state) /* make sure it is a valid group */ if ( !(grp = wb_getgrnam( group )) ) { - DEBUG(4,("winbindd_delete_user: Cannot delete a non-existent group\n")); + DEBUG(4,("winbindd_delete_group: Cannot delete a non-existent group\n")); return WINBINDD_ERROR; } + ret = wb_delete_group(grp); + free_winbindd_gr( grp ); - return ( wb_delete_group(group) ? WINBINDD_OK : WINBINDD_ERROR ); + return ( ret ? WINBINDD_OK : WINBINDD_ERROR ); } -- cgit