mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
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 e6fc0e1f54
)
This commit is contained in:
parent
ffbb7e4060
commit
08c97435d3
@ -550,13 +550,13 @@ _PUBLIC_ NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const struct dom_sid *sid,
|
||||
const char **name,
|
||||
uint32_t *atype)
|
||||
enum lsa_SidType *rtype)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dom_sid *domain_sid;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
||||
uint32_t rid;
|
||||
|
||||
uint32_t rid, atype;
|
||||
|
||||
status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return NT_STATUS_NO_SUCH_DOMAIN;
|
||||
@ -577,7 +577,9 @@ _PUBLIC_ NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap,
|
||||
if (rid < SIDMAP_LOCAL_GROUP_BASE) {
|
||||
struct passwd *pwd;
|
||||
uid_t uid = rid - SIDMAP_LOCAL_USER_BASE;
|
||||
*atype = ATYPE_NORMAL_ACCOUNT;
|
||||
atype = ATYPE_NORMAL_ACCOUNT;
|
||||
*rtype = samdb_atype_map(atype);
|
||||
|
||||
pwd = getpwuid(uid);
|
||||
if (pwd == NULL) {
|
||||
*name = talloc_asprintf(mem_ctx, "uid%u", uid);
|
||||
@ -587,7 +589,8 @@ _PUBLIC_ NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap,
|
||||
} else {
|
||||
struct group *grp;
|
||||
gid_t gid = rid - SIDMAP_LOCAL_GROUP_BASE;
|
||||
*atype = ATYPE_LOCAL_GROUP;
|
||||
atype = ATYPE_LOCAL_GROUP;
|
||||
*rtype = samdb_atype_map(atype);
|
||||
grp = getgrgid(gid);
|
||||
if (grp == NULL) {
|
||||
*name = talloc_asprintf(mem_ctx, "gid%u", gid);
|
||||
|
@ -138,6 +138,8 @@ interface security
|
||||
const string SID_NULL = "S-1-0-0";
|
||||
|
||||
/* the world domain */
|
||||
const string NAME_WORLD = "WORLD";
|
||||
|
||||
const string SID_WORLD_DOMAIN = "S-1-1";
|
||||
const string SID_WORLD = "S-1-1-0";
|
||||
|
||||
@ -147,6 +149,8 @@ interface security
|
||||
const string SID_CREATOR_GROUP = "S-1-3-1";
|
||||
|
||||
/* SECURITY_NT_AUTHORITY */
|
||||
const string NAME_NT_AUTHORITY = "NT AUTHORITY";
|
||||
|
||||
const string SID_NT_AUTHORITY = "S-1-5";
|
||||
const string SID_NT_DIALUP = "S-1-5-1";
|
||||
const string SID_NT_NETWORK = "S-1-5-2";
|
||||
@ -167,6 +171,8 @@ interface security
|
||||
const string SID_NT_NETWORK_SERVICE = "S-1-5-20";
|
||||
|
||||
/* SECURITY_BUILTIN_DOMAIN_RID */
|
||||
const string NAME_BUILTIN = "BUILTIN";
|
||||
|
||||
const string SID_BUILTIN = "S-1-5-32";
|
||||
const string SID_BUILTIN_ADMINISTRATORS = "S-1-5-32-544";
|
||||
const string SID_BUILTIN_USERS = "S-1-5-32-545";
|
||||
|
@ -135,8 +135,11 @@ PRIVATE_DEPENDENCIES = \
|
||||
[MODULE::dcerpc_lsarpc]
|
||||
INIT_FUNCTION = dcerpc_server_lsa_init
|
||||
SUBSYSTEM = dcerpc_server
|
||||
PRIVATE_PROTO_HEADER= lsa/proto.h
|
||||
OBJ_FILES = \
|
||||
lsa/dcesrv_lsa.o
|
||||
lsa/dcesrv_lsa.o \
|
||||
lsa/lsa_init.o \
|
||||
lsa/lsa_lookup.o
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
SAMDB \
|
||||
DCERPC_COMMON \
|
||||
|
@ -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
|
||||
*/
|
||||
|
69
source4/rpc_server/lsa/lsa.h
Normal file
69
source4/rpc_server/lsa/lsa.h
Normal file
@ -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"
|
||||
|
248
source4/rpc_server/lsa/lsa_init.c
Normal file
248
source4/rpc_server/lsa/lsa_init.c
Normal file
@ -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);
|
||||
}
|
||||
|
||||
|
928
source4/rpc_server/lsa/lsa_lookup.c
Normal file
928
source4/rpc_server/lsa/lsa_lookup.c
Normal file
@ -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;
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ BOOL test_lsa_OpenPolicy2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
|
||||
static BOOL test_LookupNames(struct dcerpc_pipe *p,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct policy_handle *handle,
|
||||
struct lsa_TransNameArray *tnames)
|
||||
struct lsa_TransNameArray *tnames)
|
||||
{
|
||||
struct lsa_LookupNames r;
|
||||
struct lsa_TransSidArray sids;
|
||||
@ -157,7 +157,7 @@ static BOOL test_LookupNames(struct dcerpc_pipe *p,
|
||||
r.out.sids = &sids;
|
||||
|
||||
status = dcerpc_lsa_LookupNames(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupNames failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -167,6 +167,95 @@ static BOOL test_LookupNames(struct dcerpc_pipe *p,
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL test_LookupNames_bogus(struct dcerpc_pipe *p,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct policy_handle *handle)
|
||||
{
|
||||
struct lsa_LookupNames r;
|
||||
struct lsa_TransSidArray sids;
|
||||
struct lsa_String *names;
|
||||
uint32_t count = 0;
|
||||
NTSTATUS status;
|
||||
int i;
|
||||
|
||||
struct lsa_TranslatedName name;
|
||||
struct lsa_TransNameArray tnames;
|
||||
|
||||
tnames.names = &name;
|
||||
tnames.count = 1;
|
||||
name.name.string = "NT AUTHORITY\\BOGUS";
|
||||
|
||||
printf("\nTesting LookupNames with bogus names\n");
|
||||
|
||||
sids.count = 0;
|
||||
sids.sids = NULL;
|
||||
|
||||
names = talloc_array(mem_ctx, struct lsa_String, tnames.count);
|
||||
for (i=0;i<tnames.count;i++) {
|
||||
init_lsa_String(&names[i], tnames.names[i].name.string);
|
||||
}
|
||||
|
||||
r.in.handle = handle;
|
||||
r.in.num_names = tnames.count;
|
||||
r.in.names = names;
|
||||
r.in.sids = &sids;
|
||||
r.in.level = 1;
|
||||
r.in.count = &count;
|
||||
r.out.count = &count;
|
||||
r.out.sids = &sids;
|
||||
|
||||
status = dcerpc_lsa_LookupNames(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
|
||||
printf("LookupNames failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL test_LookupNames_wellknown(struct dcerpc_pipe *p,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct policy_handle *handle)
|
||||
{
|
||||
struct lsa_TranslatedName name;
|
||||
struct lsa_TransNameArray tnames;
|
||||
bool ret = true;
|
||||
|
||||
printf("Testing LookupNames with well known names\n");
|
||||
|
||||
tnames.names = &name;
|
||||
tnames.count = 1;
|
||||
name.name.string = "NT AUTHORITY\\SYSTEM";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "NT AUTHORITY\\ANONYMOUS LOGON";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "NT AUTHORITY\\Authenticated Users";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "NT AUTHORITY";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "NT AUTHORITY\\";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "BUILTIN\\";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "BUILTIN\\Administrators";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "SYSTEM";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
|
||||
name.name.string = "Everyone";
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL test_LookupNames2(struct dcerpc_pipe *p,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct policy_handle *handle,
|
||||
@ -201,7 +290,7 @@ static BOOL test_LookupNames2(struct dcerpc_pipe *p,
|
||||
r.out.sids = &sids;
|
||||
|
||||
status = dcerpc_lsa_LookupNames2(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupNames2 failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -246,7 +335,7 @@ static BOOL test_LookupNames3(struct dcerpc_pipe *p,
|
||||
r.out.sids = &sids;
|
||||
|
||||
status = dcerpc_lsa_LookupNames3(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupNames3 failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -288,7 +377,7 @@ static BOOL test_LookupNames4(struct dcerpc_pipe *p,
|
||||
r.out.sids = &sids;
|
||||
|
||||
status = dcerpc_lsa_LookupNames4(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupNames4 failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -323,7 +412,7 @@ static BOOL test_LookupSids(struct dcerpc_pipe *p,
|
||||
r.out.names = &names;
|
||||
|
||||
status = dcerpc_lsa_LookupSids(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupSids failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -364,7 +453,7 @@ static BOOL test_LookupSids2(struct dcerpc_pipe *p,
|
||||
r.out.names = &names;
|
||||
|
||||
status = dcerpc_lsa_LookupSids2(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupSids2 failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -406,7 +495,7 @@ static BOOL test_LookupSids3(struct dcerpc_pipe *p,
|
||||
r.out.names = &names;
|
||||
|
||||
status = dcerpc_lsa_LookupSids3(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
|
||||
NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
|
||||
printf("not considering %s to be an error\n", nt_errstr(status));
|
||||
@ -463,8 +552,7 @@ BOOL test_many_LookupSids(struct dcerpc_pipe *p,
|
||||
r.out.names = &names;
|
||||
|
||||
status = dcerpc_lsa_LookupSids(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) &&
|
||||
!NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("LookupSids failed - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
@ -493,7 +581,7 @@ BOOL test_many_LookupSids(struct dcerpc_pipe *p,
|
||||
r.out.names = &names;
|
||||
|
||||
status = dcerpc_lsa_LookupSids3(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
|
||||
NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
|
||||
printf("not considering %s to be an error\n", nt_errstr(status));
|
||||
@ -1879,16 +1967,54 @@ static BOOL test_QueryInfoPolicy(struct dcerpc_pipe *p,
|
||||
|
||||
status = dcerpc_lsa_QueryInfoPolicy(p, mem_ctx, &r);
|
||||
|
||||
if ((i == 9 || i == 10 || i == 11) &&
|
||||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
printf("server failed level %u (OK)\n", i);
|
||||
continue;
|
||||
switch (i) {
|
||||
case LSA_POLICY_INFO_DB:
|
||||
case LSA_POLICY_INFO_AUDIT_FULL_SET:
|
||||
case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
printf("server should have failed level %u: %s\n", i, nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
break;
|
||||
case LSA_POLICY_INFO_DOMAIN:
|
||||
case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
|
||||
case LSA_POLICY_INFO_DNS:
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("QueryInfoPolicy failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (lp_parm_bool(NULL, "torture", "samba4", false)) {
|
||||
/* Other levels not implemented yet */
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
|
||||
printf("QueryInfoPolicy failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
} else if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("QueryInfoPolicy failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("QueryInfoPolicy failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
continue;
|
||||
if (NT_STATUS_IS_OK(status) && i == LSA_POLICY_INFO_DNS) {
|
||||
/* Let's look up some of these names */
|
||||
|
||||
struct lsa_TransNameArray tnames;
|
||||
tnames.count = 10;
|
||||
tnames.names = talloc_array(mem_ctx, struct lsa_TranslatedName, tnames.count);
|
||||
tnames.names[0].name.string = r.out.info->dns.name.string;
|
||||
tnames.names[1].name.string = r.out.info->dns.dns_domain.string;
|
||||
tnames.names[2].name.string = talloc_asprintf(mem_ctx, "%s\\", r.out.info->dns.name.string);
|
||||
tnames.names[3].name.string = talloc_asprintf(mem_ctx, "%s\\", r.out.info->dns.dns_domain.string);
|
||||
tnames.names[4].name.string = talloc_asprintf(mem_ctx, "%s\\guest", r.out.info->dns.name.string);
|
||||
tnames.names[5].name.string = talloc_asprintf(mem_ctx, "%s\\krbtgt", r.out.info->dns.name.string);
|
||||
tnames.names[6].name.string = talloc_asprintf(mem_ctx, "%s\\guest", r.out.info->dns.dns_domain.string);
|
||||
tnames.names[7].name.string = talloc_asprintf(mem_ctx, "%s\\krbtgt", r.out.info->dns.dns_domain.string);
|
||||
tnames.names[8].name.string = talloc_asprintf(mem_ctx, "krbtgt@%s", r.out.info->dns.name.string);
|
||||
tnames.names[9].name.string = talloc_asprintf(mem_ctx, "krbtgt@%s", r.out.info->dns.dns_domain.string);
|
||||
ret &= test_LookupNames(p, mem_ctx, handle, &tnames);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1904,11 +2030,6 @@ static BOOL test_QueryInfoPolicy2(struct dcerpc_pipe *p,
|
||||
int i;
|
||||
BOOL ret = True;
|
||||
printf("\nTesting QueryInfoPolicy2\n");
|
||||
if (lp_parm_bool(NULL, "torture", "samba4", false)) {
|
||||
printf("skipping QueryInfoPolicy2 against Samba4\n");
|
||||
return True;
|
||||
}
|
||||
|
||||
for (i=1;i<13;i++) {
|
||||
r.in.handle = handle;
|
||||
r.in.level = i;
|
||||
@ -1916,17 +2037,36 @@ static BOOL test_QueryInfoPolicy2(struct dcerpc_pipe *p,
|
||||
printf("\ntrying QueryInfoPolicy2 level %d\n", i);
|
||||
|
||||
status = dcerpc_lsa_QueryInfoPolicy2(p, mem_ctx, &r);
|
||||
|
||||
if ((i == 9 || i == 10 || i == 11) &&
|
||||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
printf("server failed level %u (OK)\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("QueryInfoPolicy2 failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
continue;
|
||||
|
||||
switch (i) {
|
||||
case LSA_POLICY_INFO_DB:
|
||||
case LSA_POLICY_INFO_AUDIT_FULL_SET:
|
||||
case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
printf("server should have failed level %u: %s\n", i, nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
break;
|
||||
case LSA_POLICY_INFO_DOMAIN:
|
||||
case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
|
||||
case LSA_POLICY_INFO_DNS:
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("QueryInfoPolicy2 failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (lp_parm_bool(NULL, "torture", "samba4", false)) {
|
||||
/* Other levels not implemented yet */
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
|
||||
printf("QueryInfoPolicy2 failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
} else if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("QueryInfoPolicy2 failed - %s\n", nt_errstr(status));
|
||||
ret = False;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2013,6 +2153,14 @@ BOOL torture_rpc_lsa(struct torture_context *torture)
|
||||
}
|
||||
|
||||
if (handle) {
|
||||
if (!test_LookupNames_wellknown(p, mem_ctx, handle)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!test_LookupNames_bogus(p, mem_ctx, handle)) {
|
||||
ret = False;
|
||||
}
|
||||
|
||||
if (!test_LookupSids_async(p, mem_ctx, handle)) {
|
||||
ret = False;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user