diff options
Diffstat (limited to 'source/nsswitch/winbindd_util.c')
-rw-r--r-- | source/nsswitch/winbindd_util.c | 850 |
1 files changed, 687 insertions, 163 deletions
diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index 06804b3b43f..c0c7b6ae0dd 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -1,5 +1,5 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. Winbind daemon for ntdom nss module @@ -36,204 +36,418 @@ * * Correct code should never look at a field that has this value. **/ - static const fstring name_deadbeef = "<deadbeef>"; -/* The list of trusted domains. Note that the list can be deleted and - recreated using the init_domain_list() function so pointers to - individual winbindd_domain structures cannot be made. Keep a copy of - the domain name instead. */ -static struct winbindd_domain *_domain_list; +/* Globals for domain list stuff */ + +struct winbindd_domain *domain_list = NULL; + +/* Given a domain name, return the struct winbindd domain info for it + if it is actually working. */ -struct winbindd_domain *domain_list(void) +struct winbindd_domain *find_domain_from_name(char *domain_name) { - /* Initialise list */ + struct winbindd_domain *tmp; + + if (domain_list == NULL) + get_domain_info(); + + /* Search through list */ + + for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { + if (strcmp(domain_name, tmp->name) == 0) + return tmp; + } - if (!_domain_list) - init_domain_list(); + /* Not found */ - return _domain_list; + return NULL; } -/* Free all entries in the trusted domain list */ +/* Given a domain name, return the struct winbindd domain info for it */ -void free_domain_list(void) +struct winbindd_domain *find_domain_from_sid(DOM_SID *sid) { - struct winbindd_domain *domain = _domain_list; - - while(domain) { - struct winbindd_domain *next = domain->next; - - DLIST_REMOVE(_domain_list, domain); - SAFE_FREE(domain); - domain = next; + struct winbindd_domain *tmp; + + if (domain_list == NULL) + get_domain_info(); + + /* Search through list */ + + for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { + if (sid_equal(sid, &tmp->sid)) + return tmp; } + + /* Not found */ + + return NULL; } /* Add a trusted domain to our list of domains */ static struct winbindd_domain *add_trusted_domain(char *domain_name, - struct winbindd_methods *methods) + DOM_SID *domain_sid) { - struct winbindd_domain *domain; + struct winbindd_domain *domain, *tmp; - /* We can't call domain_list() as this function is called from - init_domain_list() and we'll get stuck in a loop. */ - - for (domain = _domain_list; domain; domain = domain->next) { - if (strcmp(domain_name, domain->name) == 0) { - DEBUG(3, ("domain %s already in domain list\n", - domain_name)); - return domain; + for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { + if (strcmp(domain_name, tmp->name) == 0) { + DEBUG(3, ("domain %s already in domain list\n", domain_name)); + return tmp; } } + DEBUG(1, ("adding domain %s\n", domain_name)); + /* Create new domain entry */ - - if ((domain = (struct winbindd_domain *) - malloc(sizeof(*domain))) == NULL) + + if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL) return NULL; /* Fill in fields */ ZERO_STRUCTP(domain); - fstrcpy(domain->name, domain_name); - domain->methods = methods; - domain->sequence_number = DOM_SEQUENCE_NONE; - domain->last_seq_check = 0; - + sid_copy(&domain->sid, domain_sid); + /* Link to domain list */ - DLIST_ADD(_domain_list, domain); + DLIST_ADD(domain_list, domain); return domain; } /* Look up global info for the winbind daemon */ -BOOL init_domain_list(void) +BOOL get_domain_info(void) { + uint32 enum_ctx = 0, num_doms = 0; + char **domains = NULL; + DOM_SID *sids = NULL, domain_sid; NTSTATUS result; + CLI_POLICY_HND *hnd; + int i; + fstring level5_dom; + BOOL rv = False; TALLOC_CTX *mem_ctx; - extern struct winbindd_methods cache_methods; - struct winbindd_domain *domain; - DOM_SID *dom_sids; - char **names; - int num_domains = 0; + + DEBUG(1, ("getting trusted domain list\n")); - if (!(mem_ctx = talloc_init_named("init_domain_list"))) + if (!(mem_ctx = talloc_init())) return False; - /* Free existing list */ + /* Add our workgroup - keep handle to look up trusted domains */ - free_domain_list(); + if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) + goto done; - /* Add ourselves as the first entry */ + result = cli_lsa_query_info_policy(hnd->cli, mem_ctx, + &hnd->pol, 0x05, level5_dom, &domain_sid); - domain = add_trusted_domain(lp_workgroup(), &cache_methods); + if (!NT_STATUS_IS_OK(result)) + goto done; - /* Now we *must* get the domain sid for our primary domain. Go into - a holding pattern until that is available */ + add_trusted_domain(lp_workgroup(), &domain_sid); + + /* Enumerate list of trusted domains */ - result = cache_methods.domain_sid(domain, &domain->sid); - while (!NT_STATUS_IS_OK(result)) { - sleep(10); - DEBUG(1,("Retrying startup domain sid fetch for %s\n", - domain->name)); - result = cache_methods.domain_sid(domain, &domain->sid); - } - - DEBUG(1,("Added domain %s (%s)\n", - domain->name, - sid_string_static(&domain->sid))); + if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) + goto done; - DEBUG(1, ("getting trusted domain list\n")); + result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx, + &hnd->pol, &enum_ctx, &num_doms, &domains, &sids); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Add each domain to the trusted domain list */ - result = cache_methods.trusted_domains(domain, mem_ctx, &num_domains, - &names, &dom_sids); + for(i = 0; i < num_doms; i++) + add_trusted_domain(domains[i], &sids[i]); - /* Add each domain to the trusted domain list */ - if (NT_STATUS_IS_OK(result)) { + rv = True; + + done: + + talloc_destroy(mem_ctx); + + return rv; +} + +/* Free global domain info */ + +void free_domain_info(void) +{ + struct winbindd_domain *domain; + + /* Free list of domains */ + + if (domain_list) { + struct winbindd_domain *next_domain; + + domain = domain_list; + + while(domain) { + next_domain = domain->next; + SAFE_FREE(domain); + domain = next_domain; + } + } +} + +/* Connect to a domain controller using get_any_dc_name() to discover + the domain name and sid */ + +BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain) +{ + fstring level5_dom; + uint32 enum_ctx = 0, num_doms = 0; + char **domains = NULL; + DOM_SID *sids = NULL; + CLI_POLICY_HND *hnd; + NTSTATUS result; + BOOL rv = False; + TALLOC_CTX *mem_ctx; + + DEBUG(1, ("looking up sid for domain %s\n", domain_name)); + + if (!(mem_ctx = talloc_init())) + return False; + + if (!(hnd = cm_get_lsa_handle(domain_name))) + goto done; + + /* Do a level 5 query info policy if we are looking up the SID for + our own domain. */ + + if (strequal(domain_name, lp_workgroup())) { + + result = cli_lsa_query_info_policy(hnd->cli, mem_ctx, + &hnd->pol, 0x05, level5_dom, + &domain->sid); + + rv = NT_STATUS_IS_OK(result); + goto done; + } + + /* Use lsaenumdomains to get sid for this domain */ + + result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx, &hnd->pol, + &enum_ctx, &num_doms, &domains, &sids); + + /* Look for domain name */ + + if (NT_STATUS_IS_OK(result) && domains && sids) { + BOOL found = False; int i; - for(i = 0; i < num_domains; i++) { - domain = add_trusted_domain(names[i], &cache_methods); - if (!domain) continue; - sid_copy(&domain->sid, &dom_sids[i]); - DEBUG(1,("Added domain %s (%s)\n", - domain->name, - sid_string_static(&domain->sid))); - - /* this primes the connection */ - cache_methods.domain_sid(domain, &domain->sid); + + for(i = 0; i < num_doms; i++) { + if (strequal(domain_name, domains[i])) { + sid_copy(&domain->sid, &sids[i]); + found = True; + break; + } } + + rv = found; + goto done; } + + rv = False; /* An error occured with a trusted domain */ + + done: talloc_destroy(mem_ctx); + + return rv; +} + +/* Store a SID in a domain indexed by name in the cache. */ + +static void store_sid_by_name_in_cache(fstring name, DOM_SID *sid, enum SID_NAME_USE type) +{ + fstring domain_str; + char *p; + struct winbindd_sid sid_val; + struct winbindd_domain *domain; + + /* Get name from domain. */ + fstrcpy( domain_str, name); + p = strchr(domain_str, '\\'); + if (p) + *p = '\0'; + + if ((domain = find_domain_from_name(domain_str)) == NULL) + return; + + sid_to_string(sid_val.sid, sid); + sid_val.type = (int)type; + + DEBUG(10,("store_sid_by_name_in_cache: storing cache entry %s -> SID %s\n", + name, sid_val.sid )); + + winbindd_store_sid_cache_entry(domain, name, &sid_val); +} + +/* Lookup a SID in a domain indexed by name in the cache. */ + +static BOOL winbindd_lookup_sid_by_name_in_cache(fstring name, DOM_SID *sid, enum SID_NAME_USE *type) +{ + fstring domain_str; + char *p; + struct winbindd_sid sid_ret; + struct winbindd_domain *domain; + + /* Get name from domain. */ + fstrcpy( domain_str, name); + p = strchr(domain_str, '\\'); + if (p) + *p = '\0'; + + if ((domain = find_domain_from_name(domain_str)) == NULL) + return False; + + if (!winbindd_fetch_sid_cache_entry(domain, name, &sid_ret)) + return False; + + string_to_sid( sid, sid_ret.sid); + *type = (enum SID_NAME_USE)sid_ret.type; + + DEBUG(10,("winbindd_lookup_sid_by_name_in_cache: Cache hit for name %s. SID = %s\n", + name, sid_ret.sid )); + return True; } -/* Given a domain name, return the struct winbindd domain info for it - if it is actually working. */ +/* Store a name in a domain indexed by SID in the cache. */ -struct winbindd_domain *find_domain_from_name(const char *domain_name) +static void store_name_by_sid_in_cache(DOM_SID *sid, fstring name, enum SID_NAME_USE type) { + fstring sid_str; + uint32 rid; + DOM_SID domain_sid; + struct winbindd_name name_val; struct winbindd_domain *domain; - /* Search through list */ + /* Split sid into domain sid and user rid */ + sid_copy(&domain_sid, sid); + sid_split_rid(&domain_sid, &rid); - for (domain = domain_list(); domain != NULL; domain = domain->next) { - if (strequal(domain_name, domain->name) || - strequal(domain_name, domain->full_name)) - return domain; - } + if ((domain = find_domain_from_sid(&domain_sid)) == NULL) + return; - /* Not found */ + sid_to_string(sid_str, sid); + fstrcpy( name_val.name, name ); + name_val.type = (int)type; - return NULL; + DEBUG(10,("store_name_by_sid_in_cache: storing cache entry SID %s -> %s\n", + sid_str, name_val.name )); + + winbindd_store_name_cache_entry(domain, sid_str, &name_val); } -/* Given a domain sid, return the struct winbindd domain info for it */ +/* Lookup a name in a domain indexed by SID in the cache. */ -struct winbindd_domain *find_domain_from_sid(DOM_SID *sid) +static BOOL winbindd_lookup_name_by_sid_in_cache(DOM_SID *sid, fstring name, enum SID_NAME_USE *type) { + fstring sid_str; + uint32 rid; + DOM_SID domain_sid; + struct winbindd_name name_ret; struct winbindd_domain *domain; - /* Search through list */ + /* Split sid into domain sid and user rid */ + sid_copy(&domain_sid, sid); + sid_split_rid(&domain_sid, &rid); - for (domain = domain_list(); domain != NULL; domain = domain->next) { - if (sid_compare_domain(sid, &domain->sid) == 0) - return domain; - } + if ((domain = find_domain_from_sid(&domain_sid)) == NULL) + return False; - /* Not found */ + sid_to_string(sid_str, sid); - return NULL; + if (!winbindd_fetch_name_cache_entry(domain, sid_str, &name_ret)) + return False; + + fstrcpy( name, name_ret.name ); + *type = (enum SID_NAME_USE)name_ret.type; + + DEBUG(10,("winbindd_lookup_name_by_sid_in_cache: Cache hit for SID = %s, name %s\n", + sid_str, name )); + + return True; } /* Lookup a sid in a domain from a name */ -BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, - const char *name, DOM_SID *sid, - enum SID_NAME_USE *type) +BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, enum SID_NAME_USE *type) { + int num_sids = 0, num_names = 1; + DOM_SID *sids = NULL; + uint32 *types = NULL; + CLI_POLICY_HND *hnd; NTSTATUS result; + TALLOC_CTX *mem_ctx; + BOOL rv = False; /* Don't bother with machine accounts */ if (name[strlen(name) - 1] == '$') return False; + /* First check cache. */ + if (winbindd_lookup_sid_by_name_in_cache(name, sid, type)) { + if (*type == SID_NAME_USE_NONE) + return False; /* Negative cache hit. */ + return True; + } + /* Lookup name */ - result = domain->methods->name_to_sid(domain, name, sid, type); + + if (!(mem_ctx = talloc_init())) + return False; + + if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) + goto done; + + result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, + num_names, (char **)&name, &sids, + &types, &num_sids); /* Return rid and type if lookup successful */ - if (!NT_STATUS_IS_OK(result)) { + + if (NT_STATUS_IS_OK(result)) { + + /* Return sid */ + + if ((sid != NULL) && (sids != NULL)) + sid_copy(sid, &sids[0]); + + /* Return name type */ + + if ((type != NULL) && (types != NULL)) + *type = types[0]; + + /* Store the forward and reverse map of this lookup in the cache. */ + store_sid_by_name_in_cache(name, &sids[0], types[0]); + store_name_by_sid_in_cache(&sids[0], name, types[0]); + } else { + /* JRA. Here's where we add the -ve cache store with a name type of SID_NAME_USE_NONE. */ + DOM_SID nullsid; + + ZERO_STRUCT(nullsid); + store_sid_by_name_in_cache(name, &nullsid, SID_NAME_USE_NONE); *type = SID_NAME_UNKNOWN; } - return NT_STATUS_IS_OK(result); + rv = NT_STATUS_IS_OK(result); + + done: + talloc_destroy(mem_ctx); + + return rv; } /** @@ -243,8 +457,6 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, * * @param name On success, set to the name corresponding to @p sid. * - * @param dom_name On success, set to the 'domain name' corresponding to @p sid. - * * @param type On success, contains the type of name: alias, group or * user. * @@ -252,45 +464,335 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, * are set, otherwise False. **/ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, - fstring dom_name, fstring name, enum SID_NAME_USE *type) { - char *names; + int num_sids = 1, num_names = 0; + uint32 *types = NULL; + char **names; + CLI_POLICY_HND *hnd; NTSTATUS result; TALLOC_CTX *mem_ctx; BOOL rv = False; - struct winbindd_domain *domain; - domain = find_domain_from_sid(sid); - - if (!domain) { - DEBUG(1,("Can't find domain from sid\n")); - return False; + /* First check cache. */ + if (winbindd_lookup_name_by_sid_in_cache(sid, name, type)) { + if (*type == SID_NAME_USE_NONE) { + fstrcpy(name, name_deadbeef); + *type = SID_NAME_UNKNOWN; + return False; /* Negative cache hit. */ + } else + return True; } /* Lookup name */ - if (!(mem_ctx = talloc_init_named("winbindd_lookup_name_by_sid"))) + if (!(mem_ctx = talloc_init())) return False; - result = domain->methods->sid_to_name(domain, mem_ctx, sid, &names, type); + if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) + goto done; + + result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol, + num_sids, sid, &names, &types, + &num_names); /* Return name and type if successful */ if ((rv = NT_STATUS_IS_OK(result))) { - fstrcpy(dom_name, domain->name); - fstrcpy(name, names); + + /* Return name */ + + if ((names != NULL) && (name != NULL)) + fstrcpy(name, names[0]); + + /* Return name type */ + + if ((type != NULL) && (types != NULL)) + *type = types[0]; + + store_sid_by_name_in_cache(names[0], sid, types[0]); + store_name_by_sid_in_cache(sid, names[0], types[0]); } else { + /* OK, so we tried to look up a name in this sid, and + * didn't find it. Therefore add a negative cache + * entry. */ + store_name_by_sid_in_cache(sid, "", SID_NAME_USE_NONE); *type = SID_NAME_UNKNOWN; fstrcpy(name, name_deadbeef); } + + done: talloc_destroy(mem_ctx); return rv; } +/* Lookup user information from a rid */ + +BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, uint32 user_rid, + SAM_USERINFO_CTR **user_info) +{ + CLI_POLICY_HND *hnd; + uint16 info_level = 0x15; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + POLICY_HND dom_pol, user_pol; + BOOL got_dom_pol = False, got_user_pol = False; + + /* Get sam handle */ + + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; + + /* Get domain handle */ + + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_dom_pol = True; + + /* Get user handle */ + + result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, + des_access, user_rid, &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get user info */ + + result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, + info_level, user_info); + + cli_samr_close(hnd->cli, mem_ctx, &user_pol); + + done: + /* Clean up policy handles */ + + if (got_user_pol) + cli_samr_close(hnd->cli, mem_ctx, &user_pol); + + if (got_dom_pol) + cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + + return NT_STATUS_IS_OK(result); +} + +/* Lookup groups a user is a member of. I wish Unix had a call like this! */ + +BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 user_rid, uint32 *num_groups, + DOM_GID **user_groups) +{ + CLI_POLICY_HND *hnd; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND dom_pol, user_pol; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + BOOL got_dom_pol = False, got_user_pol = False; + + /* Get sam handle */ + + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; + + /* Get domain handle */ + + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_dom_pol = True; + + /* Get user handle */ + + result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, + des_access, user_rid, &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_user_pol = True; + + /* Query user rids */ + + result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, + num_groups, user_groups); + + done: + + /* Clean up policy handles */ + + if (got_user_pol) + cli_samr_close(hnd->cli, mem_ctx, &user_pol); + + if (got_dom_pol) + cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + + return NT_STATUS_IS_OK(result); +} + +/* Lookup group membership given a rid. */ + +BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 group_rid, uint32 *num_names, + uint32 **rid_mem, char ***names, + uint32 **name_types) +{ + CLI_POLICY_HND *hnd; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 i, total_names = 0; + POLICY_HND dom_pol, group_pol; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + BOOL got_dom_pol = False, got_group_pol = False; + + /* Get sam handle */ + + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; + + /* Get domain handle */ + + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_dom_pol = True; + + /* Get group handle */ + + result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol, + des_access, group_rid, &group_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_group_pol = True; + + /* Step #1: Get a list of user rids that are the members of the + group. */ + + result = cli_samr_query_groupmem(hnd->cli, mem_ctx, + &group_pol, num_names, rid_mem, + name_types); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Step #2: Convert list of rids into list of usernames. Do this + in bunches of ~1000 to avoid crashing NT4. It looks like there + is a buffer overflow or something like that lurking around + somewhere. */ + +#define MAX_LOOKUP_RIDS 900 + + *names = talloc(mem_ctx, *num_names * sizeof(char *)); + *name_types = talloc(mem_ctx, *num_names * sizeof(uint32)); + + for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) { + int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS); + uint32 tmp_num_names = 0; + char **tmp_names = NULL; + uint32 *tmp_types = NULL; + + /* Lookup a chunk of rids */ + + result = cli_samr_lookup_rids(hnd->cli, mem_ctx, + &dom_pol, 1000, /* flags */ + num_lookup_rids, + &(*rid_mem)[i], + &tmp_num_names, + &tmp_names, &tmp_types); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Copy result into array. The talloc system will take + care of freeing the temporary arrays later on. */ + + memcpy(&(*names)[i], tmp_names, sizeof(char *) * + tmp_num_names); + + memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) * + tmp_num_names); + + total_names += tmp_num_names; + } + + *num_names = total_names; + + done: + if (got_group_pol) + cli_samr_close(hnd->cli, mem_ctx, &group_pol); + + if (got_dom_pol) + cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + + return NT_STATUS_IS_OK(result); +} + +BOOL create_samr_domain_handle(struct winbindd_domain *domain, POLICY_HND *pdom_pol) +{ + CLI_POLICY_HND *hnd; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + TALLOC_CTX *mem_ctx = talloc_init(); + + ZERO_STRUCTP(pdom_pol); + + if (!mem_ctx) + return False; + + /* Get sam handle */ + + if (!(hnd = cm_get_sam_handle(domain->name))) { + talloc_destroy(mem_ctx); + return False; + } + /* Get domain handle */ + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, pdom_pol); + + talloc_destroy(mem_ctx); + if (!NT_STATUS_IS_OK(result)) + return False; + + return True; +} + +void close_samr_domain_handle(struct winbindd_domain *domain, POLICY_HND *pdom_pol) +{ + static POLICY_HND zero_pol; + CLI_POLICY_HND *hnd; + TALLOC_CTX *mem_ctx = talloc_init(); + + if (!mem_ctx) + return; + + if (memcmp(pdom_pol, &zero_pol, sizeof(zero_pol)) == 0) + return; + + if (!(hnd = cm_get_sam_handle(domain->name))) { + talloc_destroy(mem_ctx); + return; + } + + cli_samr_close(hnd->cli, mem_ctx, pdom_pol); + ZERO_STRUCTP(pdom_pol); + + talloc_destroy(mem_ctx); +} /* Free state information held for {set,get,end}{pw,gr}ent() functions */ @@ -305,6 +807,9 @@ void free_getent_state(struct getent_state *state) while(temp != NULL) { struct getent_state *next; + /* Close SAMR cache handle. */ + close_samr_domain_handle(temp->domain, &temp->dom_pol); + /* Free sam entries then list entry */ SAFE_FREE(state->sam_entries); @@ -316,23 +821,68 @@ void free_getent_state(struct getent_state *state) } } +struct getent_state *create_getent_state(struct winbindd_domain *domain) +{ + struct getent_state *state = (struct getent_state *)malloc(sizeof(struct getent_state)); + + if (state == NULL) + return NULL; + + ZERO_STRUCTP(state); + state->domain = domain; + + /* Create and cache a SAMR domain handle. */ + if (!create_samr_domain_handle(state->domain, &state->dom_pol)) { + free_getent_state(state); + return NULL; + } + + return state; +} + /* Initialise trusted domain info */ BOOL winbindd_param_init(void) { - /* Parse winbind uid and winbind_gid parameters */ + /* Parse winbind uid and winbind_gid parameters */ + + if (!lp_winbind_uid(&server_state.uid_low, &server_state.uid_high)) { + DEBUG(0, ("winbind uid range missing or invalid\n")); + return False; + } + + if (!lp_winbind_gid(&server_state.gid_low, &server_state.gid_high)) { + DEBUG(0, ("winbind gid range missing or invalid\n")); + return False; + } + + return True; +} - if (!lp_winbind_uid(&server_state.uid_low, &server_state.uid_high)) { - DEBUG(0, ("winbind uid range missing or invalid\n")); - return False; - } - - if (!lp_winbind_gid(&server_state.gid_low, &server_state.gid_high)) { - DEBUG(0, ("winbind gid range missing or invalid\n")); - return False; - } - - return True; +/* Query display info for a domain. This returns enough information plus a + bit extra to give an overview of domain users for the User Manager + application. */ + +NTSTATUS winbindd_query_dispinfo(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, POLICY_HND *pdom_pol, + uint32 *start_ndx, uint16 info_level, + uint32 *num_entries, SAM_DISPINFO_CTR *ctr) +{ + CLI_POLICY_HND *hnd; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + /* Get sam handle */ + + if (!(hnd = cm_get_sam_handle(domain->name))) + return NT_STATUS_UNSUCCESSFUL; + + /* Query display info */ + + result = cli_samr_query_dispinfo(hnd->cli, mem_ctx, + pdom_pol, start_ndx, info_level, + num_entries, 0xffff, ctr); + + return result; } /* Check if a domain is present in a comma-separated list of domains */ @@ -351,43 +901,17 @@ BOOL check_domain_env(char *domain_env, char *domain) } /* Parse a string of the form DOMAIN/user into a domain and a user */ -extern fstring global_myworkgroup; -BOOL parse_domain_user(const char *domuser, fstring domain, fstring user) +BOOL parse_domain_user(char *domuser, fstring domain, fstring user) { char *p = strchr(domuser,*lp_winbind_separator()); - if (!(p || lp_winbind_use_default_domain())) + if (!p) return False; - if(!p && lp_winbind_use_default_domain()) { - fstrcpy(user, domuser); - fstrcpy(domain, global_myworkgroup); - } else { - fstrcpy(user, p+1); - fstrcpy(domain, domuser); - domain[PTR_DIFF(p, domuser)] = 0; - } + fstrcpy(user, p+1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = 0; strupper(domain); return True; } - -/* - Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and - 'winbind separator' options. - This means: - - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is - global_myworkgroup - -*/ -void fill_domain_username(fstring name, const char *domain, const char *user) -{ - if(lp_winbind_use_default_domain() && - !strcmp(global_myworkgroup, domain)) { - strlcpy(name, user, sizeof(fstring)); - } else { - slprintf(name, sizeof(fstring) - 1, "%s%s%s", - domain, lp_winbind_separator(), - user); - } -} |