diff options
author | Gerald Carter <jerry@samba.org> | 2003-07-11 05:33:40 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2003-07-11 05:33:40 +0000 |
commit | 03d5867d529f126da368ebda70bf2d997aa602e0 (patch) | |
tree | 6bed479ab42b3bcbd5ac6b70157c16232ff69869 /source3 | |
parent | d117c83ca9fc1b598d09f5d24805560e9c49f65c (diff) | |
download | samba-03d5867d529f126da368ebda70bf2d997aa602e0.tar.gz |
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)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/auth/auth_util.c | 6 | ||||
-rw-r--r-- | source3/groupdb/mapping.c | 6 | ||||
-rw-r--r-- | source3/include/idmap.h | 1 | ||||
-rw-r--r-- | source3/lib/smbldap.c | 148 | ||||
-rw-r--r-- | source3/nsswitch/wb_client.c | 74 | ||||
-rw-r--r-- | source3/nsswitch/wbinfo.c | 82 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_acct.c | 226 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_nss.h | 2 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_user.c | 13 | ||||
-rw-r--r-- | source3/passdb/passdb.c | 171 | ||||
-rw-r--r-- | source3/passdb/pdb_ldap.c | 489 | ||||
-rw-r--r-- | source3/passdb/pdb_smbpasswd.c | 112 | ||||
-rw-r--r-- | source3/passdb/pdb_tdb.c | 77 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 35 | ||||
-rw-r--r-- | source3/sam/idmap.c | 15 | ||||
-rw-r--r-- | source3/sam/idmap_ldap.c | 283 | ||||
-rw-r--r-- | source3/sam/idmap_tdb.c | 41 | ||||
-rw-r--r-- | source3/sam/idmap_util.c | 114 | ||||
-rw-r--r-- | source3/utils/net_rpc_samsync.c | 4 | ||||
-rw-r--r-- | source3/utils/pdbedit.c | 2 |
20 files changed, 1059 insertions, 842 deletions
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 51cd1994f91..3f9c120cfb1 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -56,10 +56,12 @@ static int smb_create_user(const char *domain, const char *unix_username, const /**************************************************************************** Add and Delete UNIX users on demand, based on NTSTATUS codes. + We don't care about RID's here so ignore. ****************************************************************************/ void auth_add_user_script(const char *domain, const char *username) { + uint32 rid; /* * User validated ok against Domain controller. * If the admin wants us to try and create a UNIX @@ -75,8 +77,10 @@ void auth_add_user_script(const char *domain, const char *username) However, a host set for 'security = server' might run winbindd for account allocation */ - if ( !winbind_create_user(username) ) + if ( !winbind_create_user(username, NULL) ) { DEBUG(5,("auth_add_user_script: winbindd_create_user() failed\n")); + rid = 0; + } } } diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c index e769b4dd9da..8a6f5148605 100644 --- a/source3/groupdb/mapping.c +++ b/source3/groupdb/mapping.c @@ -756,7 +756,7 @@ int smb_create_group(char *unix_group, gid_t *new_gid) /* Try winbindd */ - if ( winbind_create_group( unix_group ) ) { + if ( winbind_create_group( unix_group, NULL ) ) { DEBUG(3,("smb_create_group: winbindd created the group (%s)\n", unix_group)); return 0; @@ -783,15 +783,13 @@ int smb_delete_group(char *unix_group) DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret)); return ret; } -#if 0 + if ( winbind_delete_group( unix_group ) ) { DEBUG(3,("smb_delete_group: winbindd deleted the group (%s)\n", unix_group)); return 0; } -#endif - return -1; } diff --git a/source3/include/idmap.h b/source3/include/idmap.h index 7da3718d197..ae7e4e5101b 100644 --- a/source3/include/idmap.h +++ b/source3/include/idmap.h @@ -42,6 +42,7 @@ struct idmap_methods { /* Called when backend is first loaded */ NTSTATUS (*init)( char *params ); + NTSTATUS (*allocate_rid)(uint32 *rid, int rid_type); NTSTATUS (*allocate_id)(unid_t *id, int id_type); NTSTATUS (*get_sid_from_id)(DOM_SID *sid, unid_t id, int id_type); NTSTATUS (*get_id_from_sid)(unid_t *id, int *id_type, const DOM_SID *sid); diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index cba73d386c4..21e3383acdc 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -1110,3 +1110,151 @@ NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_ return NT_STATUS_OK; } +/********************************************************************** + Add the sambaDomain to LDAP, so we don't have to search for this stuff + again. This is a once-add operation for now. + + TODO: Add other attributes, and allow modification. +*********************************************************************/ +static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, + const char *domain_name) +{ + fstring sid_string; + fstring algorithmic_rid_base_string; + pstring filter, dn; + LDAPMod **mods = NULL; + int rc; + int ldap_op; + LDAPMessage *result = NULL; + int num_result; + char **attr_list; + + slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), + domain_name, LDAP_OBJ_DOMINFO); + + attr_list = get_attr_list( dominfo_attr_list ); + rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result); + free_attr_list( attr_list ); + + if (rc != LDAP_SUCCESS) { + return NT_STATUS_UNSUCCESSFUL; + } + + num_result = ldap_count_entries(ldap_state->ldap_struct, result); + + if (num_result > 1) { + DEBUG (0, ("More than domain with that name exists: bailing out!\n")); + ldap_msgfree(result); + return NT_STATUS_UNSUCCESSFUL; + } + + /* Check if we need to add an entry */ + DEBUG(3,("Adding new domain\n")); + ldap_op = LDAP_MOD_ADD; + + snprintf(dn, sizeof(dn), "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), + domain_name, lp_ldap_suffix()); + + /* Free original search */ + ldap_msgfree(result); + + /* make the changes - the entry *must* not already have samba attributes */ + smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), + domain_name); + + /* If we don't have an entry, then ask secrets.tdb for what it thinks. + It may choose to make it up */ + + sid_to_string(sid_string, get_global_sam_sid()); + smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string); + + slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base()); + smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), + algorithmic_rid_base_string); + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO); + + switch(ldap_op) + { + case LDAP_MOD_ADD: + rc = smbldap_add(ldap_state, dn, mods); + break; + case LDAP_MOD_REPLACE: + rc = smbldap_modify(ldap_state, dn, mods); + break; + default: + DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (rc!=LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(1,("failed to %s domain dn= %s with: %s\n\t%s\n", + ldap_op == LDAP_MOD_ADD ? "add" : "modify", + dn, ldap_err2string(rc), + ld_error?ld_error:"unknown")); + SAFE_FREE(ld_error); + + ldap_mods_free(mods, True); + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(2,("added: domain = %s in the LDAP database\n", domain_name)); + ldap_mods_free(mods, True); + return NT_STATUS_OK; +} + +/********************************************************************** +Search for the domain info entry +*********************************************************************/ +NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state, + LDAPMessage ** result, const char *domain_name, + BOOL try_add) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + pstring filter; + int rc; + char **attr_list; + int count; + + snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))", + LDAP_OBJ_DOMINFO, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), + domain_name); + + DEBUG(2, ("Searching for:[%s]\n", filter)); + + + attr_list = get_attr_list( dominfo_attr_list ); + rc = smbldap_search_suffix(ldap_state, filter, attr_list , result); + free_attr_list( attr_list ); + + if (rc != LDAP_SUCCESS) { + DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc))); + DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter)); + } else if (ldap_count_entries(ldap_state->ldap_struct, *result) < 1) { + DEBUG(3, ("Got no domain info entries for domain\n")); + ldap_msgfree(*result); + *result = NULL; + if (try_add && NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state, domain_name))) { + return smbldap_search_domain_info(ldap_state, result, domain_name, False); + } + else { + DEBUG(0, ("Adding domain info for %s failed with %s\n", + domain_name, nt_errstr(ret))); + return ret; + } + } else if ((count = ldap_count_entries(ldap_state->ldap_struct, *result)) > 1) { + DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n", + count, domain_name)); + ldap_msgfree(*result); + *result = NULL; + return ret; + } else { + return NT_STATUS_OK; + } + + return ret; +} + diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c index 26a0e58191f..eb9a7e99958 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 6ebf6effa76..f5337993704 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 2a3a6eb2bb0..a1cd1d5f19a 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; i<grp->num_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; i<grp->num_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 a2d9e82c7c7..c4407bbe31c 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 7c95ba84705..c49c41687b9 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 */ diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index a2623ff3d70..408695d4bd1 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -290,41 +290,37 @@ NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd) /************************************************************* Initialises a SAM_ACCOUNT ready to add a new account, based - on the unix user if possible. + on the UNIX user. Pass in a RID if you have one ************************************************************/ -NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username) +NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username, + uint32 rid) { - NTSTATUS nt_status = NT_STATUS_NO_MEMORY; - - struct passwd *pwd; + NTSTATUS nt_status = NT_STATUS_NO_MEMORY; + struct passwd *pwd; + BOOL ret; pwd = Get_Pwnam(username); - if (pwd) { - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) { - *new_sam_acct = NULL; - return nt_status; - } - } else { - DOM_SID g_sid; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(new_sam_acct))) { - *new_sam_acct = NULL; - return nt_status; - } - if (!pdb_set_username(*new_sam_acct, username, PDB_SET)) { - pdb_free_sam(new_sam_acct); - return nt_status; - } - - pdb_set_domain (*new_sam_acct, get_global_sam_name(), PDB_DEFAULT); - - /* set Domain Users by default ! */ - sid_copy(&g_sid, get_global_sam_sid()); - sid_append_rid(&g_sid, DOMAIN_GROUP_RID_USERS); - pdb_set_group_sid(*new_sam_acct, &g_sid, PDB_SET); + if (!pwd) + return NT_STATUS_NO_SUCH_USER; + + if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) { + *new_sam_acct = NULL; + return nt_status; } - return NT_STATUS_OK; + + /* see if we need to generate a new rid using the 2.2 algorithm */ + if ( rid == 0 && lp_enable_rid_algorithm() ) { + DEBUG(10,("pdb_init_sam_new: no RID specified. Generating one via old algorithm\n")); + rid = fallback_pdb_uid_to_user_rid(pwd->pw_uid); + } + + /* set the new SID */ + + ret = pdb_set_user_sid_from_rid( *new_sam_acct, rid, PDB_SET ); + + return (ret ? NT_STATUS_OK : NT_STATUS_NO_SUCH_USER); } @@ -920,8 +916,8 @@ BOOL local_password_change(const char *user_name, int local_flags, pdb_free_sam(&sam_pass); if ((local_flags & LOCAL_ADD_USER) || (local_flags & LOCAL_DELETE_USER)) { - /* Might not exist in /etc/passwd */ - if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pass, user_name))) { + /* Might not exist in /etc/passwd. Use rid algorithm here */ + if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pass, user_name, 0))) { slprintf(err_str, err_str_len-1, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name); return False; } @@ -1248,121 +1244,6 @@ BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_ } /********************************************************************** -**********************************************************************/ - -BOOL pdb_get_free_ugid_range(uint32 *low, uint32 *high) -{ - uid_t u_low, u_high; - gid_t g_low, g_high; - - if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) { - return False; - } - - *low = (u_low < g_low) ? u_low : g_low; - *high = (u_high < g_high) ? u_high : g_high; - - return True; -} - -/****************************************************************** - Get the the non-algorithmic RID range if idmap range are defined -******************************************************************/ - -BOOL pdb_get_free_rid_range(uint32 *low, uint32 *high) -{ - uint32 id_low, id_high; - - if (!lp_enable_rid_algorithm()) { - *low = BASE_RID; - *high = (uint32)-1; - } - - if (!pdb_get_free_ugid_range(&id_low, &id_high)) { - return False; - } - - *low = fallback_pdb_uid_to_user_rid(id_low); - if (fallback_pdb_user_rid_to_uid((uint32)-1) < id_high) { - *high = (uint32)-1; - } else { - *high = fallback_pdb_uid_to_user_rid(id_high); - } - - return True; -} - -/********************************************************************** - Get the free RID base if idmap is configured, otherwise return 0 -**********************************************************************/ - -uint32 pdb_get_free_rid_base(void) -{ - uint32 low, high; - if (pdb_get_free_rid_range(&low, &high)) { - return low; - } - return 0; -} - -/********************************************************************** -**********************************************************************/ - -BOOL pdb_check_ugid_is_in_free_range(uint32 id) -{ - uint32 low, high; - - if (!pdb_get_free_ugid_range(&low, &high)) { - return False; - } - if (id < low || id > high) { - return False; - } - return True; -} - -/********************************************************************** -**********************************************************************/ - -BOOL pdb_check_rid_is_in_free_range(uint32 rid) -{ - uint32 low, high; - - if (!pdb_get_free_rid_range(&low, &high)) { - return False; - } - if (rid < algorithmic_rid_base()) { - return True; - } - - if (rid < low || rid > high) { - return False; - } - - return True; -} - -/********************************************************************** - if it is a foreign SID or if the SID is in the free range, return true -**********************************************************************/ - -BOOL pdb_check_sid_is_in_free_range(const DOM_SID *sid) -{ - if (sid_compare_domain(get_global_sam_sid(), sid) == 0) { - - uint32 rid; - - if (sid_peek_rid(sid, &rid)) { - return pdb_check_rid_is_in_free_range(rid); - } - - return False; - } - - return True; -} - -/********************************************************************** Marshall/unmarshall SAM_ACCOUNT structs. *********************************************************************/ diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 886fd809f32..e32f566a7d7 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -96,15 +96,6 @@ struct ldapsam_privates { /* configuration items */ int schema_ver; - - BOOL permit_non_unix_accounts; - - uint32 low_allocated_user_rid; - uint32 high_allocated_user_rid; - - uint32 low_allocated_group_rid; - uint32 high_allocated_group_rid; - }; /********************************************************************** @@ -338,423 +329,7 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, ldap_memfree(dn); return NT_STATUS_OK; } - -/********************************************************************** - Add the sambaDomain to LDAP, so we don't have to search for this stuff - again. This is a once-add operation for now. - - TODO: Add other attributes, and allow modification. -*********************************************************************/ -static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state) -{ - fstring sid_string; - fstring algorithmic_rid_base_string; - pstring filter, dn; - LDAPMod **mods = NULL; - int rc; - int ldap_op; - LDAPMessage *result = NULL; - int num_result; - char **attr_list; - - slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - ldap_state->domain_name, LDAP_OBJ_DOMINFO); - - attr_list = get_attr_list( dominfo_attr_list ); - rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, - attr_list, &result); - free_attr_list( attr_list ); - - if (rc != LDAP_SUCCESS) { - return NT_STATUS_UNSUCCESSFUL; - } - - num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); - - if (num_result > 1) { - DEBUG (0, ("More than domain with that name exists: bailing out!\n")); - ldap_msgfree(result); - return NT_STATUS_UNSUCCESSFUL; - } - - /* Check if we need to add an entry */ - DEBUG(3,("Adding new domain\n")); - ldap_op = LDAP_MOD_ADD; - - snprintf(dn, sizeof(dn), "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - ldap_state->domain_name, lp_ldap_suffix()); - - /* Free original search */ - ldap_msgfree(result); - - /* make the changes - the entry *must* not already have samba attributes */ - smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - ldap_state->domain_name); - - /* If we don't have an entry, then ask secrets.tdb for what it thinks. - It may choose to make it up */ - - sid_to_string(sid_string, get_global_sam_sid()); - smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string); - - slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base()); - smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), - algorithmic_rid_base_string); - smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO); - - switch(ldap_op) - { - case LDAP_MOD_ADD: - rc = smbldap_add(ldap_state->smbldap_state, dn, mods); - break; - case LDAP_MOD_REPLACE: - rc = smbldap_modify(ldap_state->smbldap_state, dn, mods); - break; - default: - DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op)); - return NT_STATUS_INVALID_PARAMETER; - } - - if (rc!=LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, - &ld_error); - DEBUG(1, - ("failed to %s domain dn= %s with: %s\n\t%s\n", - ldap_op == LDAP_MOD_ADD ? "add" : "modify", - dn, ldap_err2string(rc), - ld_error?ld_error:"unknown")); - SAFE_FREE(ld_error); - - ldap_mods_free(mods, True); - return NT_STATUS_UNSUCCESSFUL; - } - - DEBUG(2,("added: domain = %s in the LDAP database\n", ldap_state->domain_name)); - ldap_mods_free(mods, True); - return NT_STATUS_OK; -} - -/********************************************************************** -Search for the domain info entry -*********************************************************************/ -static NTSTATUS ldapsam_search_domain_info(struct ldapsam_privates *ldap_state, - LDAPMessage ** result, BOOL try_add) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - pstring filter; - int rc; - char **attr_list; - int count; - - snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))", - LDAP_OBJ_DOMINFO, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), - ldap_state->domain_name); - - DEBUG(2, ("Searching for:[%s]\n", filter)); - - - attr_list = get_attr_list( dominfo_attr_list ); - rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, - attr_list , result); - free_attr_list( attr_list ); - - if (rc != LDAP_SUCCESS) { - DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc))); - DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter)); - } else if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, *result) < 1) { - DEBUG(3, ("Got no domain info entries for domain %s\n", - ldap_state->domain_name)); - ldap_msgfree(*result); - *result = NULL; - if (try_add && NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) { - return ldapsam_search_domain_info(ldap_state, result, False); - } else { - DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret))); - return ret; - } - } else if ((count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, *result)) > 1) { - DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n", - count, ldap_state->domain_name)); - ldap_msgfree(*result); - *result = NULL; - return ret; - } else { - return NT_STATUS_OK; - } - - return ret; -} - -/********************************************************************** - Even if the sambaDomain attribute in LDAP tells us that this RID is - safe to use, always check before use. -*********************************************************************/ -static BOOL sid_in_use(struct ldapsam_privates *ldap_state, - const DOM_SID *sid, int *error) -{ - fstring filter; - fstring sid_string; - LDAPMessage *result = NULL; - int count; - int rc; - char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL}; - - slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid)); - - rc = smbldap_search_suffix(ldap_state->smbldap_state, - filter, sid_attr, &result); - - if (rc != LDAP_SUCCESS) { - char *ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n", - sid_string, ld_error)); - SAFE_FREE(ld_error); - - *error = rc; - return True; - } - - if ((count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result)) > 0) { - DEBUG(3, ("Sid %s already in use - trying next RID\n", - sid_string)); - ldap_msgfree(result); - return True; - } - - ldap_msgfree(result); - - /* good, sid is not in use */ - return False; -} - -/********************************************************************** - Set the new nextRid attribute, and return one we can use. - - This also checks that this RID is actually free - in case the admin - manually stole it :-). -*********************************************************************/ -static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *rid, int rid_type) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - int rc; - LDAPMessage *domain_result = NULL; - LDAPMessage *entry = NULL; - char *dn; - LDAPMod **mods = NULL; - fstring old_rid_string; - fstring next_rid_string; - fstring algorithmic_rid_base_string; - uint32 next_rid; - uint32 alg_rid_base; - int attempts = 0; - char *ld_error = NULL; - - if ( ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT ) { - DEBUG(0, ("Allocated RIDs require the %s objectclass used by 'ldapsam'\n", - LDAP_OBJ_SAMBASAMACCOUNT)); - return NT_STATUS_UNSUCCESSFUL; - } - - while (attempts < 10) - { - if (!NT_STATUS_IS_OK(ret = ldapsam_search_domain_info(ldap_state, &domain_result, True))) { - return ret; - } - - entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, domain_result); - if (!entry) { - DEBUG(0, ("Could not get domain info entry\n")); - ldap_msgfree(domain_result); - return ret; - } - - if ((dn = ldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry)) == NULL) { - DEBUG(0, ("Could not get domain info DN\n")); - ldap_msgfree(domain_result); - return ret; - } - - /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and - algorithmic_rid_base. The other two are to avoid stomping on the - different sets of algorithmic RIDs */ - - if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), - algorithmic_rid_base_string)) - { - - alg_rid_base = (uint32)atol(algorithmic_rid_base_string); - } else { - alg_rid_base = algorithmic_rid_base(); - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base); - smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), - algorithmic_rid_base_string); - } - - next_rid = 0; - - if (alg_rid_base > BASE_RID) { - /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we - can allocate to new users */ - if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), - old_rid_string)) - { - *rid = (uint32)atol(old_rid_string); - } else { - *rid = BASE_RID; - } - - next_rid = *rid+1; - if (next_rid >= alg_rid_base) { - return NT_STATUS_UNSUCCESSFUL; - } - - slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid); - - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), - next_rid_string); - } - - if (!next_rid) { /* not got one already */ - switch (rid_type) { - case USER_RID_TYPE: - if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), - old_rid_string)) - { - - *rid = (uint32)atol(old_rid_string); - - } else { - *rid = ldap_state->low_allocated_user_rid; - } - break; - case GROUP_RID_TYPE: - if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), - old_rid_string)) - { - *rid = (uint32)atol(old_rid_string); - } else { - *rid = ldap_state->low_allocated_group_rid; - } - break; - } - - /* This is the core of the whole routine. If we had - scheme-style closures, there would be a *lot* less code - duplication... */ - - next_rid = *rid+RID_MULTIPLIER; - slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid); - - switch (rid_type) { - case USER_RID_TYPE: - if (next_rid > ldap_state->high_allocated_user_rid) { - return NT_STATUS_UNSUCCESSFUL; - } - - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), - next_rid_string); - break; - - case GROUP_RID_TYPE: - if (next_rid > ldap_state->high_allocated_group_rid) { - return NT_STATUS_UNSUCCESSFUL; - } - - /* Try to make the modification atomically by enforcing the - old value in the delete mod. */ - smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), - next_rid_string); - break; - } - } - - if ((rc = ldap_modify_s(ldap_state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) { - DOM_SID dom_sid; - DOM_SID sid; - pstring domain_sid_string; - int error = 0; - - if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, domain_result, - get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), - domain_sid_string)) - { - ldap_mods_free(mods, True); - ldap_memfree(dn); - ldap_msgfree(domain_result); - return ret; - } - - if (!string_to_sid(&dom_sid, domain_sid_string)) { - ldap_mods_free(mods, True); - ldap_memfree(dn); - ldap_msgfree(domain_result); - return ret; - } - - ldap_mods_free(mods, True); - mods = NULL; - ldap_memfree(dn); - ldap_msgfree(domain_result); - - sid_copy(&sid, &dom_sid); - sid_append_rid(&sid, *rid); - - /* check RID is not in use */ - if (sid_in_use(ldap_state, &sid, &error)) { - if (error) { - return ret; - } - continue; - } - - return NT_STATUS_OK; - } - - ld_error = NULL; - ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); - DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL")); - SAFE_FREE(ld_error); - - ldap_mods_free(mods, True); - mods = NULL; - - ldap_memfree(dn); - dn = NULL; - - ldap_msgfree(domain_result); - domain_result = NULL; - - { - /* Sleep for a random timeout */ - unsigned sleeptime = (sys_random()*sys_getpid()*attempts); - attempts += 1; - - sleeptime %= 100; - msleep(sleeptime); - } - } - - DEBUG(0, ("Failed to set new RID\n")); - return ret; -} + /* New Interface is being implemented here */ @@ -1192,34 +767,6 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass))); - if (pdb_get_init_flags(sampass, PDB_USERSID) == PDB_DEFAULT) { - if (ldap_state->permit_non_unix_accounts) { - if (!NT_STATUS_IS_OK(ldapsam_next_rid(ldap_state, &rid, USER_RID_TYPE))) { - DEBUG(0, ("NO user RID specified on account %s, and " - "finding next available NUA RID failed, " - "cannot store!\n", - pdb_get_username(sampass))); - ldap_mods_free(*mods, True); - return False; - } - } else { - DEBUG(0, ("NO user RID specified on account %s, " - "cannot store!\n", pdb_get_username(sampass))); - ldap_mods_free(*mods, True); - return False; - } - - /* now that we have figured out the RID, always store it, as - the schema requires it (either as a SID or a RID) */ - - if (!pdb_set_user_sid_from_rid(sampass, rid, PDB_CHANGED)) { - DEBUG(0, ("Could not store RID back onto SAM_ACCOUNT for user %s!\n", - pdb_get_username(sampass))); - ldap_mods_free(*mods, True); - return False; - } - } - /* only update the RID if we actually need to */ if (need_update(sampass, PDB_USERSID)) { @@ -2733,10 +2280,8 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met struct ldapsam_privates *ldap_state; uint32 alg_rid_base; pstring alg_rid_base_string; - uint32 low_idmap_uid, high_idmap_uid; - uint32 low_idmap_gid, high_idmap_gid; - LDAPMessage *result; - LDAPMessage *entry; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; DOM_SID ldap_domain_sid; DOM_SID secrets_domain_sid; pstring domain_sid_string; @@ -2748,14 +2293,17 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met (*pdb_method)->name = "ldapsam"; ldap_state = (*pdb_method)->private_data; - ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT; - ldap_state->permit_non_unix_accounts = False; + ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT; /* Try to setup the Domain Name, Domain SID, algorithmic rid base */ - - if (!NT_STATUS_IS_OK(nt_status = ldapsam_search_domain_info(ldap_state, &result, True))) { + + nt_status = smbldap_search_domain_info(ldap_state->smbldap_state, &result, + ldap_state->domain_name, True); + + if ( !NT_STATUS_IS_OK(nt_status) ) { DEBUG(2, ("WARNING: Could not get domain info, nor add one to the domain\n")); - DEBUGADD(2, ("Continuing on regardless, will be unable to allocate new users/groups, and will risk BDCs having inconsistant SIDs\n")); + DEBUGADD(2, ("Continuing on regardless, will be unable to allocate new users/groups, " + "and will risk BDCs having inconsistant SIDs\n")); sid_copy(&ldap_state->domain_sid, get_global_sam_sid()); return NT_STATUS_OK; } @@ -2796,21 +2344,6 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met } } ldap_msgfree(result); - - /* check for non-unix account ranges */ - - if (lp_idmap_uid(&low_idmap_uid, &high_idmap_uid) - && lp_idmap_gid(&low_idmap_gid, &high_idmap_gid)) - { - DEBUG(2, ("Enabling non-unix account ranges\n")); - - ldap_state->permit_non_unix_accounts = True; - - ldap_state->low_allocated_user_rid = fallback_pdb_uid_to_user_rid(low_idmap_uid); - ldap_state->high_allocated_user_rid = fallback_pdb_uid_to_user_rid(high_idmap_uid); - ldap_state->low_allocated_group_rid = pdb_gid_to_group_rid(low_idmap_gid); - ldap_state->high_allocated_group_rid = pdb_gid_to_group_rid(high_idmap_gid); - } return NT_STATUS_OK; } diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c index 0e7dd77b405..055e8e71bac 100644 --- a/source3/passdb/pdb_smbpasswd.c +++ b/source3/passdb/pdb_smbpasswd.c @@ -1,10 +1,10 @@ /* * Unix SMB/CIFS implementation. * SMB parameters and setup - * Copyright (C) Andrew Tridgell 1992-1998 - * Modified by Jeremy Allison 1995. - * Modified by Gerald (Jerry) Carter 2000-2001 - * Modified by Andrew Bartlett 2002. + * Copyright (C) Andrew Tridgell 1992-1998 + * Modified by Jeremy Allison 1995. + * Modified by Gerald (Jerry) Carter 2000-2001,2003 + * Modified by Andrew Bartlett 2002. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -34,14 +34,13 @@ struct smb_passwd { - BOOL smb_userid_set; /* this is actually the unix uid_t */ - uint32 smb_userid; /* this is actually the unix uid_t */ + uint32 smb_userid; /* this is actually the unix uid_t */ const char *smb_name; /* username string */ - const unsigned char *smb_passwd; /* Null if no password */ + const unsigned char *smb_passwd; /* Null if no password */ const unsigned char *smb_nt_passwd; /* Null if no password */ - uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */ + uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */ time_t pass_last_set_time; /* password last set time */ }; @@ -61,12 +60,6 @@ struct smbpasswd_privates /* retrive-once info */ const char *smbpasswd_file; - - BOOL permit_non_unix_accounts; - - uid_t low_nua_userid; - uid_t high_nua_userid; - }; enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE }; @@ -591,28 +584,6 @@ static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, str /* Ok - entry doesn't exist. We can add it */ - /* Account not in /etc/passwd hack!!! */ - if (!newpwd->smb_userid_set) { - if (!smbpasswd_state->permit_non_unix_accounts) { - DEBUG(0, ("add_smbfilepwd_entry: cannot add account %s without unix identity\n", newpwd->smb_name)); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return False; - } - - if (max_found_uid < smbpasswd_state->low_nua_userid) { - newpwd->smb_userid = smbpasswd_state->low_nua_userid; - newpwd->smb_userid_set = True; - } else if (max_found_uid >= smbpasswd_state->high_nua_userid) { - DEBUG(0, ("add_smbfilepwd_entry: cannot add machine %s, no uids are free! \n", newpwd->smb_name)); - endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); - return False; - } else { - newpwd->smb_userid = max_found_uid + 1; - newpwd->smb_userid_set = True; - } - } - - /* Create a new smb passwd entry and set it to the given password. */ /* * The add user write needs to be atomic - so get the fd from @@ -1149,12 +1120,10 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas DEBUG(0, ("Could not find gest account via getpwnam()! (%s)\n", lp_guestaccount())); return False; } - smb_pw->smb_userid_set = True; smb_pw->smb_userid=passwd->pw_uid; passwd_free(&passwd); } else if (fallback_pdb_rid_is_user(rid)) { - smb_pw->smb_userid_set = True; smb_pw->smb_userid=fallback_pdb_user_rid_to_uid(rid); } else { DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n")); @@ -1170,25 +1139,6 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass); smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass); -#if 0 - /* - * ifdef'out by JFM on 11/29/2001. - * this assertion is no longer valid - * and I don't understand the goal - * and doing the same thing with the group mapping code - * is hairy ! - * - * We just have the RID, in which SID is it valid ? - * our domain SID ? well known SID ? local SID ? - */ - - if (gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) { - DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n")); - DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass))); - return False; - } -#endif - return True; } @@ -1204,49 +1154,28 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n")); return False; } - - pwfile = getpwnam_alloc(pw_buf->smb_name); - if (pwfile == NULL) { - if ((smbpasswd_state->permit_non_unix_accounts) - && (pw_buf->smb_userid >= smbpasswd_state->low_nua_userid) - && (pw_buf->smb_userid <= smbpasswd_state->high_nua_userid)) { - pdb_set_user_sid_from_rid(sam_pass, fallback_pdb_uid_to_user_rid (pw_buf->smb_userid), PDB_SET); - - /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. - - This was down the bottom for machines, but it looks pretty good as - a general default for non-unix users. --abartlet 2002-01-08 - */ - pdb_set_group_sid_from_rid (sam_pass, DOMAIN_GROUP_RID_USERS, PDB_SET); - pdb_set_username (sam_pass, pw_buf->smb_name, PDB_SET); - pdb_set_domain (sam_pass, get_global_sam_name(), PDB_DEFAULT); + /* verify the user account exists */ - } else { - DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid %u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid)); - return False; - } - } else { - if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) { + if ( !(pwfile = getpwnam_alloc(pw_buf->smb_name)) ) { + DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid " + "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid)); return False; - } - - passwd_free(&pwfile); } + if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) + return False; + + passwd_free(&pwfile); + + /* set remaining fields */ + pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET); pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET); pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET); pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET); pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET); -#if 0 /* JERRY */ - /* the smbpasswd format doesn't have a must change time field, so - we can't get this right. The best we can do is to set this to - some time in the future. 21 days seems as reasonable as any other value :) - */ - pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE, PDB_DEFAULT); -#endif return True; } @@ -1558,11 +1487,6 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m (*pdb_method)->free_private_data = free_private_data; - if (lp_idmap_uid(&privates->low_nua_userid, &privates->high_nua_userid)) { - DEBUG(3, ("idmap uid range defined, non unix accounts enabled\n")); - privates->permit_non_unix_accounts = True; - } - return NT_STATUS_OK; } diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index a166697b4bc..6f5d348ce13 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -1,11 +1,11 @@ /* * Unix SMB/CIFS implementation. * SMB parameters and setup - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Simo Sorce 2000-2002 - * Copyright (C) Gerald Carter 2000 - * Copyright (C) Jeremy Allison 2001 - * Copyright (C) Andrew Bartlett 2002 + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Simo Sorce 2000-2002 + * Copyright (C) Gerald Carter 2000 + * Copyright (C) Jeremy Allison 2001 + * Copyright (C) Andrew Bartlett 2002 * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -48,13 +48,6 @@ struct tdbsam_privates { /* retrive-once info */ const char *tdbsam_location; - - BOOL permit_non_unix_accounts; - - BOOL algorithmic_rids; - - uint32 low_nua_rid; - uint32 high_nua_rid; }; /*************************************************************** @@ -342,61 +335,31 @@ static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, fstring name; BOOL ret = True; uint32 user_rid; - BOOL tdb_ret; /* invalidate the existing TDB iterator if it is open */ + if (tdb_state->passwd_tdb) { tdb_close(tdb_state->passwd_tdb); tdb_state->passwd_tdb = NULL; } /* open the account TDB passwd*/ + pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600); - if (!pwd_tdb) - { - DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location)); + + if (!pwd_tdb) { + DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", + tdb_state->tdbsam_location)); return False; } if (!pdb_get_group_rid(newpwd)) { - DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",pdb_get_username(newpwd))); + DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n", + pdb_get_username(newpwd))); ret = False; goto done; } - /* if flag == TDB_INSERT then make up a new RID else throw an error. */ - if (!(user_rid = pdb_get_user_rid(newpwd))) { - if ((flag & TDB_INSERT) && tdb_state->permit_non_unix_accounts) { - uint32 lowrid, highrid; - if (!pdb_get_free_rid_range(&lowrid, &highrid)) { - /* should never happen */ - DEBUG(0, ("tdbsam: something messed up, no high/low rids but nua enabled ?!\n")); - ret = False; - goto done; - } - user_rid = lowrid; - tdb_ret = tdb_change_uint32_atomic(pwd_tdb, "RID_COUNTER", &user_rid, RID_MULTIPLIER); - if (!tdb_ret) { - ret = False; - goto done; - } - if (user_rid > highrid) { - DEBUG(0, ("tdbsam: no NUA rids available, cannot add user %s!\n", pdb_get_username(newpwd))); - ret = False; - goto done; - } - if (!pdb_set_user_sid_from_rid(newpwd, user_rid, PDB_CHANGED)) { - DEBUG(0, ("tdbsam: not able to set new allocated user RID into sam account!\n")); - ret = False; - goto done; - } - } else { - DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a RID\n",pdb_get_username(newpwd))); - ret = False; - goto done; - } - } - /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */ if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) { DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n")); @@ -531,7 +494,6 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth { NTSTATUS nt_status; struct tdbsam_privates *tdb_state; - uid_t low_nua_uid, high_nua_uid; if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { return nt_status; @@ -569,19 +531,6 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth (*pdb_method)->free_private_data = free_private_data; - if (lp_idmap_uid(&low_nua_uid, &high_nua_uid)) { - DEBUG(3, ("idmap uid range defined, non unix accounts enabled\n")); - - tdb_state->permit_non_unix_accounts = True; - - tdb_state->low_nua_rid=fallback_pdb_uid_to_user_rid(low_nua_uid); - - tdb_state->high_nua_rid=fallback_pdb_uid_to_user_rid(high_nua_uid); - - } else { - tdb_state->algorithmic_rids = True; - } - return NT_STATUS_OK; } diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index dfa3a8b62e0..9324fd4765a 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -2204,6 +2204,7 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ uint32 acc_granted; SEC_DESC *psd; size_t sd_size; + uint32 new_rid = 0; /* check this, when giving away 'add computer to domain' privs */ uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS; @@ -2272,6 +2273,17 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ pw = Get_Pwnam(account); + /********************************************************************* + * HEADS UP! If we have to create a new user account, we have to get + * a new RID from somewhere. This used to be done by the passdb + * backend. It has been moved into idmap now. Since idmap is now + * wrapped up behind winbind, this means you have to run winbindd if you + * want new accounts to get a new RID when "enable rid algorithm = no". + * Tough. We now have a uniform way of allocating RIDs regardless + * of what ever passdb backend people may use. + * --jerry (2003-07-10) + *********************************************************************/ + if ( !pw ) { /* * we can't check both the ending $ and the acb_info. @@ -2293,15 +2305,17 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_ } else /* no add user script -- ask winbindd to do it */ { - if ( !winbind_create_user( account ) ) - DEBUG(3,("_api_samr_create_user: winbind_create_user(%s) failed\n", account)); + if ( !winbind_create_user( account, &new_rid ) ) { + DEBUG(3,("_api_samr_create_user: winbind_create_user(%s) failed\n", + account)); + } } } - /* implicit call to getpwnam() next */ + /* implicit call to getpwnam() next. we have a valid SID coming out of this call */ - if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account)) ) + if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account, new_rid)) ) return nt_status; pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED); @@ -3711,12 +3725,25 @@ static int smb_delete_user(const char *unix_user) pstring del_script; int ret; + /* try winbindd first since it is impossible to determine where + a user came from via NSS. Try the delete user script if this fails + meaning the user did not exist in winbindd's list of accounts */ + + if ( winbind_delete_user( unix_user ) ) { + DEBUG(3,("winbind_delete_user: removed user (%s)\n", unix_user)); + return 0; + } + + + /* fall back to 'delete user script' */ + pstrcpy(del_script, lp_deluser_script()); if (! *del_script) return -1; all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); ret = smbrun(del_script,NULL); DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); + return ret; } diff --git a/source3/sam/idmap.c b/source3/sam/idmap.c index 1db89eba24f..7a8f270e15a 100644 --- a/source3/sam/idmap.c +++ b/source3/sam/idmap.c @@ -252,7 +252,7 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type) } /************************************************************************** - Get ID from SID. This can create a mapping for a SID to a POSIX id. + Alloocate a new UNIX uid/gid **************************************************************************/ NTSTATUS idmap_allocate_id(unid_t *id, int id_type) @@ -265,6 +265,19 @@ NTSTATUS idmap_allocate_id(unid_t *id, int id_type) return cache_map->allocate_id( id, id_type ); } +/************************************************************************** + Alloocate a new RID +**************************************************************************/ + +NTSTATUS idmap_allocate_rid(uint32 *rid, int type) +{ + /* we have to allocate from the authoritative backend */ + + if ( remote_map ) + return remote_map->allocate_rid( rid, type ); + + return cache_map->allocate_rid( rid, type ); +} /************************************************************************** Shutdown maps. diff --git a/source3/sam/idmap_ldap.c b/source3/sam/idmap_ldap.c index 2901b1fc499..9a1ee039d0c 100644 --- a/source3/sam/idmap_ldap.c +++ b/source3/sam/idmap_ldap.c @@ -42,7 +42,11 @@ struct ldap_idmap_state { struct smbldap_state *smbldap_state; TALLOC_CTX *mem_ctx; - /* struct ldap_idmap_state *prev, *next; */ + uint32 low_allocated_user_rid; + uint32 high_allocated_user_rid; + uint32 low_allocated_group_rid; + uint32 high_allocated_group_rid; + }; #define LDAP_MAX_ALLOC_ID 128 /* number tries while allocating @@ -56,6 +60,282 @@ static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, int id static NTSTATUS ldap_idmap_close(void); +/********************************************************************** + Even if the sambaDomain attribute in LDAP tells us that this RID is + safe to use, always check before use. +*********************************************************************/ + +static BOOL sid_in_use(struct ldap_idmap_state *state, + const DOM_SID *sid, int *error) +{ + fstring filter; + fstring sid_string; + LDAPMessage *result = NULL; + int count; + int rc; + char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL}; + + slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid)); + + rc = smbldap_search_suffix(state->smbldap_state, + filter, sid_attr, &result); + + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n", + sid_string, ld_error)); + SAFE_FREE(ld_error); + + *error = rc; + return True; + } + + if ((count = ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) { + DEBUG(3, ("Sid %s already in use - trying next RID\n", + sid_string)); + ldap_msgfree(result); + return True; + } + + ldap_msgfree(result); + + /* good, sid is not in use */ + return False; +} + +/********************************************************************** + Set the new nextRid attribute, and return one we can use. + + This also checks that this RID is actually free - in case the admin + manually stole it :-). +*********************************************************************/ +static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid, + int rid_type) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + int rc; + LDAPMessage *domain_result = NULL; + LDAPMessage *entry = NULL; + char *dn; + LDAPMod **mods = NULL; + fstring old_rid_string; + fstring next_rid_string; + fstring algorithmic_rid_base_string; + uint32 next_rid; + uint32 alg_rid_base; + int attempts = 0; + char *ld_error = NULL; + + while (attempts < 10) + { + if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state, + &domain_result, get_global_sam_name(), True))) + { + return ret; + } + + entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result); + if (!entry) { + DEBUG(0, ("Could not get domain info entry\n")); + ldap_msgfree(domain_result); + return ret; + } + + if ((dn = ldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) { + DEBUG(0, ("Could not get domain info DN\n")); + ldap_msgfree(domain_result); + return ret; + } + + /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and + algorithmic_rid_base. The other two are to avoid stomping on the + different sets of algorithmic RIDs */ + + if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), + algorithmic_rid_base_string)) + { + + alg_rid_base = (uint32)atol(algorithmic_rid_base_string); + } else { + alg_rid_base = algorithmic_rid_base(); + /* Try to make the modification atomically by enforcing the + old value in the delete mod. */ + slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base); + smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), + algorithmic_rid_base_string); + } + + next_rid = 0; + + if (alg_rid_base > BASE_RID) { + /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we + can allocate to new users */ + if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), + old_rid_string)) + { + *rid = (uint32)atol(old_rid_string); + } else { + *rid = BASE_RID; + } + + next_rid = *rid+1; + if (next_rid >= alg_rid_base) { + return NT_STATUS_UNSUCCESSFUL; + } + + slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid); + + /* Try to make the modification atomically by enforcing the + old value in the delete mod. */ + smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), + next_rid_string); + } + + if (!next_rid) { /* not got one already */ + switch (rid_type) { + case USER_RID_TYPE: + if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), + old_rid_string)) + { + + *rid = (uint32)atol(old_rid_string); + + } else { + *rid = state->low_allocated_user_rid; + } + break; + case GROUP_RID_TYPE: + if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), + old_rid_string)) + { + *rid = (uint32)atol(old_rid_string); + } else { + *rid = state->low_allocated_group_rid; + } + break; + } + + /* This is the core of the whole routine. If we had + scheme-style closures, there would be a *lot* less code + duplication... */ + + next_rid = *rid+RID_MULTIPLIER; + slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid); + + switch (rid_type) { + case USER_RID_TYPE: + if (next_rid > state->high_allocated_user_rid) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* Try to make the modification atomically by enforcing the + old value in the delete mod. */ + smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), + next_rid_string); + break; + + case GROUP_RID_TYPE: + if (next_rid > state->high_allocated_group_rid) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* Try to make the modification atomically by enforcing the + old value in the delete mod. */ + smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), + next_rid_string); + break; + } + } + + if ((rc = ldap_modify_s(state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) { + DOM_SID dom_sid; + DOM_SID sid; + pstring domain_sid_string; + int error = 0; + + if (!smbldap_get_single_attribute(state->smbldap_state->ldap_struct, domain_result, + get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), + domain_sid_string)) + { + ldap_mods_free(mods, True); + ldap_memfree(dn); + ldap_msgfree(domain_result); + return ret; + } + + if (!string_to_sid(&dom_sid, domain_sid_string)) { + ldap_mods_free(mods, True); + ldap_memfree(dn); + ldap_msgfree(domain_result); + return ret; + } + + ldap_mods_free(mods, True); + mods = NULL; + ldap_memfree(dn); + ldap_msgfree(domain_result); + + sid_copy(&sid, &dom_sid); + sid_append_rid(&sid, *rid); + + /* check RID is not in use */ + if (sid_in_use(state, &sid, &error)) { + if (error) { + return ret; + } + continue; + } + + return NT_STATUS_OK; + } + + ld_error = NULL; + ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL")); + SAFE_FREE(ld_error); + + ldap_mods_free(mods, True); + mods = NULL; + + ldap_memfree(dn); + dn = NULL; + + ldap_msgfree(domain_result); + domain_result = NULL; + + { + /* Sleep for a random timeout */ + unsigned sleeptime = (sys_random()*sys_getpid()*attempts); + attempts += 1; + + sleeptime %= 100; + msleep(sleeptime); + } + } + + DEBUG(0, ("Failed to set new RID\n")); + return ret; +} + + +/***************************************************************************** + Allocate a new RID +*****************************************************************************/ + +static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type) +{ + return ldap_next_rid( &ldap_state, rid, rid_type ); +} + /***************************************************************************** Allocate a new uid or gid *****************************************************************************/ @@ -675,6 +955,7 @@ static void ldap_idmap_status(void) static struct idmap_methods ldap_methods = { ldap_idmap_init, + ldap_allocate_rid, ldap_allocate_id, ldap_get_sid_from_id, ldap_get_id_from_sid, diff --git a/source3/sam/idmap_tdb.c b/source3/sam/idmap_tdb.c index 4643b7db59d..7f8dce1f1a1 100644 --- a/source3/sam/idmap_tdb.c +++ b/source3/sam/idmap_tdb.c @@ -59,7 +59,45 @@ TDB_CONTEXT *idmap_tdb_handle( void ) return NULL; } -/* Allocate either a user or group id from the pool */ +/********************************************************************** + allocate a new RID; We don't care if is a user or group +**********************************************************************/ + +static NTSTATUS db_allocate_rid(uint32 *rid, int rid_type) +{ + uint32 lowrid, highrid; + uint32 tmp_rid; + + /* can't handle group rids right now. This is such a mess.... */ + + if ( rid_type == GROUP_RID_TYPE ) + return NT_STATUS_UNSUCCESSFUL; + + /* cannot fail since idmap is only called winbindd */ + + idmap_get_free_rid_range( &lowrid, &highrid ); + + tmp_rid = lowrid; + + if ( !tdb_change_uint32_atomic(idmap_tdb, "RID_COUNTER", &tmp_rid, RID_MULTIPLIER) ) { + DEBUG(3,("db_allocate_rid: Failed to locate next rid record in idmap db\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + if ( tmp_rid > highrid ) { + DEBUG(0, ("db_allocate_rid: no RIDs available!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + *rid = tmp_rid; + + return NT_STATUS_OK; +} + +/********************************************************************** + Allocate either a user or group id from the pool +**********************************************************************/ + static NTSTATUS db_allocate_id(unid_t *id, int id_type) { BOOL ret; @@ -609,6 +647,7 @@ static void db_idmap_status(void) static struct idmap_methods db_methods = { db_idmap_init, + db_allocate_rid, db_allocate_id, db_get_sid_from_id, db_get_id_from_sid, diff --git a/source3/sam/idmap_util.c b/source3/sam/idmap_util.c index 94de30a5ce5..f767cc898c7 100644 --- a/source3/sam/idmap_util.c +++ b/source3/sam/idmap_util.c @@ -22,6 +22,120 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP +/********************************************************************** +**********************************************************************/ + +BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high) +{ + uid_t u_low, u_high; + gid_t g_low, g_high; + + if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) { + return False; + } + + *low = (u_low < g_low) ? u_low : g_low; + *high = (u_high < g_high) ? u_high : g_high; + + return True; +} + +/****************************************************************** + Get the the non-algorithmic RID range if idmap range are defined +******************************************************************/ + +BOOL idmap_get_free_rid_range(uint32 *low, uint32 *high) +{ + uint32 id_low, id_high; + + if (!lp_enable_rid_algorithm()) { + *low = BASE_RID; + *high = (uint32)-1; + } + + if (!idmap_get_free_ugid_range(&id_low, &id_high)) { + return False; + } + + *low = fallback_pdb_uid_to_user_rid(id_low); + if (fallback_pdb_user_rid_to_uid((uint32)-1) < id_high) { + *high = (uint32)-1; + } else { + *high = fallback_pdb_uid_to_user_rid(id_high); + } + + return True; +} + +/********************************************************************** + Get the free RID base if idmap is configured, otherwise return 0 +**********************************************************************/ + +uint32 idmap_get_free_rid_base(void) +{ + uint32 low, high; + if (idmap_get_free_rid_range(&low, &high)) { + return low; + } + return 0; +} + +/********************************************************************** +**********************************************************************/ + +BOOL idmap_check_ugid_is_in_free_range(uint32 id) +{ + uint32 low, high; + + if (!idmap_get_free_ugid_range(&low, &high)) { + return False; + } + if (id < low || id > high) { + return False; + } + return True; +} + +/********************************************************************** +**********************************************************************/ + +BOOL idmap_check_rid_is_in_free_range(uint32 rid) +{ + uint32 low, high; + + if (!idmap_get_free_rid_range(&low, &high)) { + return False; + } + if (rid < algorithmic_rid_base()) { + return True; + } + + if (rid < low || rid > high) { + return False; + } + + return True; +} + +/********************************************************************** + if it is a foreign SID or if the SID is in the free range, return true +**********************************************************************/ + +BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid) +{ + if (sid_compare_domain(get_global_sam_sid(), sid) == 0) { + + uint32 rid; + + if (sid_peek_rid(sid, &rid)) { + return idmap_check_rid_is_in_free_range(rid); + } + + return False; + } + + return True; +} /***************************************************************** Returns SID pointer. diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c index 4b31c061f39..31535f79457 100644 --- a/source3/utils/net_rpc_samsync.c +++ b/source3/utils/net_rpc_samsync.c @@ -444,7 +444,9 @@ fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta) } else { DEBUG(8,("fetch_account_info: no add user/machine script. Asking winbindd\n")); - if ( !winbind_create_user( account ) ) + + /* don't need a RID allocated since the user already has a SID */ + if ( !winbind_create_user( account, NULL ) ) DEBUG(4,("fetch_account_info: winbind_create_user() failed\n")); } diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index b79972aa35e..96d0d3c057f 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -350,7 +350,7 @@ static int new_user (struct pdb_context *in, const char *username, NTSTATUS nt_status; char *password1, *password2, *staticpass; - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pwent, username))) { + if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pwent, username, 0))) { DEBUG(0, ("could not create account to add new user %s\n", username)); return -1; } |