/* lookup a name for 1 SID */ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, struct dom_sid *sid, const char *sid_str, const char **authority_name, const char **name, enum lsa_SidType *rtype) { NTSTATUS status; int ret; uint32_t atype; struct ldb_message **res; struct ldb_dn *domain_dn; const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL}; status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype); if (NT_STATUS_IS_OK(status)) { return status; } if (dom_sid_in_domain(state->domain_sid, sid)) { *authority_name = state->domain_name; domain_dn = state->domain_dn; } else if (dom_sid_in_domain(state->builtin_sid, sid)) { *authority_name = NAME_BUILTIN; domain_dn = state->builtin_dn; } else { /* Not well known, our domain or built in */ /* In future, we must look at SID histories, and at trusted domains via winbind */ return NT_STATUS_NOT_FOUND; } ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid)); if (ret == 1) { *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL); if (!*name) { *name = ldb_msg_find_attr_as_string(res[0], "cn", NULL); if (!*name) { *name = talloc_strdup(mem_ctx, sid_str); NT_STATUS_HAVE_NO_MEMORY(*name); } } atype = samdb_result_uint(res[0], "sAMAccountType", 0); *rtype = ds_atype_map(atype); return NT_STATUS_OK; } /* need to re-add a check for an allocated sid */ return NT_STATUS_NOT_FOUND; }
/* lookup a SID for 1 name */ static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, const char *name, const char **authority_name, struct dom_sid **sid, enum lsa_SidType *rtype, uint32_t *rid) { int ret, i; uint32_t atype; struct ldb_message **res; const char * const attrs[] = { "objectSid", "sAMAccountType", NULL}; const char *p; const char *domain; const char *username; struct ldb_dn *domain_dn; struct dom_sid *domain_sid; NTSTATUS status; p = strchr_m(name, '\\'); if (p != NULL) { domain = talloc_strndup(mem_ctx, name, p-name); if (!domain) { return NT_STATUS_NO_MEMORY; } username = p + 1; } else if (strchr_m(name, '@')) { status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status))); return status; } } else { domain = NULL; username = name; } if (!domain) { /* Look up table of well known names */ status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype); if (NT_STATUS_IS_OK(status)) { dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } if (username == NULL) { *authority_name = NAME_BUILTIN; *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) { *authority_name = NAME_NT_AUTHORITY; *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); *rtype = SID_NAME_DOMAIN; dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } if (strcasecmp_m(username, NAME_BUILTIN) == 0) { *authority_name = NAME_BUILTIN; *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, state->domain_dns) == 0) { *authority_name = state->domain_name; *sid = state->domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, state->domain_name) == 0) { *authority_name = state->domain_name; *sid = state->domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } /* Perhaps this is a well known user? */ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } /* Perhaps this is a BUILTIN user? */ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } /* OK, I give up - perhaps we need to assume the user is in our domain? */ name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } return STATUS_SOME_UNMAPPED; } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) { if (!*username) { *authority_name = NAME_NT_AUTHORITY; *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); *rtype = SID_NAME_DOMAIN; dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } /* Look up table of well known names */ status = lookup_well_known_names(mem_ctx, domain, username, authority_name, sid, rtype); if (NT_STATUS_IS_OK(status)) { dom_sid_split_rid(NULL, *sid, NULL, rid); } return status; } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) { *authority_name = NAME_BUILTIN; domain_dn = state->builtin_dn; } else if (strcasecmp_m(domain, state->domain_dns) == 0) { *authority_name = state->domain_name; domain_dn = state->domain_dn; } else if (strcasecmp_m(domain, state->domain_name) == 0) { *authority_name = state->domain_name; domain_dn = state->domain_dn; } else { /* Not local, need to ask winbind in future */ return STATUS_SOME_UNMAPPED; } ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs); if (ret == 1) { domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); if (domain_sid == NULL) { return NT_STATUS_INVALID_SID; } } else { return NT_STATUS_INVALID_SID; } if (!*username) { *sid = domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "(&(sAMAccountName=%s)(objectSid=*))", ldb_binary_encode_string(mem_ctx, username)); if (ret == -1) { return NT_STATUS_INVALID_SID; } for (i=0; i < ret; i++) { *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); if (*sid == NULL) { return NT_STATUS_INVALID_SID; } /* Check that this is in the domain */ if (!dom_sid_in_domain(domain_sid, *sid)) { continue; } atype = samdb_result_uint(res[i], "sAMAccountType", 0); *rtype = ds_atype_map(atype); if (*rtype == SID_NAME_UNKNOWN) { return STATUS_SOME_UNMAPPED; } dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } /* need to check for an allocated sid */ return NT_STATUS_INVALID_SID; }
/* 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; }
/* 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; }
/* 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; }
NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, unsigned int num_rids, uint32_t *rids, const char **names, enum lsa_SidType *lsa_attrs) { const char *attrs[] = { "sAMAccountType", "sAMAccountName", NULL }; unsigned int i, num_mapped; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); num_mapped = 0; for (i=0; i<num_rids; i++) { struct ldb_message *msg; struct ldb_dn *dn; uint32_t attr; int rc; lsa_attrs[i] = SID_NAME_UNKNOWN; dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<SID=%s>", dom_sid_string(tmp_ctx, dom_sid_add_rid(tmp_ctx, domain_sid, rids[i]))); if (dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rc = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "samAccountName=*"); if (rc == LDB_ERR_NO_SUCH_OBJECT) { continue; } else if (rc != LDB_SUCCESS) { talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } names[i] = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); if (names[i] == NULL) { DEBUG(10, ("no samAccountName\n")); continue; } talloc_steal(names, names[i]); attr = ldb_msg_find_attr_as_uint(msg, "samAccountType", 0); lsa_attrs[i] = ds_atype_map(attr); if (lsa_attrs[i] == SID_NAME_UNKNOWN) { continue; } num_mapped += 1; } talloc_free(tmp_ctx); if (num_mapped == 0) { return NT_STATUS_NONE_MAPPED; } if (num_mapped < num_rids) { return STATUS_SOME_UNMAPPED; } return NT_STATUS_OK; }