/* convert a sid to a user or group name */ NTSTATUS ads_sid_to_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const DOM_SID *sid, char **name, enum SID_NAME_USE *type) { const char *attrs[] = {"userPrincipalName", "sAMAccountName", "sAMAccountType", NULL}; ADS_STATUS rc; void *msg = NULL; char *ldap_exp = NULL; char *sidstr = NULL; uint32 atype; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; if (!(sidstr = sid_binstring(sid))) { DEBUG(1,("ads_sid_to_name: sid_binstring failed!\n")); status = NT_STATUS_NO_MEMORY; goto done; } if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) { DEBUG(1,("ads_sid_to_name: asprintf failed!\n")); status = NT_STATUS_NO_MEMORY; goto done; } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); if (!ADS_ERR_OK(rc)) { status = ads_ntstatus(rc); DEBUG(1,("ads_sid_to_name ads_search: %s\n", ads_errstr(rc))); goto done; } if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) { goto done; } *name = ads_pull_username(ads, mem_ctx, msg); if (!*name) { DEBUG(1,("ads_sid_to_name: ads_pull_username retuned NULL!\n")); status = NT_STATUS_NO_MEMORY; goto done; } *type = ads_atype_map(atype); status = NT_STATUS_OK; DEBUG(3,("ads sid_to_name mapped %s\n", *name)); done: if (msg) ads_msgfree(ads, msg); SAFE_FREE(ldap_exp); SAFE_FREE(sidstr); return status; }
/* Lookup groups a user is a member of. */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const struct dom_sid *sid, uint32 *p_num_groups, struct dom_sid **user_sids) { ADS_STRUCT *ads = NULL; const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL}; ADS_STATUS rc; int count; LDAPMessage *msg = NULL; char *user_dn = NULL; struct dom_sid *sids; int i; struct dom_sid primary_group; uint32 primary_group_rid; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; uint32_t num_groups = 0; DEBUG(3,("ads: lookup_usergroups\n")); *p_num_groups = 0; status = lookup_usergroups_cached(domain, mem_ctx, sid, p_num_groups, user_sids); if (NT_STATUS_IS_OK(status)) { return NT_STATUS_OK; } if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n", domain->name)); /* Tell the cache manager not to remember this one */ return NT_STATUS_SYNCHRONIZATION_REQUIRED; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry_sid(ads, &msg, sid, attrs); if (!ADS_ERR_OK(rc)) { status = ads_ntstatus(rc); DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: " "%s\n", sid_string_dbg(sid), ads_errstr(rc))); goto done; } count = ads_count_replies(ads, msg); if (count != 1) { status = NT_STATUS_UNSUCCESSFUL; DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: " "invalid number of results (count=%d)\n", sid_string_dbg(sid), count)); goto done; } if (!msg) { DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", sid_string_dbg(sid))); status = NT_STATUS_UNSUCCESSFUL; goto done; } user_dn = ads_get_dn(ads, mem_ctx, msg); if (user_dn == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) { DEBUG(1,("%s: No primary group for sid=%s !?\n", domain->name, sid_string_dbg(sid))); goto done; } sid_compose(&primary_group, &domain->sid, primary_group_rid); count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids); /* there must always be at least one group in the token, unless we are talking to a buggy Win2k server */ /* actually this only happens when the machine account has no read * permissions on the tokenGroup attribute - gd */ if (count == 0) { /* no tokenGroups */ /* lookup what groups this user is a member of by DN search on * "memberOf" */ status = lookup_usergroups_memberof(domain, mem_ctx, user_dn, &primary_group, &num_groups, user_sids); *p_num_groups = num_groups; if (NT_STATUS_IS_OK(status)) { goto done; } /* lookup what groups this user is a member of by DN search on * "member" */ status = lookup_usergroups_member(domain, mem_ctx, user_dn, &primary_group, &num_groups, user_sids); *p_num_groups = num_groups; goto done; } *user_sids = NULL; num_groups = 0; status = add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } for (i=0;i<count;i++) { /* ignore Builtin groups from ADS - Guenther */ if (sid_check_is_in_builtin(&sids[i])) { continue; } status = add_sid_to_array_unique(mem_ctx, &sids[i], user_sids, &num_groups); if (!NT_STATUS_IS_OK(status)) { goto done; } } *p_num_groups = (uint32)num_groups; status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n", sid_string_dbg(sid))); done: TALLOC_FREE(user_dn); ads_msgfree(ads, msg); return status; }
/* Lookup user information from a rid */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const struct dom_sid *sid, struct wbint_userinfo *info) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "*", NULL }; ADS_STATUS rc; int count; LDAPMessage *msg = NULL; char *ldap_exp; char *sidstr; uint32 group_rid; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; struct netr_SamInfo3 *user = NULL; gid_t gid = -1; int ret; char *ads_name; DEBUG(3,("ads: query_user\n")); info->homedir = NULL; info->shell = NULL; /* try netsamlogon cache first */ if (winbindd_use_cache() && (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) { DEBUG(5,("query_user: Cache lookup succeeded for %s\n", sid_string_dbg(sid))); sid_compose(&info->user_sid, &domain->sid, user->base.rid); sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid); info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string); info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string); nss_get_info_cached( domain, sid, mem_ctx, &info->homedir, &info->shell, &info->full_name, &gid ); info->primary_gid = gid; TALLOC_FREE(user); return NT_STATUS_OK; } if ( !winbindd_can_contact_domain(domain)) { DEBUG(8,("query_user: No incoming trust from domain %s\n", domain->name)); /* We still need to generate some basic information about the user even if we cannot contact the domain. Most of this stuff we can deduce. */ sid_copy( &info->user_sid, sid ); /* Assume "Domain Users" for the primary group */ sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS ); /* Try to fill in what the nss_info backend can do */ nss_get_info_cached( domain, sid, mem_ctx, &info->homedir, &info->shell, &info->full_name, &gid); info->primary_gid = gid; return NT_STATUS_OK; } /* no cache...do the query */ if ( (ads = ads_cached_connection(domain)) == NULL ) { domain->last_status = NT_STATUS_SERVER_DISABLED; return NT_STATUS_SERVER_DISABLED; } sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid); ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr); TALLOC_FREE(sidstr); if (ret == -1) { return NT_STATUS_NO_MEMORY; } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); SAFE_FREE(ldap_exp); if (!ADS_ERR_OK(rc) || !msg) { DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_string_dbg(sid), ads_errstr(rc))); return ads_ntstatus(rc); } count = ads_count_replies(ads, msg); if (count != 1) { DEBUG(1,("query_user(sid=%s): Not found\n", sid_string_dbg(sid))); ads_msgfree(ads, msg); return NT_STATUS_NO_SUCH_USER; } info->acct_name = ads_pull_username(ads, mem_ctx, msg); if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { DEBUG(1,("No primary group for %s !?\n", sid_string_dbg(sid))); ads_msgfree(ads, msg); return NT_STATUS_NO_SUCH_USER; } sid_copy(&info->user_sid, sid); sid_compose(&info->group_sid, &domain->sid, group_rid); /* * We have to fetch the "name" attribute before doing the * nss_get_info_cached call. nss_get_info_cached might destroy * the ads struct, potentially invalidating the ldap message. */ ads_name = ads_pull_string(ads, mem_ctx, msg, "name"); ads_msgfree(ads, msg); msg = NULL; status = nss_get_info_cached( domain, sid, mem_ctx, &info->homedir, &info->shell, &info->full_name, &gid); info->primary_gid = gid; if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("nss_get_info_cached failed: %s\n", nt_errstr(status))); return status; } if (info->full_name == NULL) { info->full_name = ads_name; } else { TALLOC_FREE(ads_name); } status = NT_STATUS_OK; DEBUG(3,("ads query_user gave %s\n", info->acct_name)); return NT_STATUS_OK; }
/* Query display info for a realm. This is the basic user list fn */ static NTSTATUS query_user_list(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_entries, struct wbint_userinfo **pinfo) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "*", NULL }; int i, count; ADS_STATUS rc; LDAPMessage *res = NULL; LDAPMessage *msg = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; *num_entries = 0; DEBUG(3,("ads: query_user_list\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("query_user_list: No incoming trust for domain %s\n", domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); goto done; } count = ads_count_replies(ads, res); if (count == 0) { DEBUG(1,("query_user_list: No users found\n")); goto done; } (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count); if (!*pinfo) { status = NT_STATUS_NO_MEMORY; goto done; } count = 0; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { struct wbint_userinfo *info = &((*pinfo)[count]); uint32 group; uint32 atype; if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) || ds_atype_map(atype) != SID_NAME_USER) { DEBUG(1,("Not a user account? atype=0x%x\n", atype)); continue; } info->acct_name = ads_pull_username(ads, mem_ctx, msg); info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); info->homedir = NULL; info->shell = NULL; info->primary_gid = (gid_t)-1; if (!ads_pull_sid(ads, msg, "objectSid", &info->user_sid)) { DEBUG(1, ("No sid for %s !?\n", info->acct_name)); continue; } if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) { DEBUG(1, ("No primary group for %s !?\n", info->acct_name)); continue; } sid_compose(&info->group_sid, &domain->sid, group); count += 1; } (*num_entries) = count; ads_msgfree(ads, res); for (i=0; i<count; i++) { struct wbint_userinfo *info = &((*pinfo)[i]); const char *gecos = NULL; gid_t primary_gid = (gid_t)-1; status = nss_get_info_cached(domain, &info->user_sid, mem_ctx, &info->homedir, &info->shell, &gecos, &primary_gid); if (!NT_STATUS_IS_OK(status)) { /* * Deliberately ignore this error, there might be more * users to fill */ continue; } if (gecos != NULL) { info->full_name = gecos; } info->primary_gid = primary_gid; } status = NT_STATUS_OK; DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries))); done: return status; }
/* convert a single name to a sid in a domain */ NTSTATUS ads_name_to_sid(ADS_STRUCT *ads, const char *name, DOM_SID *sid, enum SID_NAME_USE *type) { const char *attrs[] = {"objectSid", "sAMAccountType", NULL}; int count; ADS_STATUS rc; void *res = NULL; char *ldap_exp; uint32 t; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; char *escaped_name = escape_ldap_string_alloc(name); char *escaped_realm = escape_ldap_string_alloc(ads->config.realm); if (!escaped_name || !escaped_realm) { status = NT_STATUS_NO_MEMORY; goto done; } if (asprintf(&ldap_exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))", escaped_name, escaped_name, escaped_realm) == -1) { DEBUG(1,("ads_name_to_sid: asprintf failed!\n")); status = NT_STATUS_NO_MEMORY; goto done; } rc = ads_search_retry(ads, &res, ldap_exp, attrs); free(ldap_exp); if (!ADS_ERR_OK(rc)) { DEBUG(1,("name_to_sid ads_search: %s\n", ads_errstr(rc))); goto done; } count = ads_count_replies(ads, res); if (count != 1) { DEBUG(1,("name_to_sid: %s not found\n", name)); goto done; } if (!ads_pull_sid(ads, res, "objectSid", sid)) { DEBUG(1,("No sid for %s !?\n", name)); goto done; } if (!ads_pull_uint32(ads, res, "sAMAccountType", &t)) { DEBUG(1,("No sAMAccountType for %s !?\n", name)); goto done; } *type = ads_atype_map(t); status = NT_STATUS_OK; DEBUG(3,("ads name_to_sid mapped %s\n", name)); done: if (res) ads_msgfree(ads, res); SAFE_FREE(escaped_name); SAFE_FREE(escaped_realm); return status; }
static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, int scope, const char *base, const char *filter, const char **attrs, void *args, const char *range_attr, char ***strings, size_t *num_strings, uint32_t *first_usn, int *num_retries, bool *more_values) { LDAPMessage *res = NULL; ADS_STATUS status; int count; uint32_t current_usn; DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1])); *more_values = False; status = ads_do_search_retry_internal(ads, base, scope, filter, attrs, args, &res); if (!ADS_ERR_OK(status)) { DEBUG(1,("ads_search: %s\n", ads_errstr(status))); return status; } if (!res) { return ADS_ERROR(LDAP_NO_MEMORY); } count = ads_count_replies(ads, res); if (count == 0) { ads_msgfree(ads, res); return ADS_ERROR(LDAP_SUCCESS); } if (*num_strings == 0) { if (!ads_pull_uint32(ads, res, "usnChanged", first_usn)) { DEBUG(1, ("could not pull first usnChanged!\n")); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } } if (!ads_pull_uint32(ads, res, "usnChanged", ¤t_usn)) { DEBUG(1, ("could not pull current usnChanged!\n")); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } if (*first_usn != current_usn) { DEBUG(5, ("USN on this record changed" " - restarting search\n")); if (*num_retries < 5) { (*num_retries)++; *num_strings = 0; ads_msgfree(ads, res); return ADS_ERROR_NT(STATUS_MORE_ENTRIES); } else { DEBUG(5, ("USN on this record changed" " - restarted search too many times, aborting!\n")); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } } *strings = ads_pull_strings_range(ads, mem_ctx, res, range_attr, *strings, &attrs[0], num_strings, more_values); ads_msgfree(ads, res); /* paranoia checks */ if (*strings == NULL && *more_values) { DEBUG(0,("no strings found but more values???\n")); return ADS_ERROR(LDAP_NO_MEMORY); } if (*num_strings == 0 && *more_values) { DEBUG(0,("no strings found but more values???\n")); return ADS_ERROR(LDAP_NO_MEMORY); } return (*more_values) ? ADS_ERROR_NT(STATUS_MORE_ENTRIES) : ADS_ERROR(LDAP_SUCCESS); }
/* Query display info for a realm. This is the basic user list fn */ static NTSTATUS query_user_list(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t **prids) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "sAMAccountType", "objectSid", NULL }; int count; uint32_t *rids = NULL; ADS_STATUS rc; LDAPMessage *res = NULL; LDAPMessage *msg = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; DEBUG(3,("ads: query_user_list\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("query_user_list: No incoming trust for domain %s\n", domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); if (!ADS_ERR_OK(rc)) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); status = ads_ntstatus(rc); goto done; } else if (!res) { DEBUG(1,("query_user_list ads_search returned NULL res\n")); goto done; } count = ads_count_replies(ads, res); if (count == 0) { DEBUG(1,("query_user_list: No users found\n")); goto done; } rids = talloc_zero_array(mem_ctx, uint32_t, count); if (rids == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } count = 0; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { struct dom_sid user_sid; uint32_t atype; bool ok; ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype); if (!ok) { DBG_INFO("Object lacks sAMAccountType attribute\n"); continue; } if (ds_atype_map(atype) != SID_NAME_USER) { DBG_INFO("Not a user account? atype=0x%x\n", atype); continue; } if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) { char *dn = ads_get_dn(ads, talloc_tos(), msg); DBG_INFO("No sid for %s !?\n", dn); TALLOC_FREE(dn); continue; } if (!dom_sid_in_domain(&domain->sid, &user_sid)) { fstring sidstr, domstr; DBG_WARNING("Got sid %s in domain %s\n", sid_to_fstring(sidstr, &user_sid), sid_to_fstring(domstr, &domain->sid)); continue; } sid_split_rid(&user_sid, &rids[count]); count += 1; } rids = talloc_realloc(mem_ctx, rids, uint32_t, count); if (prids != NULL) { *prids = rids; } status = NT_STATUS_OK; DBG_NOTICE("ads query_user_list gave %d entries\n", count); done: return status; }
/* Lookup user information from a rid */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *sid, struct wbint_userinfo *info) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "*", NULL }; ADS_STATUS rc; int count; LDAPMessage *msg = NULL; char *ldap_exp; char *sidstr; uint32 group_rid; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; struct netr_SamInfo3 *user = NULL; gid_t gid; DEBUG(3,("ads: query_user\n")); info->homedir = NULL; info->shell = NULL; info->primary_gid = (gid_t)-1; /* try netsamlogon cache first */ if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) { DEBUG(5,("query_user: Cache lookup succeeded for %s\n", sid_string_dbg(sid))); sid_compose(&info->user_sid, &domain->sid, user->base.rid); sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid); info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string); info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string); nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, &info->homedir, &info->shell, &info->full_name, &gid ); info->primary_gid = gid; TALLOC_FREE(user); return NT_STATUS_OK; } if ( !winbindd_can_contact_domain(domain)) { DEBUG(8,("query_user: No incoming trust from domain %s\n", domain->name)); /* We still need to generate some basic information about the user even if we cannot contact the domain. Most of this stuff we can deduce. */ sid_copy( &info->user_sid, sid ); /* Assume "Domain Users" for the primary group */ sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS ); /* Try to fill in what the nss_info backend can do */ nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, &info->homedir, &info->shell, &info->full_name, &gid); info->primary_gid = gid; status = NT_STATUS_OK; goto done; } /* no cache...do the query */ if ( (ads = ads_cached_connection(domain)) == NULL ) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } sidstr = sid_binstring(talloc_tos(), sid); if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) { status = NT_STATUS_NO_MEMORY; goto done; } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); free(ldap_exp); TALLOC_FREE(sidstr); if (!ADS_ERR_OK(rc) || !msg) { DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_string_dbg(sid), ads_errstr(rc))); goto done; } count = ads_count_replies(ads, msg); if (count != 1) { DEBUG(1,("query_user(sid=%s): Not found\n", sid_string_dbg(sid))); goto done; } info->acct_name = ads_pull_username(ads, mem_ctx, msg); nss_get_info_cached( domain, sid, mem_ctx, ads, msg, &info->homedir, &info->shell, &info->full_name, &gid); info->primary_gid = gid; if (info->full_name == NULL) { info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); } if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { DEBUG(1,("No primary group for %s !?\n", sid_string_dbg(sid))); goto done; } sid_copy(&info->user_sid, sid); sid_compose(&info->group_sid, &domain->sid, group_rid); status = NT_STATUS_OK; DEBUG(3,("ads query_user gave %s\n", info->acct_name)); done: if (msg) ads_msgfree(ads, msg); return status; }
/* Query display info for a realm. This is the basic user list fn */ static NTSTATUS query_user_list(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_entries, struct wbint_userinfo **info) { ADS_STRUCT *ads = NULL; const char *attrs[] = { "*", NULL }; int i, count; ADS_STATUS rc; LDAPMessage *res = NULL; LDAPMessage *msg = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; *num_entries = 0; DEBUG(3,("ads: query_user_list\n")); if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("query_user_list: No incoming trust for domain %s\n", domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; } rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); goto done; } count = ads_count_replies(ads, res); if (count == 0) { DEBUG(1,("query_user_list: No users found\n")); goto done; } (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count); if (!*info) { status = NT_STATUS_NO_MEMORY; goto done; } i = 0; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { const char *name; const char *gecos = NULL; const char *homedir = NULL; const char *shell = NULL; uint32 group; uint32 atype; DOM_SID user_sid; gid_t primary_gid = (gid_t)-1; if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) || ds_atype_map(atype) != SID_NAME_USER) { DEBUG(1,("Not a user account? atype=0x%x\n", atype)); continue; } name = ads_pull_username(ads, mem_ctx, msg); if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) { status = nss_get_info_cached( domain, &user_sid, mem_ctx, ads, msg, &homedir, &shell, &gecos, &primary_gid ); } if (gecos == NULL) { gecos = ads_pull_string(ads, mem_ctx, msg, "name"); } if (!ads_pull_sid(ads, msg, "objectSid", &(*info)[i].user_sid)) { DEBUG(1,("No sid for %s !?\n", name)); continue; } if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) { DEBUG(1,("No primary group for %s !?\n", name)); continue; } (*info)[i].acct_name = name; (*info)[i].full_name = gecos; (*info)[i].homedir = homedir; (*info)[i].shell = shell; (*info)[i].primary_gid = primary_gid; sid_compose(&(*info)[i].group_sid, &domain->sid, group); i++; } (*num_entries) = i; status = NT_STATUS_OK; DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries))); done: if (res) ads_msgfree(ads, res); return status; }