diff options
-rw-r--r-- | source3/include/passdb.h | 23 | ||||
-rw-r--r-- | source3/include/smb_macros.h | 10 | ||||
-rw-r--r-- | source3/passdb/pdb_interface.c | 358 | ||||
-rw-r--r-- | source3/utils/net.c | 72 |
4 files changed, 415 insertions, 48 deletions
diff --git a/source3/include/passdb.h b/source3/include/passdb.h index 2c63271492..624f0c5fea 100644 --- a/source3/include/passdb.h +++ b/source3/include/passdb.h @@ -480,4 +480,27 @@ struct pdb_init_function_entry { enum sql_search_field { SQL_SEARCH_NONE = 0, SQL_SEARCH_USER_SID = 1, SQL_SEARCH_USER_NAME = 2}; +struct samr_displayentry { + uint32 rid; + uint16 acct_flags; + const char *account_name; + const char *fullname; + const char *description; +}; + +enum pdb_search_type { + PDB_USER_SEARCH, + PDB_GROUP_SEARCH, + PDB_ALIAS_SEARCH +}; + +struct pdb_search { + TALLOC_CTX *mem_ctx; + enum pdb_search_type type; + struct samr_displayentry *cache; + uint32 cache_size; + BOOL search_ended; + void *private; +}; + #endif /* _PASSDB_H */ diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index 1076bd53e8..ab4ee5ee73 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -351,4 +351,14 @@ copy an IP address from one buffer to another #endif +#define ADD_TO_ARRAY(mem_ctx, type, elem, array, num) \ +do { \ + *(array) = ((mem_ctx) != NULL) ? \ + TALLOC_REALLOC_ARRAY(mem_ctx, (*(array)), type, (*(num))+1) : \ + SMB_REALLOC_ARRAY((*(array)), type, (*(num))+1); \ + SMB_ASSERT((*(array)) != NULL); \ + (*(array))[*(num)] = (elem); \ + (*(num)) += 1; \ +} while (0) + #endif /* _SMB_MACROS_H */ diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index 730569ec4b..301dc101eb 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -1586,3 +1586,361 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) return NT_STATUS_OK; } + +struct pdb_search *pdb_search_users(uint16 acct_flags); +struct pdb_search *pdb_search_groups(void); +struct pdb_search *pdb_search_aliases(const DOM_SID *sid); +uint32 pdb_search_entries(struct pdb_search *search, uint32 start_idx, uint32 max_entries, struct samr_displayentry **result); +void pdb_search_destroy(struct pdb_search *search); + +static struct pdb_search *pdb_search_init(enum pdb_search_type type) +{ + TALLOC_CTX *mem_ctx; + struct pdb_search *result; + + mem_ctx = talloc_init("pdb_search"); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_init failed\n")); + return NULL; + } + + result = TALLOC_P(mem_ctx, struct pdb_search); + if (result == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } + + result->mem_ctx = mem_ctx; + result->type = type; + result->cache = NULL; + result->cache_size = 0; + result->search_ended = False; + + return result; +} + +static void fill_displayentry(TALLOC_CTX *mem_ctx, uint32 rid, + uint16 acct_flags, + const char *account_name, + const char *fullname, + const char *description, + struct samr_displayentry *entry) +{ + entry->rid = rid; + entry->acct_flags = acct_flags; + + if (account_name != NULL) + entry->account_name = talloc_strdup(mem_ctx, account_name); + + if (fullname != NULL) + entry->fullname = talloc_strdup(mem_ctx, fullname); + + if (description != NULL) + entry->description = talloc_strdup(mem_ctx, description); +} + +static BOOL user_search_in_progress = False; +struct user_search { + uint16 acct_flags; +}; + +struct pdb_search *pdb_search_users(uint16 acct_flags) +{ + struct pdb_search *result; + struct user_search *state; + + if (user_search_in_progress) { + DEBUG(1, ("user search in progress\n")); + return NULL; + } + + if (!pdb_setsampwent(False, acct_flags)) + return NULL; + + user_search_in_progress = True; + + result = pdb_search_init(PDB_USER_SEARCH); + if (result == NULL) + return NULL; + + state = TALLOC_P(result->mem_ctx, struct user_search); + if (state == NULL) { + DEBUG(0, ("talloc failed\n")); + talloc_destroy(result->mem_ctx); + return NULL; + } + + state->acct_flags = acct_flags; + + result->private = state; + return result; +} + +static BOOL pdb_search_entry_users(struct pdb_search *s, TALLOC_CTX *mem_ctx, + struct samr_displayentry *entry) +{ + struct user_search *state = s->private; + SAM_ACCOUNT *user = NULL; + NTSTATUS status; + + next: + status = pdb_init_sam(&user); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Could not pdb_init_sam\n")); + return False; + } + + if (!pdb_getsampwent(user)) { + pdb_free_sam(&user); + return False; + } + + if ((state->acct_flags != 0) && + ((pdb_get_acct_ctrl(user) & state->acct_flags) == 0)) { + pdb_free_sam(&user); + goto next; + } + + fill_displayentry(mem_ctx, pdb_get_user_rid(user), + pdb_get_acct_ctrl(user), pdb_get_username(user), + pdb_get_fullname(user), pdb_get_acct_desc(user), + entry); + + pdb_free_sam(&user); + return True; +} + +static void pdb_search_end_users(struct pdb_search *search) +{ + pdb_endsampwent(); + user_search_in_progress = False; +} + +struct group_search { + GROUP_MAP *groups; + int num_groups, current_group; +}; + +struct pdb_search *pdb_search_groups(void) +{ + struct pdb_search *result; + struct group_search *state; + + result = pdb_search_init(PDB_GROUP_SEARCH); + if (result == NULL) + return NULL; + + state = TALLOC_P(result->mem_ctx, struct group_search); + if (state == NULL) { + DEBUG(0, ("talloc failed\n")); + talloc_destroy(result->mem_ctx); + return NULL; + } + + if (!pdb_enum_group_mapping(SID_NAME_DOM_GRP, &state->groups, + &state->num_groups, True)) { + DEBUG(0, ("Could not enum groups\n")); + talloc_destroy(result->mem_ctx); + return NULL; + } + + state->current_group = 0; + result->private = state; + return result; +} + +static BOOL pdb_search_entry_group(struct pdb_search *s, TALLOC_CTX *mem_ctx, + struct samr_displayentry *entry) +{ + struct group_search *state = s->private; + uint32 rid; + GROUP_MAP *map = &state->groups[state->current_group]; + + if (state->current_group == state->num_groups) + return False; + + sid_peek_rid(&map->sid, &rid); + + fill_displayentry(mem_ctx, rid, 0, map->nt_name, NULL, map->comment, + entry); + + state->current_group += 1; + return True; +} + +static void pdb_search_end_groups(struct pdb_search *search) +{ + struct group_search *state = search->private; + SAFE_FREE(state->groups); +} + +struct alias_search { + GROUP_MAP *aliases; + int num_aliases, current_alias; +}; + +struct pdb_search *pdb_search_aliases(const DOM_SID *sid) +{ + struct pdb_search *result; + struct alias_search *state; + enum SID_NAME_USE type = SID_NAME_UNKNOWN; + DOM_SID builtin_sid; + + if (sid_equal(sid, get_global_sam_sid())) + type = SID_NAME_ALIAS; + + string_to_sid(&builtin_sid, "S-1-5-32"); + + if (sid_equal(sid, &builtin_sid)) + type = SID_NAME_WKN_GRP; + + if (type == SID_NAME_UNKNOWN) { + DEBUG(3, ("unknown domain sid: %s\n", sid_string_static(sid))); + return NULL; + } + + result = pdb_search_init(PDB_ALIAS_SEARCH); + if (result == NULL) + return NULL; + + state = TALLOC_P(result->mem_ctx, struct alias_search); + if (state == NULL) { + DEBUG(0, ("talloc failed\n")); + talloc_destroy(result->mem_ctx); + return NULL; + } + + if (!pdb_enum_group_mapping(type, &state->aliases, + &state->num_aliases, False)) { + DEBUG(0, ("Could not enum aliases\n")); + talloc_destroy(result->mem_ctx); + return NULL; + } + + state->current_alias = 0; + result->private = state; + return result; +} + +static BOOL pdb_search_entry_alias(struct pdb_search *s, TALLOC_CTX *mem_ctx, + struct samr_displayentry *entry) +{ + struct alias_search *state = s->private; + uint32 rid; + GROUP_MAP *map = &state->aliases[state->current_alias]; + + if (state->current_alias == state->num_aliases) + return False; + + sid_peek_rid(&map->sid, &rid); + + fill_displayentry(mem_ctx, rid, 0, map->nt_name, NULL, map->comment, + entry); + + state->current_alias += 1; + return True; +} + +static void pdb_search_end_aliases(struct pdb_search *search) +{ + struct alias_search *state = search->private; + SAFE_FREE(state->aliases); +} + +static BOOL pdb_search_entry(struct pdb_search *search, TALLOC_CTX *mem_ctx, + struct samr_displayentry *entry) +{ + BOOL result = False; + switch (search->type) { + case PDB_USER_SEARCH: + result = pdb_search_entry_users(search, mem_ctx, entry); + break; + case PDB_GROUP_SEARCH: + result = pdb_search_entry_group(search, mem_ctx, entry); + break; + case PDB_ALIAS_SEARCH: + result = pdb_search_entry_alias(search, mem_ctx, entry); + break; + default: + DEBUG(0, ("unknown search type: %d\n", search->type)); + break; + } + return result; +} + +static void pdb_search_end(struct pdb_search *search) +{ + switch (search->type) { + case PDB_USER_SEARCH: + pdb_search_end_users(search); + break; + case PDB_GROUP_SEARCH: + pdb_search_end_groups(search); + break; + case PDB_ALIAS_SEARCH: + pdb_search_end_aliases(search); + break; + default: + DEBUG(0, ("unknown search type: %d\n", search->type)); + break; + } +} + +static struct samr_displayentry *pdb_search_getentry(struct pdb_search *search, + uint32 idx) +{ + if (idx < search->cache_size) + return &search->cache[idx]; + + if (search->search_ended) + return NULL; + + while (idx >= search->cache_size) { + struct samr_displayentry entry; + + if (!pdb_search_entry(search, search->mem_ctx, &entry)) { + pdb_search_end(search); + search->search_ended = True; + break; + } + + ADD_TO_ARRAY(search->mem_ctx, struct samr_displayentry, + entry, &search->cache, &search->cache_size); + } + + return (search->cache_size > idx) ? &search->cache[idx] : NULL; +} + +uint32 pdb_search_entries(struct pdb_search *search, + uint32 start_idx, uint32 max_entries, + struct samr_displayentry **result) +{ + struct samr_displayentry *end_entry; + uint32 end_idx = start_idx+max_entries-1; + + /* The first entry needs to be searched after the last. Otherwise the + * first entry might have moved due to a realloc during the search for + * the last entry. */ + + end_entry = pdb_search_getentry(search, end_idx); + *result = pdb_search_getentry(search, start_idx); + + if (end_entry != NULL) + return max_entries; + + if (start_idx >= search->cache_size) + return 0; + + return search->cache_size - start_idx; +} + +void pdb_search_destroy(struct pdb_search *search) +{ + if (search == NULL) + return; + + if (!search->search_ended) + pdb_search_end(search); + + talloc_destroy(search->mem_ctx); +} diff --git a/source3/utils/net.c b/source3/utils/net.c index ef992b1014..61c366710c 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -632,62 +632,38 @@ static int net_afs(int argc, const char **argv) #endif /* WITH_FAKE_KASERVER */ -static uint32 get_maxrid(void) +static BOOL search_maxrid(struct pdb_search *search, const char *type, + uint32 *max_rid) { - SAM_ACCOUNT *pwd = NULL; - uint32 max_rid = 0; - GROUP_MAP *map = NULL; - int num_entries = 0; - int i; - - if (!pdb_setsampwent(False, 0)) { - DEBUG(0, ("get_maxrid: Unable to open passdb.\n")); - return 0; - } + struct samr_displayentry *entries; + uint32 i, num_entries; - for (; (NT_STATUS_IS_OK(pdb_init_sam(&pwd))) - && pdb_getsampwent(pwd) == True; pwd=NULL) { - uint32 rid; - - if (!sid_peek_rid(pdb_get_user_sid(pwd), &rid)) { - DEBUG(0, ("can't get RID for user '%s'\n", - pdb_get_username(pwd))); - pdb_free_sam(&pwd); - continue; - } - - if (rid > max_rid) - max_rid = rid; - - DEBUG(1,("%d is user '%s'\n", rid, pdb_get_username(pwd))); - pdb_free_sam(&pwd); + if (search == NULL) { + d_printf("get_maxrid: Could not search %s\n", type); + return False; } - pdb_endsampwent(); - pdb_free_sam(&pwd); - - if (!pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, - ENUM_ONLY_MAPPED)) - return max_rid; - - for (i = 0; i < num_entries; i++) { - uint32 rid; + num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries); + for (i=0; i<num_entries; i++) + *max_rid = MAX(*max_rid, entries[i].rid); + pdb_search_destroy(search); + return True; +} - if (!sid_peek_check_rid(get_global_sam_sid(), &map[i].sid, - &rid)) { - DEBUG(3, ("skipping map for group '%s', SID %s\n", - map[i].nt_name, - sid_string_static(&map[i].sid))); - continue; - } - DEBUG(1,("%d is group '%s'\n", rid, map[i].nt_name)); +static uint32 get_maxrid(void) +{ + uint32 max_rid = 0; - if (rid > max_rid) - max_rid = rid; - } + if (!search_maxrid(pdb_search_users(0), "users", &max_rid)) + return 0; - SAFE_FREE(map); + if (!search_maxrid(pdb_search_groups(), "groups", &max_rid)) + return 0; + if (!search_maxrid(pdb_search_aliases(get_global_sam_sid()), + "aliases", &max_rid)) + return 0; + return max_rid; } |