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/wb_client.c | 74 ++++++++++++- source3/nsswitch/wbinfo.c | 82 ++++++++++---- source3/nsswitch/winbindd_acct.c | 226 +++++++++++++++++++++++++++++++++++---- source3/nsswitch/winbindd_nss.h | 2 + source3/nsswitch/winbindd_user.c | 13 +++ 5 files changed, 350 insertions(+), 47 deletions(-) (limited to 'source3/nsswitch') diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c index 26a0e58191..eb9a7e9995 100644 --- a/source3/nsswitch/wb_client.c +++ b/source3/nsswitch/wb_client.c @@ -371,7 +371,7 @@ BOOL winbind_ping( void ) Ask winbindd to create a local user **********************************************************************/ -BOOL winbind_create_user( const char *name ) +BOOL winbind_create_user( const char *name, uint32 *rid ) { struct winbindd_request request; struct winbindd_response response; @@ -384,6 +384,11 @@ BOOL winbind_create_user( const char *name ) return False; DEBUG(10,("winbind_create_user: %s\n", name)); + + /* see if the caller wants a new RID returned */ + + if ( rid ) + request.flags = WBFLAG_ALLOCATE_RID; fstrcpy( request.data.acct_mgt.username, name ); fstrcpy( request.data.acct_mgt.groupname, "" ); @@ -392,6 +397,9 @@ BOOL winbind_create_user( const char *name ) result = winbindd_request( WINBINDD_CREATE_USER, &request, &response); + if ( rid ) + *rid = response.data.rid; + return result == NSS_STATUS_SUCCESS; } @@ -399,7 +407,7 @@ BOOL winbind_create_user( const char *name ) Ask winbindd to create a local group **********************************************************************/ -BOOL winbind_create_group( const char *name ) +BOOL winbind_create_group( const char *name, uint32 *rid ) { struct winbindd_request request; struct winbindd_response response; @@ -413,12 +421,20 @@ BOOL winbind_create_group( const char *name ) DEBUG(10,("winbind_create_group: %s\n", name)); + /* see if the caller wants a new RID returned */ + + if ( rid ) + request.flags = WBFLAG_ALLOCATE_RID; + fstrcpy( request.data.acct_mgt.groupname, name ); ZERO_STRUCT(response); result = winbindd_request( WINBINDD_CREATE_GROUP, &request, &response); + if ( rid ) + *rid = response.data.rid; + return result == NSS_STATUS_SUCCESS; } @@ -510,4 +526,58 @@ BOOL winbind_set_user_primary_group( const char *user, const char *group ) } +/********************************************************************** + Ask winbindd to remove a user from its lists of accounts +**********************************************************************/ + +BOOL winbind_delete_user( const char *user ) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + + if ( !lp_winbind_enable_local_accounts() ) + return False; + + if ( !user ) + return False; + + DEBUG(10,("winbind_delete_user: user (%s)\n", user)); + + fstrcpy( request.data.acct_mgt.username, user ); + + ZERO_STRUCT(response); + + result = winbindd_request( WINBINDD_DELETE_USER, &request, &response); + + return result == NSS_STATUS_SUCCESS; +} + +/********************************************************************** + Ask winbindd to remove a group from its lists of accounts +**********************************************************************/ + +BOOL winbind_delete_group( const char *group ) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + + if ( !lp_winbind_enable_local_accounts() ) + return False; + + if ( !group ) + return False; + + DEBUG(10,("winbind_delete_group: group (%s)\n", group)); + + fstrcpy( request.data.acct_mgt.groupname, group ); + + ZERO_STRUCT(response); + + result = winbindd_request( WINBINDD_DELETE_GROUP, &request, &response); + + return result == NSS_STATUS_SUCCESS; +} + diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c index 6ebf6effa7..f533799370 100644 --- a/source3/nsswitch/wbinfo.c +++ b/source3/nsswitch/wbinfo.c @@ -526,16 +526,36 @@ static BOOL wbinfo_create_user(char *username) ZERO_STRUCT(request); ZERO_STRUCT(response); + request.flags = WBFLAG_ALLOCATE_RID; fstrcpy(request.data.acct_mgt.username, username); result = winbindd_request(WINBINDD_CREATE_USER, &request, &response); - if (response.data.auth.nt_status) - d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); + if ( result == NSS_STATUS_SUCCESS ) + d_printf("New RID is %d\n", response.data.rid); + + return result == NSS_STATUS_SUCCESS; +} +/****************************************************************** + remove a winbindd user +******************************************************************/ + +static BOOL wbinfo_delete_user(char *username) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + + /* Send off request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + fstrcpy(request.data.acct_mgt.username, username); + + result = winbindd_request(WINBINDD_DELETE_USER, &request, &response); + return result == NSS_STATUS_SUCCESS; } @@ -558,12 +578,28 @@ static BOOL wbinfo_create_group(char *groupname) result = winbindd_request(WINBINDD_CREATE_GROUP, &request, &response); - if (response.data.auth.nt_status) - d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); + return result == NSS_STATUS_SUCCESS; +} +/****************************************************************** + remove a winbindd group +******************************************************************/ + +static BOOL wbinfo_delete_group(char *groupname) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + + /* Send off request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + fstrcpy(request.data.acct_mgt.groupname, groupname); + + result = winbindd_request(WINBINDD_DELETE_GROUP, &request, &response); + return result == NSS_STATUS_SUCCESS; } @@ -614,12 +650,6 @@ static BOOL wbinfo_add_user_to_group(char *string) result = winbindd_request(WINBINDD_ADD_USER_TO_GROUP, &request, &response); - if (response.data.auth.nt_status) - d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); - return result == NSS_STATUS_SUCCESS; } @@ -647,12 +677,6 @@ static BOOL wbinfo_remove_user_from_group(char *string) result = winbindd_request(WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response); - if (response.data.auth.nt_status) - d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); - return result == NSS_STATUS_SUCCESS; } @@ -851,7 +875,9 @@ int main(int argc, char **argv) { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" }, { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" }, { "create-user", 'c', POPT_ARG_STRING, &string_arg, 'c', "Create a local user account", "name" }, + { "delete-user", 'x', POPT_ARG_STRING, &string_arg, 'x', "Delete a local user account", "name" }, { "create-group", 'C', POPT_ARG_STRING, &string_arg, 'C', "Create a local group", "name" }, + { "delete-group", 'X', POPT_ARG_STRING, &string_arg, 'X', "Delete a local group", "name" }, { "add-to-group", 'o', POPT_ARG_STRING, &string_arg, 'o', "Add user to group", "user:group" }, { "del-from-group", 'O', POPT_ARG_STRING, &string_arg, 'O', "Remove user from group", "user:group" }, { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" }, @@ -1036,6 +1062,18 @@ int main(int argc, char **argv) goto done; } break; + case 'x': + if ( !wbinfo_delete_user(string_arg) ) { + d_printf("Could not delete user account\n"); + goto done; + } + break; + case 'X': + if ( !wbinfo_delete_group(string_arg) ) { + d_printf("Could not delete group\n"); + goto done; + } + break; case 'P': if (!wbinfo_ping()) { d_printf("could not ping winbindd!\n"); 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 ); } diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index a2d9e82c7c..c4407bbe31 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -148,6 +148,7 @@ typedef struct winbindd_gr { #define WBFLAG_PAM_LMKEY 0x0008 #define WBFLAG_PAM_CONTACT_TRUSTDOM 0x0010 #define WBFLAG_QUERY_ONLY 0x0020 +#define WBFLAG_ALLOCATE_RID 0x0040 /* Winbind request structure */ @@ -257,6 +258,7 @@ struct winbindd_response { char nt_session_key[16]; char first_8_lm_hash[8]; } auth; + uint32 rid; /* create user or group */ } data; /* Variable length return data */ diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 7c95ba8470..c49c41687b 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -308,6 +308,19 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state) free_getent_state(state->getpwent_state); state->getpwent_state = NULL; } + +#if 0 /* JERRY */ + /* add any local users we have */ + + if ( (domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL ) + return WINBINDD_ERROR; + + ZERO_STRUCTP(domain_state); + + /* Add to list of open domains */ + + DLIST_ADD(state->getpwent_state, domain_state); +#endif /* Create sam pipes for each domain we know about */ -- cgit