diff options
author | Andrew Bartlett <abartlet@samba.org> | 2007-09-17 05:31:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 15:06:51 -0500 |
commit | 08c97435d3dd055329d41b3814af687c7404533f (patch) | |
tree | cd7b2eacbda9378478ea4b8eca2168bf3d3a151e /source4/rpc_server/lsa | |
parent | ffbb7e40604b9cffeb0c226279b929497b03a964 (diff) | |
download | samba-08c97435d3dd055329d41b3814af687c7404533f.tar.gz samba-08c97435d3dd055329d41b3814af687c7404533f.tar.bz2 samba-08c97435d3dd055329d41b3814af687c7404533f.zip |
r25194: A major rework of the Samba4 LSA LookupNames and LookupSids code, with
a new torture suite to match.
This should fix bug #4954 by Matthias Wallnöfer <mwallnoefer@yahoo.de>
Previously we had no knowlege of BUILTIN or well-known names.
This code needs expansion to check with winbind for trusted domains.
Andrew Bartlett
(This used to be commit e6fc0e1f54ad64bdddc88e9ebd0d8d181b6ce26a)
Diffstat (limited to 'source4/rpc_server/lsa')
-rw-r--r-- | source4/rpc_server/lsa/dcesrv_lsa.c | 850 | ||||
-rw-r--r-- | source4/rpc_server/lsa/lsa.h | 69 | ||||
-rw-r--r-- | source4/rpc_server/lsa/lsa_init.c | 248 | ||||
-rw-r--r-- | source4/rpc_server/lsa/lsa_lookup.c | 928 |
4 files changed, 1251 insertions, 844 deletions
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c index 144e61cd75..8a695bdedf 100644 --- a/source4/rpc_server/lsa/dcesrv_lsa.c +++ b/source4/rpc_server/lsa/dcesrv_lsa.c @@ -4,7 +4,7 @@ endpoint server for the lsarpc pipe Copyright (C) Andrew Tridgell 2004 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2007 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 @@ -20,51 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "includes.h" -#include "rpc_server/dcerpc_server.h" -#include "rpc_server/common/common.h" -#include "auth/auth.h" -#include "dsdb/samdb/samdb.h" -#include "libcli/ldap/ldap.h" -#include "lib/ldb/include/ldb_errors.h" -#include "libcli/security/security.h" -#include "libcli/auth/libcli_auth.h" -#include "param/secrets.h" -#include "db_wrap.h" -#include "librpc/gen_ndr/ndr_dssetup.h" -#include "param/param.h" +#include "rpc_server/lsa/lsa.h" /* this type allows us to distinguish handle types */ -enum lsa_handle { - LSA_HANDLE_POLICY, - LSA_HANDLE_ACCOUNT, - LSA_HANDLE_SECRET, - LSA_HANDLE_TRUSTED_DOMAIN -}; - -/* - state associated with a lsa_OpenPolicy() operation -*/ -struct lsa_policy_state { - struct dcesrv_handle *handle; - struct ldb_context *sam_ldb; - struct sidmap_context *sidmap; - uint32_t access_mask; - struct ldb_dn *domain_dn; - struct ldb_dn *forest_dn; - struct ldb_dn *builtin_dn; - struct ldb_dn *system_dn; - const char *domain_name; - const char *domain_dns; - const char *forest_dns; - struct dom_sid *domain_sid; - struct GUID domain_guid; - struct dom_sid *builtin_sid; - int mixed_domain; -}; - /* state associated with a lsa_OpenAccount() operation @@ -269,162 +229,6 @@ static NTSTATUS dcesrv_lsa_ChangePassword(struct dcesrv_call_state *dce_call, TA DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); } -static NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_policy_state **_state) -{ - struct lsa_policy_state *state; - struct ldb_dn *partitions_basedn; - struct ldb_result *dom_res; - const char *dom_attrs[] = { - "objectSid", - "objectGUID", - "nTMixedDomain", - "fSMORoleOwner", - NULL - }; - struct ldb_result *ref_res; - struct ldb_result *forest_ref_res; - const char *ref_attrs[] = { - "nETBIOSName", - "dnsRoot", - NULL - }; - int ret; - - state = talloc(mem_ctx, struct lsa_policy_state); - if (!state) { - return NT_STATUS_NO_MEMORY; - } - - /* make sure the sam database is accessible */ - state->sam_ldb = samdb_connect(state, dce_call->conn->auth_state.session_info); - if (state->sam_ldb == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx); - - state->sidmap = sidmap_open(state); - if (state->sidmap == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - /* work out the domain_dn - useful for so many calls its worth - fetching here */ - state->domain_dn = samdb_base_dn(state->sam_ldb); - if (!state->domain_dn) { - return NT_STATUS_NO_MEMORY; - } - - /* work out the forest root_dn - useful for so many calls its worth - fetching here */ - state->forest_dn = samdb_root_dn(state->sam_ldb); - if (!state->forest_dn) { - return NT_STATUS_NO_MEMORY; - } - - ret = ldb_search(state->sam_ldb, state->domain_dn, LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res); - - if (ret != LDB_SUCCESS) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - talloc_steal(mem_ctx, dom_res); - if (dom_res->count != 1) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid"); - if (!state->domain_sid) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); - if (!state->domain_sid) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0); - - talloc_free(dom_res); - - ret = ldb_search_exp_fmt(state->sam_ldb, state, &ref_res, - partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs, - "(&(objectclass=crossRef)(ncName=%s))", - ldb_dn_get_linearized(state->domain_dn)); - - if (ret != LDB_SUCCESS) { - talloc_free(ref_res); - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - if (ref_res->count != 1) { - talloc_free(ref_res); - return NT_STATUS_NO_SUCH_DOMAIN; - } - - state->domain_name = ldb_msg_find_attr_as_string(ref_res->msgs[0], "nETBIOSName", NULL); - if (!state->domain_name) { - talloc_free(ref_res); - return NT_STATUS_NO_SUCH_DOMAIN; - } - talloc_steal(state, state->domain_name); - - state->domain_dns = ldb_msg_find_attr_as_string(ref_res->msgs[0], "dnsRoot", NULL); - if (!state->domain_dns) { - talloc_free(ref_res); - return NT_STATUS_NO_SUCH_DOMAIN; - } - talloc_steal(state, state->domain_dns); - - talloc_free(ref_res); - - ret = ldb_search_exp_fmt(state->sam_ldb, state, &forest_ref_res, - partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs, - "(&(objectclass=crossRef)(ncName=%s))", - ldb_dn_get_linearized(state->forest_dn)); - - if (ret != LDB_SUCCESS) { - talloc_free(forest_ref_res); - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - if (forest_ref_res->count != 1) { - talloc_free(forest_ref_res); - return NT_STATUS_NO_SUCH_DOMAIN; - } - - state->forest_dns = ldb_msg_find_attr_as_string(forest_ref_res->msgs[0], "dnsRoot", NULL); - if (!state->forest_dns) { - talloc_free(forest_ref_res); - return NT_STATUS_NO_SUCH_DOMAIN; - } - talloc_steal(state, state->forest_dns); - - talloc_free(forest_ref_res); - - /* work out the builtin_dn - useful for so many calls its worth - fetching here */ - state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)"); - if (!state->builtin_dn) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - /* work out the system_dn - useful for so many calls its worth - fetching here */ - state->system_dn = samdb_search_dn(state->sam_ldb, state, - state->domain_dn, "(&(objectClass=container)(cn=System))"); - if (!state->system_dn) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN); - if (!state->builtin_sid) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - *_state = state; - - return NT_STATUS_OK; -} - /* dssetup_DsRoleGetPrimaryDomainInformation @@ -532,60 +336,6 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal return WERR_INVALID_PARAM; } -/* - lsa_OpenPolicy2 -*/ -static NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_OpenPolicy2 *r) -{ - NTSTATUS status; - struct lsa_policy_state *state; - struct dcesrv_handle *handle; - - ZERO_STRUCTP(r->out.handle); - - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_POLICY); - if (!handle) { - return NT_STATUS_NO_MEMORY; - } - - handle->data = talloc_steal(handle, state); - - state->access_mask = r->in.access_mask; - state->handle = handle; - *r->out.handle = handle->wire_handle; - - /* note that we have completely ignored the attr element of - the OpenPolicy. As far as I can tell, this is what w2k3 - does */ - - return NT_STATUS_OK; -} - -/* - lsa_OpenPolicy - a wrapper around lsa_OpenPolicy2 -*/ -static NTSTATUS dcesrv_lsa_OpenPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_OpenPolicy *r) -{ - struct lsa_OpenPolicy2 r2; - - r2.in.system_name = NULL; - r2.in.attr = r->in.attr; - r2.in.access_mask = r->in.access_mask; - r2.out.handle = r->out.handle; - - return dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &r2); -} - - - /* fill in the AccountDomain info @@ -643,6 +393,10 @@ static NTSTATUS dcesrv_lsa_QueryInfoPolicy2(struct dcesrv_call_state *dce_call, case LSA_POLICY_INFO_DNS: return dcesrv_lsa_info_DNS(state, mem_ctx, &r->out.info->dns); + case LSA_POLICY_INFO_DB: + case LSA_POLICY_INFO_AUDIT_FULL_SET: + case LSA_POLICY_INFO_AUDIT_FULL_QUERY: + return NT_STATUS_INVALID_PARAMETER; } return NT_STATUS_INVALID_INFO_CLASS; @@ -1473,311 +1227,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca } -/* - return the authority name and authority sid, given a sid -*/ -static NTSTATUS dcesrv_lsa_authority_name(struct lsa_policy_state *state, - TALLOC_CTX *mem_ctx, struct dom_sid *sid, - const char **authority_name, - struct dom_sid **authority_sid) -{ - if (dom_sid_in_domain(state->domain_sid, sid)) { - *authority_name = state->domain_name; - *authority_sid = state->domain_sid; - return NT_STATUS_OK; - } - - if (dom_sid_in_domain(state->builtin_sid, sid)) { - *authority_name = "BUILTIN"; - *authority_sid = state->builtin_sid; - return NT_STATUS_OK; - } - - *authority_sid = dom_sid_dup(mem_ctx, sid); - if (*authority_sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - (*authority_sid)->num_auths = 0; - *authority_name = dom_sid_string(mem_ctx, *authority_sid); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/* - add to the lsa_RefDomainList for LookupSids and LookupNames -*/ -static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, - struct dom_sid *sid, - struct lsa_RefDomainList *domains, - uint32_t *sid_index) -{ - NTSTATUS status; - const char *authority_name; - struct dom_sid *authority_sid; - int i; - - /* work out the authority name */ - status = dcesrv_lsa_authority_name(state, mem_ctx, sid, - &authority_name, &authority_sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* see if we've already done this authority name */ - for (i=0;i<domains->count;i++) { - if (strcmp(authority_name, domains->domains[i].name.string) == 0) { - *sid_index = i; - return NT_STATUS_OK; - } - } - - domains->domains = talloc_realloc(domains, - domains->domains, - struct lsa_DomainInfo, - domains->count+1); - if (domains->domains == NULL) { - return NT_STATUS_NO_MEMORY; - } - domains->domains[i].name.string = authority_name; - domains->domains[i].sid = authority_sid; - domains->count++; - domains->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER * domains->count; - *sid_index = i; - - return NT_STATUS_OK; -} - -/* - 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 **name, uint32_t *atype) -{ - int ret; - struct ldb_message **res; - const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "name", NULL}; - NTSTATUS status; - - ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &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], "name", NULL); - if (!*name) { - *name = talloc_strdup(mem_ctx, sid_str); - NT_STATUS_HAVE_NO_MEMORY(*name); - } - } - - *atype = samdb_result_uint(res[0], "sAMAccountType", 0); - - return NT_STATUS_OK; - } - - status = sidmap_allocated_sid_lookup(state->sidmap, mem_ctx, sid, name, atype); - - return status; -} - - -/* - lsa_LookupSids2 -*/ -static NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - struct lsa_LookupSids2 *r) -{ - struct lsa_policy_state *state; - int i; - NTSTATUS status = NT_STATUS_OK; - - r->out.domains = NULL; - - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); - if (r->out.domains == NULL) { - return NT_STATUS_NO_MEMORY; - } - - r->out.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); - if (r->out.names == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.count = 0; - - r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2, - r->in.sids->num_sids); - if (r->out.names->names == NULL) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0;i<r->in.sids->num_sids;i++) { - struct dom_sid *sid = r->in.sids->sids[i].sid; - char *sid_str = dom_sid_string(mem_ctx, sid); - const char *name; - uint32_t atype, rtype, sid_index; - NTSTATUS status2; - - r->out.names->count++; - (*r->out.count)++; - - r->out.names->names[i].sid_type = SID_NAME_UNKNOWN; - r->out.names->names[i].name.string = sid_str; - r->out.names->names[i].sid_index = 0xFFFFFFFF; - r->out.names->names[i].unknown = 0; - - if (sid_str == NULL) { - r->out.names->names[i].name.string = "(SIDERROR)"; - status = STATUS_SOME_UNMAPPED; - continue; - } - - /* work out the authority name */ - status2 = dcesrv_lsa_authority_list(state, mem_ctx, sid, r->out.domains, &sid_index); - if (!NT_STATUS_IS_OK(status2)) { - return status2; - } - - status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str, - &name, &atype); - if (!NT_STATUS_IS_OK(status2)) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - rtype = samdb_atype_map(atype); - if (rtype == SID_NAME_UNKNOWN) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - r->out.names->names[i].sid_type = rtype; - r->out.names->names[i].name.string = name; - r->out.names->names[i].sid_index = sid_index; - r->out.names->names[i].unknown = 0; - } - - return status; -} - - -/* - lsa_LookupSids3 - - Identical to LookupSids2, but doesn't take a policy handle - -*/ -static NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - struct lsa_LookupSids3 *r) -{ - struct lsa_LookupSids2 r2; - struct lsa_OpenPolicy2 pol; - NTSTATUS status; - struct dcesrv_handle *h; - - /* No policy handle on the wire, so make one up here */ - r2.in.handle = talloc(mem_ctx, struct policy_handle); - if (!r2.in.handle) { - return NT_STATUS_NO_MEMORY; - } - - pol.out.handle = r2.in.handle; - pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - pol.in.attr = NULL; - pol.in.system_name = NULL; - status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* ensure this handle goes away at the end of this call */ - DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY); - talloc_steal(mem_ctx, h); - - r2.in.sids = r->in.sids; - r2.in.names = r->in.names; - r2.in.level = r->in.level; - r2.in.count = r->in.count; - r2.in.unknown1 = r->in.unknown1; - r2.in.unknown2 = r->in.unknown2; - r2.out.count = r->out.count; - r2.out.names = r->out.names; - - status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2); - if (dce_call->fault_code != 0) { - return status; - } - - r->out.domains = r2.out.domains; - r->out.names = r2.out.names; - r->out.count = r2.out.count; - - return status; -} - - -/* - lsa_LookupSids -*/ -static NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_LookupSids *r) -{ - struct lsa_LookupSids2 r2; - NTSTATUS status; - int i; - - r2.in.handle = r->in.handle; - r2.in.sids = r->in.sids; - r2.in.names = NULL; - r2.in.level = r->in.level; - r2.in.count = r->in.count; - r2.in.unknown1 = 0; - r2.in.unknown2 = 0; - r2.out.count = r->out.count; - r2.out.names = NULL; - - status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2); - if (dce_call->fault_code != 0) { - return status; - } - - r->out.domains = r2.out.domains; - if (!r2.out.names) { - r->out.names = NULL; - return status; - } - - r->out.names = talloc(mem_ctx, struct lsa_TransNameArray); - if (r->out.names == NULL) { - return NT_STATUS_NO_MEMORY; - } - r->out.names->count = r2.out.names->count; - r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName, - r->out.names->count); - if (r->out.names->names == NULL) { - return NT_STATUS_NO_MEMORY; - } - for (i=0;i<r->out.names->count;i++) { - r->out.names->names[i].sid_type = r2.out.names->names[i].sid_type; - r->out.names->names[i].name.string = r2.out.names->names[i].name.string; - r->out.names->names[i].sid_index = r2.out.names->names[i].sid_index; - } - - return status; -} - - /* lsa_OpenAccount */ @@ -3007,293 +2456,6 @@ static NTSTATUS dcesrv_lsa_TestCall(struct dcesrv_call_state *dce_call, DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); } -/* - lookup a SID for 1 name -*/ -static NTSTATUS dcesrv_lsa_lookup_name(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, - const char *name, struct dom_sid **sid, uint32_t *atype) -{ - int ret; - struct ldb_message **res; - const char * const attrs[] = { "objectSid", "sAMAccountType", NULL}; - const char *p; - - p = strchr_m(name, '\\'); - if (p != NULL) { - /* TODO: properly parse the domain prefix here, and use it to - limit the search */ - name = p + 1; - } - - ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, "sAMAccountName=%s", ldb_binary_encode_string(mem_ctx, name)); - if (ret == 1) { - *sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); - if (*sid == NULL) { - return NT_STATUS_INVALID_SID; - } - - *atype = samdb_result_uint(res[0], "sAMAccountType", 0); - - return NT_STATUS_OK; - } - - /* need to add a call into sidmap to check for a allocated sid */ - - return NT_STATUS_INVALID_SID; -} - - -/* - lsa_LookupNames3 -*/ -static NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - struct lsa_LookupNames3 *r) -{ - struct lsa_policy_state *policy_state; - struct dcesrv_handle *policy_handle; - int i; - NTSTATUS status = NT_STATUS_OK; - - DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); - - policy_state = policy_handle->data; - - r->out.domains = NULL; - - r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); - if (r->out.domains == NULL) { - return NT_STATUS_NO_MEMORY; - } - - r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); - if (r->out.sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.count = 0; - - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3, - r->in.num_names); - if (r->out.sids->sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0;i<r->in.num_names;i++) { - const char *name = r->in.names[i].string; - struct dom_sid *sid; - uint32_t atype, rtype, sid_index; - NTSTATUS status2; - - r->out.sids->count++; - (*r->out.count)++; - - r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN; - r->out.sids->sids[i].sid = NULL; - r->out.sids->sids[i].sid_index = 0xFFFFFFFF; - r->out.sids->sids[i].unknown = 0; - - status2 = dcesrv_lsa_lookup_name(policy_state, mem_ctx, name, &sid, &atype); - if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - rtype = samdb_atype_map(atype); - if (rtype == SID_NAME_UNKNOWN) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, sid, r->out.domains, &sid_index); - if (!NT_STATUS_IS_OK(status2)) { - return status2; - } - - r->out.sids->sids[i].sid_type = rtype; - r->out.sids->sids[i].sid = sid; - r->out.sids->sids[i].sid_index = sid_index; - r->out.sids->sids[i].unknown = 0; - } - - return status; -} - -/* - lsa_LookupNames4 - - Identical to LookupNames3, but doesn't take a policy handle - -*/ -static NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_LookupNames4 *r) -{ - struct lsa_LookupNames3 r2; - struct lsa_OpenPolicy2 pol; - NTSTATUS status; - struct dcesrv_handle *h; - - /* No policy handle on the wire, so make one up here */ - r2.in.handle = talloc(mem_ctx, struct policy_handle); - if (!r2.in.handle) { - return NT_STATUS_NO_MEMORY; - } - - pol.out.handle = r2.in.handle; - pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - pol.in.attr = NULL; - pol.in.system_name = NULL; - status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* ensure this handle goes away at the end of this call */ - DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY); - talloc_steal(mem_ctx, h); - - r2.in.num_names = r->in.num_names; - r2.in.names = r->in.names; - r2.in.sids = r->in.sids; - r2.in.count = r->in.count; - r2.in.unknown1 = r->in.unknown1; - r2.in.unknown2 = r->in.unknown2; - r2.out.domains = r->out.domains; - r2.out.sids = r->out.sids; - r2.out.count = r->out.count; - - status = dcesrv_lsa_LookupNames3(dce_call, mem_ctx, &r2); - if (dce_call->fault_code != 0) { - return status; - } - - r->out.domains = r2.out.domains; - r->out.sids = r2.out.sids; - r->out.count = r2.out.count; - return status; -} - -/* - lsa_LookupNames2 -*/ -static NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - struct lsa_LookupNames2 *r) -{ - struct lsa_policy_state *state; - struct dcesrv_handle *h; - int i; - NTSTATUS status = NT_STATUS_OK; - - r->out.domains = NULL; - - DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY); - - state = h->data; - - r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); - if (r->out.domains == NULL) { - return NT_STATUS_NO_MEMORY; - } - - r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); - if (r->out.sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.count = 0; - - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2, - r->in.num_names); - if (r->out.sids->sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0;i<r->in.num_names;i++) { - const char *name = r->in.names[i].string; - struct dom_sid *sid; - uint32_t atype, rtype, sid_index; - NTSTATUS status2; - - r->out.sids->count++; - (*r->out.count)++; - - r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN; - r->out.sids->sids[i].rid = 0xFFFFFFFF; - r->out.sids->sids[i].sid_index = 0xFFFFFFFF; - r->out.sids->sids[i].unknown = 0; - - status2 = dcesrv_lsa_lookup_name(state, mem_ctx, name, &sid, &atype); - if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - rtype = samdb_atype_map(atype); - if (rtype == SID_NAME_UNKNOWN) { - status = STATUS_SOME_UNMAPPED; - continue; - } - - status2 = dcesrv_lsa_authority_list(state, mem_ctx, sid, r->out.domains, &sid_index); - if (!NT_STATUS_IS_OK(status2)) { - return status2; - } - - r->out.sids->sids[i].sid_type = rtype; - r->out.sids->sids[i].rid = sid->sub_auths[sid->num_auths-1]; - r->out.sids->sids[i].sid_index = sid_index; - r->out.sids->sids[i].unknown = 0; - } - - return status; -} - -/* - lsa_LookupNames -*/ -static NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_LookupNames *r) -{ - struct lsa_LookupNames2 r2; - NTSTATUS status; - int i; - - r2.in.handle = r->in.handle; - r2.in.num_names = r->in.num_names; - r2.in.names = r->in.names; - r2.in.sids = NULL; - r2.in.level = r->in.level; - r2.in.count = r->in.count; - r2.in.unknown1 = 0; - r2.in.unknown2 = 0; - r2.out.count = r->out.count; - - status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2); - if (dce_call->fault_code != 0) { - return status; - } - - r->out.domains = r2.out.domains; - r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray); - if (r->out.sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - r->out.sids->count = r2.out.sids->count; - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid, - r->out.sids->count); - if (r->out.sids->sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - for (i=0;i<r->out.sids->count;i++) { - r->out.sids->sids[i].sid_type = r2.out.sids->sids[i].sid_type; - r->out.sids->sids[i].rid = r2.out.sids->sids[i].rid; - r->out.sids->sids[i].sid_index = r2.out.sids->sids[i].sid_index; - } - - return status; -} - /* lsa_CREDRWRITE */ diff --git a/source4/rpc_server/lsa/lsa.h b/source4/rpc_server/lsa/lsa.h new file mode 100644 index 0000000000..6ecda0ff82 --- /dev/null +++ b/source4/rpc_server/lsa/lsa.h @@ -0,0 +1,69 @@ +/* + Unix SMB/CIFS implementation. + + endpoint server for the lsarpc pipe + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 + + 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 Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpc_server/dcerpc_server.h" +#include "rpc_server/common/common.h" +#include "auth/auth.h" +#include "dsdb/samdb/samdb.h" +#include "libcli/ldap/ldap.h" +#include "lib/ldb/include/ldb_errors.h" +#include "libcli/security/security.h" +#include "libcli/auth/libcli_auth.h" +#include "param/secrets.h" +#include "db_wrap.h" +#include "librpc/gen_ndr/ndr_dssetup.h" +#include "param/param.h" + +/* + state associated with a lsa_OpenPolicy() operation +*/ +struct lsa_policy_state { + struct dcesrv_handle *handle; + struct ldb_context *sam_ldb; + struct sidmap_context *sidmap; + uint32_t access_mask; + struct ldb_dn *domain_dn; + struct ldb_dn *forest_dn; + struct ldb_dn *builtin_dn; + struct ldb_dn *system_dn; + const char *domain_name; + const char *domain_dns; + const char *forest_dns; + struct dom_sid *domain_sid; + struct GUID domain_guid; + struct dom_sid *builtin_sid; + struct dom_sid *nt_authority_sid; + struct dom_sid *creator_owner_domain_sid; + struct dom_sid *world_domain_sid; + int mixed_domain; +}; + +enum lsa_handle { + LSA_HANDLE_POLICY, + LSA_HANDLE_ACCOUNT, + LSA_HANDLE_SECRET, + LSA_HANDLE_TRUSTED_DOMAIN +}; + +#include "rpc_server/lsa/proto.h" + diff --git a/source4/rpc_server/lsa/lsa_init.c b/source4/rpc_server/lsa/lsa_init.c new file mode 100644 index 0000000000..6cf062a22a --- /dev/null +++ b/source4/rpc_server/lsa/lsa_init.c @@ -0,0 +1,248 @@ +/* + Unix SMB/CIFS implementation. + + endpoint server for the lsarpc pipe + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2007 + + 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 Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "rpc_server/lsa/lsa.h" + +NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct lsa_policy_state **_state) +{ + struct lsa_policy_state *state; + struct ldb_dn *partitions_basedn; + struct ldb_result *dom_res; + const char *dom_attrs[] = { + "objectSid", + "objectGUID", + "nTMixedDomain", + "fSMORoleOwner", + NULL + }; + struct ldb_result *ref_res; + struct ldb_result *forest_ref_res; + const char *ref_attrs[] = { + "nETBIOSName", + "dnsRoot", + NULL + }; + int ret; + + state = talloc(mem_ctx, struct lsa_policy_state); + if (!state) { + return NT_STATUS_NO_MEMORY; + } + + /* make sure the sam database is accessible */ + state->sam_ldb = samdb_connect(state, dce_call->conn->auth_state.session_info); + if (state->sam_ldb == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx); + + state->sidmap = sidmap_open(state); + if (state->sidmap == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + /* work out the domain_dn - useful for so many calls its worth + fetching here */ + state->domain_dn = samdb_base_dn(state->sam_ldb); + if (!state->domain_dn) { + return NT_STATUS_NO_MEMORY; + } + + /* work out the forest root_dn - useful for so many calls its worth + fetching here */ + state->forest_dn = samdb_root_dn(state->sam_ldb); + if (!state->forest_dn) { + return NT_STATUS_NO_MEMORY; + } + + ret = ldb_search(state->sam_ldb, state->domain_dn, LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res); + + if (ret != LDB_SUCCESS) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + talloc_steal(mem_ctx, dom_res); + if (dom_res->count != 1) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid"); + if (!state->domain_sid) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); + if (!state->domain_sid) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0); + + talloc_free(dom_res); + + ret = ldb_search_exp_fmt(state->sam_ldb, state, &ref_res, + partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs, + "(&(objectclass=crossRef)(ncName=%s))", + ldb_dn_get_linearized(state->domain_dn)); + + if (ret != LDB_SUCCESS) { + talloc_free(ref_res); + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + if (ref_res->count != 1) { + talloc_free(ref_res); + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->domain_name = ldb_msg_find_attr_as_string(ref_res->msgs[0], "nETBIOSName", NULL); + if (!state->domain_name) { + talloc_free(ref_res); + return NT_STATUS_NO_SUCH_DOMAIN; + } + talloc_steal(state, state->domain_name); + + state->domain_dns = ldb_msg_find_attr_as_string(ref_res->msgs[0], "dnsRoot", NULL); + if (!state->domain_dns) { + talloc_free(ref_res); + return NT_STATUS_NO_SUCH_DOMAIN; + } + talloc_steal(state, state->domain_dns); + + talloc_free(ref_res); + + ret = ldb_search_exp_fmt(state->sam_ldb, state, &forest_ref_res, + partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs, + "(&(objectclass=crossRef)(ncName=%s))", + ldb_dn_get_linearized(state->forest_dn)); + + if (ret != LDB_SUCCESS) { + talloc_free(forest_ref_res); + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + if (forest_ref_res->count != 1) { + talloc_free(forest_ref_res); + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->forest_dns = ldb_msg_find_attr_as_string(forest_ref_res->msgs[0], "dnsRoot", NULL); + if (!state->forest_dns) { + talloc_free(forest_ref_res); + return NT_STATUS_NO_SUCH_DOMAIN; + } + talloc_steal(state, state->forest_dns); + + talloc_free(forest_ref_res); + + /* work out the builtin_dn - useful for so many calls its worth + fetching here */ + state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)"); + if (!state->builtin_dn) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + /* work out the system_dn - useful for so many calls its worth + fetching here */ + state->system_dn = samdb_search_dn(state->sam_ldb, state, + state->domain_dn, "(&(objectClass=container)(cn=System))"); + if (!state->system_dn) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN); + if (!state->builtin_sid) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->nt_authority_sid = dom_sid_parse_talloc(state, SID_NT_AUTHORITY); + if (!state->nt_authority_sid) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->creator_owner_domain_sid = dom_sid_parse_talloc(state, SID_CREATOR_OWNER_DOMAIN); + if (!state->creator_owner_domain_sid) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + state->world_domain_sid = dom_sid_parse_talloc(state, SID_WORLD_DOMAIN); + if (!state->world_domain_sid) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + *_state = state; + + return NT_STATUS_OK; +} + +/* + lsa_OpenPolicy2 +*/ +NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct lsa_OpenPolicy2 *r) +{ + NTSTATUS status; + struct lsa_policy_state *state; + struct dcesrv_handle *handle; + + ZERO_STRUCTP(r->out.handle); + + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_POLICY); + if (!handle) { + return NT_STATUS_NO_MEMORY; + } + + handle->data = talloc_steal(handle, state); + + state->access_mask = r->in.access_mask; + state->handle = handle; + *r->out.handle = handle->wire_handle; + + /* note that we have completely ignored the attr element of + the OpenPolicy. As far as I can tell, this is what w2k3 + does */ + + return NT_STATUS_OK; +} + +/* + lsa_OpenPolicy + a wrapper around lsa_OpenPolicy2 +*/ +NTSTATUS dcesrv_lsa_OpenPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct lsa_OpenPolicy *r) +{ + struct lsa_OpenPolicy2 r2; + + r2.in.system_name = NULL; + r2.in.attr = r->in.attr; + r2.in.access_mask = r->in.access_mask; + r2.out.handle = r->out.handle; + + return dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &r2); +} + + diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c new file mode 100644 index 0000000000..4ca3e4d51e --- /dev/null +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -0,0 +1,928 @@ +/* + Unix SMB/CIFS implementation. + + endpoint server for the lsarpc pipe + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2007 + + 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 Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "rpc_server/lsa/lsa.h" + +static const struct { + const char *domain; + const char *name; + const char *sid; + int rtype; +} well_known[] = { + { + .name = "EVERYONE", + .sid = SID_WORLD, + .rtype = SID_NAME_WKN_GRP, + }, + { + .name = "CREATOR OWNER", + .sid = SID_CREATOR_OWNER, + .rtype = SID_NAME_WKN_GRP, + }, + { + .name = "CREATOR GROUP", + .sid = SID_CREATOR_OWNER, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Dialup", + .sid = SID_NT_DIALUP, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Network", + .sid = SID_NT_DIALUP, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Batch", + .sid = SID_NT_BATCH, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Interactive", + .sid = SID_NT_INTERACTIVE, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Service", + .sid = SID_NT_SERVICE, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "ANONYMOUS LOGON", + .sid = SID_NT_ANONYMOUS, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Proxy", + .sid = SID_NT_PROXY, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "ServerLogon", + .sid = SID_NT_ENTERPRISE_DCS, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Self", + .sid = SID_NT_SELF, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Authenticated Users", + .sid = SID_NT_AUTHENTICATED_USERS, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Restricted", + .sid = SID_NT_RESTRICTED, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Termainal Server User", + .sid = SID_NT_TERMINAL_SERVER_USERS, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Remote Interactive Logon", + .sid = SID_NT_REMOTE_INTERACTIVE, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "This Organization", + .sid = SID_NT_THIS_ORGANISATION, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "SYSTEM", + .sid = SID_NT_SYSTEM, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Local Service", + .sid = SID_NT_LOCAL_SERVICE, + .rtype = SID_NAME_WKN_GRP, + }, + { + .domain = "NT AUTHORITY", + .name = "Network Service", + .sid = SID_NT_NETWORK_SERVICE, + .rtype = SID_NAME_WKN_GRP, + }, + { + .sid = NULL, + } +}; + +static NTSTATUS lookup_well_known_names(TALLOC_CTX *mem_ctx, const char *domain, + const char *name, const char **authority_name, + struct dom_sid **sid, uint32_t *rtype) +{ + int i; + for (i=0; well_known[i].sid; i++) { + if (domain) { + if (strcasecmp_m(domain, well_known[i].domain) == 0 + && strcasecmp_m(name, well_known[i].name) == 0) { + *authority_name = well_known[i].domain; + *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid); + *rtype = well_known[i].rtype; + return NT_STATUS_OK; + } + } else { + if (strcasecmp_m(name, well_known[i].name) == 0) { + *authority_name = well_known[i].domain; + *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid); + *rtype = well_known[i].rtype; + return NT_STATUS_OK; + } + } + } + return NT_STATUS_NOT_FOUND; +} + +static NTSTATUS lookup_well_known_sids(TALLOC_CTX *mem_ctx, + const char *sid_str, const char **authority_name, + const char **name, uint32_t *rtype) +{ + int i; + for (i=0; well_known[i].sid; i++) { + if (strcasecmp_m(sid_str, well_known[i].sid) == 0) { + *authority_name = well_known[i].domain; + *name = well_known[i].name; + *rtype = well_known[i].rtype; + return NT_STATUS_OK; + } + } + return NT_STATUS_NOT_FOUND; +} + +/* + lookup a SID for 1 name +*/ +static NTSTATUS dcesrv_lsa_lookup_name(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, + const char *name, const char **authority_name, + struct dom_sid **sid, enum lsa_SidType *rtype) +{ + int ret, atype, i; + 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, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username); + if (!NT_STATUS_IS_OK(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)) { + 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; + 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; + 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; + 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; + 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(state, mem_ctx, name, authority_name, sid, rtype); + 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(state, mem_ctx, name, authority_name, sid, rtype); + 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(state, mem_ctx, name, authority_name, sid, rtype); + 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; + return NT_STATUS_OK; + } + + /* Look up table of well known names */ + return lookup_well_known_names(mem_ctx, domain, username, authority_name, + sid, rtype); + } 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; + 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 = samdb_atype_map(atype); + if (*rtype == SID_NAME_UNKNOWN) { + return STATUS_SOME_UNMAPPED; + } + + return NT_STATUS_OK; + } + + /* need to add a call into sidmap to check for a allocated sid */ + + return NT_STATUS_INVALID_SID; +} + + +/* + add to the lsa_RefDomainList for LookupSids and LookupNames +*/ +static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, + enum lsa_SidType rtype, + const char *authority_name, + struct dom_sid *sid, + struct lsa_RefDomainList *domains, + uint32_t *sid_index) +{ + struct dom_sid *authority_sid; + int i; + + if (rtype != SID_NAME_DOMAIN) { + authority_sid = dom_sid_dup(mem_ctx, sid); + if (authority_sid == NULL) { + return NT_STATUS_NO_MEMORY; + } + authority_sid->num_auths--; + } else { + authority_sid = sid; + } + + /* see if we've already done this authority name */ + for (i=0;i<domains->count;i++) { + if (strcasecmp_m(authority_name, domains->domains[i].name.string) == 0) { + *sid_index = i; + return NT_STATUS_OK; + } + } + + domains->domains = talloc_realloc(domains, + domains->domains, + struct lsa_DomainInfo, + domains->count+1); + if (domains->domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + domains->domains[i].name.string = authority_name; + domains->domains[i].sid = authority_sid; + domains->count++; + domains->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER * domains->count; + *sid_index = i; + + return NT_STATUS_OK; +} + +/* + 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 = samdb_atype_map(atype); + + return NT_STATUS_OK; + } + + /* need to re-add a call into sidmap to check for a allocated sid */ + /* status = sidmap_allocated_sid_lookup(state->sidmap, mem_ctx, sid, name, rtype); */ + + return NT_STATUS_NOT_FOUND; +} + + +/* + lsa_LookupSids2 +*/ +NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct lsa_LookupSids2 *r) +{ + struct lsa_policy_state *state; + int i; + NTSTATUS status = NT_STATUS_OK; + + r->out.domains = NULL; + + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); + if (r->out.domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + + r->out.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); + if (r->out.names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + *r->out.count = 0; + + r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2, + r->in.sids->num_sids); + if (r->out.names->names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0;i<r->in.sids->num_sids;i++) { + struct dom_sid *sid = r->in.sids->sids[i].sid; + char *sid_str = dom_sid_string(mem_ctx, sid); + const char *name, *authority_name; + enum lsa_SidType rtype; + uint32_t sid_index; + NTSTATUS status2; + + r->out.names->count++; + + r->out.names->names[i].sid_type = SID_NAME_UNKNOWN; + r->out.names->names[i].name.string = sid_str; + r->out.names->names[i].sid_index = 0xFFFFFFFF; + r->out.names->names[i].unknown = 0; + + if (sid_str == NULL) { + r->out.names->names[i].name.string = "(SIDERROR)"; + status = STATUS_SOME_UNMAPPED; + continue; + } + + status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str, + &authority_name, &name, &rtype); + if (!NT_STATUS_IS_OK(status2)) { + status = STATUS_SOME_UNMAPPED; + continue; + } + + /* set up the authority table */ + status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, + authority_name, sid, + r->out.domains, &sid_index); + if (!NT_STATUS_IS_OK(status2)) { + return status2; + } + + r->out.names->names[i].sid_type = rtype; + r->out.names->names[i].name.string = name; + r->out.names->names[i].sid_index = sid_index; + r->out.names->names[i].unknown = 0; + + (*r->out.count)++; + } + + if (*r->out.count == 0) { + return NT_STATUS_NONE_MAPPED; + } + if (*r->out.count != r->in.sids->num_sids) { + return STATUS_SOME_UNMAPPED; + } + + return NT_STATUS_OK; +} + + +/* + lsa_LookupSids3 + + Identical to LookupSids2, but doesn't take a policy handle + +*/ +NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct lsa_LookupSids3 *r) +{ + struct lsa_LookupSids2 r2; + struct lsa_OpenPolicy2 pol; + NTSTATUS status; + struct dcesrv_handle *h; + + /* No policy handle on the wire, so make one up here */ + r2.in.handle = talloc(mem_ctx, struct policy_handle); + if (!r2.in.handle) { + return NT_STATUS_NO_MEMORY; + } + + pol.out.handle = r2.in.handle; + pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + pol.in.attr = NULL; + pol.in.system_name = NULL; + status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* ensure this handle goes away at the end of this call */ + DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY); + talloc_steal(mem_ctx, h); + + r2.in.sids = r->in.sids; + r2.in.names = r->in.names; + r2.in.level = r->in.level; + r2.in.count = r->in.count; + r2.in.unknown1 = r->in.unknown1; + r2.in.unknown2 = r->in.unknown2; + r2.out.count = r->out.count; + r2.out.names = r->out.names; + + status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2); + if (dce_call->fault_code != 0) { + return status; + } + + r->out.domains = r2.out.domains; + r->out.names = r2.out.names; + r->out.count = r2.out.count; + + return status; +} + + +/* + lsa_LookupSids +*/ +NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct lsa_LookupSids *r) +{ + struct lsa_LookupSids2 r2; + NTSTATUS status; + int i; + + r2.in.handle = r->in.handle; + r2.in.sids = r->in.sids; + r2.in.names = NULL; + r2.in.level = r->in.level; + r2.in.count = r->in.count; + r2.in.unknown1 = 0; + r2.in.unknown2 = 0; + r2.out.count = r->out.count; + r2.out.names = NULL; + + status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2); + if (dce_call->fault_code != 0) { + return status; + } + + r->out.domains = r2.out.domains; + if (!r2.out.names) { + r->out.names = NULL; + return status; + } + + r->out.names = talloc(mem_ctx, struct lsa_TransNameArray); + if (r->out.names == NULL) { + return NT_STATUS_NO_MEMORY; + } + r->out.names->count = r2.out.names->count; + r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName, + r->out.names->count); + if (r->out.names->names == NULL) { + return NT_STATUS_NO_MEMORY; + } + for (i=0;i<r->out.names->count;i++) { + r->out.names->names[i].sid_type = r2.out.names->names[i].sid_type; + r->out.names->names[i].name.string = r2.out.names->names[i].name.string; + r->out.names->names[i].sid_index = r2.out.names->names[i].sid_index; + } + + return status; +} + + +/* + lsa_LookupNames3 +*/ +NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct lsa_LookupNames3 *r) +{ + struct lsa_policy_state *policy_state; + struct dcesrv_handle *policy_handle; + int i; + + DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); + + policy_state = policy_handle->data; + + r->out.domains = NULL; + + r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); + if (r->out.domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + + r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); + if (r->out.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + *r->out.count = 0; + + r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3, + r->in.num_names); + if (r->out.sids->sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0;i<r->in.num_names;i++) { + const char *name = r->in.names[i].string; + const char *authority_name; + struct dom_sid *sid; + uint32_t sid_index; + enum lsa_SidType rtype; + NTSTATUS status2; + + r->out.sids->count++; + + r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN; + r->out.sids->sids[i].sid = NULL; + r->out.sids->sids[i].sid_index = 0xFFFFFFFF; + r->out.sids->sids[i].unknown = 0; + + status2 = dcesrv_lsa_lookup_name(policy_state, mem_ctx, name, &authority_name, &sid, &rtype); + if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) { + continue; + } + + status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, authority_name, + sid, r->out.domains, &sid_index); + if (!NT_STATUS_IS_OK(status2)) { + return status2; + } + + r->out.sids->sids[i].sid_type = rtype; + r->out.sids->sids[i].sid = sid; + r->out.sids->sids[i].sid_index = sid_index; + r->out.sids->sids[i].unknown = 0; + + (*r->out.count)++; + } + + if (*r->out.count == 0) { + return NT_STATUS_NONE_MAPPED; + } + if (*r->out.count != r->in.num_names) { + return STATUS_SOME_UNMAPPED; + } + + return NT_STATUS_OK; +} + +/* + lsa_LookupNames4 + + Identical to LookupNames3, but doesn't take a policy handle + +*/ +NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct lsa_LookupNames4 *r) +{ + struct lsa_LookupNames3 r2; + struct lsa_OpenPolicy2 pol; + NTSTATUS status; + struct dcesrv_handle *h; + + /* No policy handle on the wire, so make one up here */ + r2.in.handle = talloc(mem_ctx, struct policy_handle); + if (!r2.in.handle) { + return NT_STATUS_NO_MEMORY; + } + + pol.out.handle = r2.in.handle; + pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + pol.in.attr = NULL; + pol.in.system_name = NULL; + status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* ensure this handle goes away at the end of this call */ + DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY); + talloc_steal(mem_ctx, h); + + r2.in.num_names = r->in.num_names; + r2.in.names = r->in.names; + r2.in.sids = r->in.sids; + r2.in.count = r->in.count; + r2.in.unknown1 = r->in.unknown1; + r2.in.unknown2 = r->in.unknown2; + r2.out.domains = r->out.domains; + r2.out.sids = r->out.sids; + r2.out.count = r->out.count; + + status = dcesrv_lsa_LookupNames3(dce_call, mem_ctx, &r2); + if (dce_call->fault_code != 0) { + return status; + } + + r->out.domains = r2.out.domains; + r->out.sids = r2.out.sids; + r->out.count = r2.out.count; + return status; +} + +/* + lsa_LookupNames2 +*/ +NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct lsa_LookupNames2 *r) +{ + struct lsa_policy_state *state; + struct dcesrv_handle *h; + int i; + + r->out.domains = NULL; + + DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY); + + state = h->data; + + r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); + if (r->out.domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + + r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); + if (r->out.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + *r->out.count = 0; + + r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2, + r->in.num_names); + if (r->out.sids->sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0;i<r->in.num_names;i++) { + const char *name = r->in.names[i].string; + const char *authority_name; + struct dom_sid *sid; + uint32_t rtype, sid_index; + NTSTATUS status2; + + r->out.sids->count++; + + r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN; + r->out.sids->sids[i].rid = 0xFFFFFFFF; + r->out.sids->sids[i].sid_index = 0xFFFFFFFF; + r->out.sids->sids[i].unknown = 0; + + status2 = dcesrv_lsa_lookup_name(state, mem_ctx, name, + &authority_name, &sid, &rtype); + if (!NT_STATUS_IS_OK(status2)) { + continue; + } + + status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, authority_name, + sid, r->out.domains, &sid_index); + if (!NT_STATUS_IS_OK(status2)) { + return status2; + } + + r->out.sids->sids[i].sid_type = rtype; + r->out.sids->sids[i].rid = sid->sub_auths[sid->num_auths-1]; + r->out.sids->sids[i].sid_index = sid_index; + r->out.sids->sids[i].unknown = 0; + + (*r->out.count)++; + } + + if (*r->out.count == 0) { + return NT_STATUS_NONE_MAPPED; + } + if (*r->out.count != r->in.num_names) { + return STATUS_SOME_UNMAPPED; + } + + return NT_STATUS_OK; +} + +/* + lsa_LookupNames +*/ +NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct lsa_LookupNames *r) +{ + struct lsa_LookupNames2 r2; + NTSTATUS status; + int i; + + r2.in.handle = r->in.handle; + r2.in.num_names = r->in.num_names; + r2.in.names = r->in.names; + r2.in.sids = NULL; + r2.in.level = r->in.level; + r2.in.count = r->in.count; + r2.in.unknown1 = 0; + r2.in.unknown2 = 0; + r2.out.count = r->out.count; + + status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2); + if (dce_call->fault_code != 0) { + return status; + } + + r->out.domains = r2.out.domains; + r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray); + if (r->out.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + r->out.sids->count = r2.out.sids->count; + r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid, + r->out.sids->count); + if (r->out.sids->sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + for (i=0;i<r->out.sids->count;i++) { + r->out.sids->sids[i].sid_type = r2.out.sids->sids[i].sid_type; + r->out.sids->sids[i].rid = r2.out.sids->sids[i].rid; + r->out.sids->sids[i].sid_index = r2.out.sids->sids[i].sid_index; + } + + return status; +} + |