diff options
-rw-r--r-- | source4/librpc/idl/drsuapi.idl | 73 | ||||
-rw-r--r-- | source4/rpc_server/config.mk | 2 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 50 | ||||
-rw-r--r-- | source4/rpc_server/drsuapi/drsuapi_cracknames.c | 128 | ||||
-rw-r--r-- | source4/torture/rpc/drsuapi.c | 155 |
5 files changed, 330 insertions, 78 deletions
diff --git a/source4/librpc/idl/drsuapi.idl b/source4/librpc/idl/drsuapi.idl index fc9aee6b7f..d49f3d294a 100644 --- a/source4/librpc/idl/drsuapi.idl +++ b/source4/librpc/idl/drsuapi.idl @@ -72,44 +72,77 @@ interface drsuapi /*****************/ /* Function 0x0c */ + typedef enum { + DRSUAPI_DS_NAME_STATUS_OK = 0, + DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR = 1, + DRSUAPI_DS_NAME_STATUS_NOT_FOUND = 2, + DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE = 3, + DRSUAPI_DS_NAME_STATUS_NO_MAPPING = 4, + DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY = 5, + DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING = 6, + DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL = 7 + } drsuapi_DsNameStatus; + + typedef enum { + DRSUAPI_DS_NAME_FLAG_NO_FLAGS = 0x0, + DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY = 0x1, + DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC = 0x2, + DRSUAPI_DS_NAME_FLAG_GCVERIFY = 0x4, + DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL = 0x8 + } drsuapi_DsNameFlags; + + typedef enum { + DRSUAPI_DS_NAME_FORMAT_UKNOWN = 0, + DRSUAPI_DS_NAME_FORMAT_FQDN_1779 = 1, + DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT = 2, + DRSUAPI_DS_NAME_FORMAT_DISPLAY = 3, + DRSUAPI_DS_NAME_FORMAT_GUID = 6, + DRSUAPI_DS_NAME_FORMAT_CANONICAL = 7, + DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL = 8, + DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX = 9, + DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL = 10, + DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY = 11, + DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN = 12 + } drsuapi_DsNameFormat; + typedef struct { unistr *str; - } drsuapi_DsCrackNamesInInfo1Names; + } drsuapi_DsNameString; typedef struct { - uint32 unknown1; - uint32 unknown2; - uint32 unknown3; - uint32 unknown4; - uint32 unknown5; + uint32 unknown1; /* 0x000004e4 */ + uint32 unknown2; /* 0x00000407 */ + uint32 format_flags; + uint32 format_offered; + uint32 format_desired; [range(1,10000)] uint32 count; - [size_is(count)] drsuapi_DsCrackNamesInInfo1Names *names; - } drsuapi_DsCrackNamesInInfo1; + [size_is(count)] drsuapi_DsNameString *names; + } drsuapi_DsNameRequest1; typedef union { - [case(1)] drsuapi_DsCrackNamesInInfo1 info1; - } drsuapi_DsCrackNamesInInfo; + [case(1)] drsuapi_DsNameRequest1 req1; + } drsuapi_DsNameRequest; typedef struct { - uint32 unknown1; - unistr *name1; - unistr *name2; - } drsuapi_DsCrackNamesOutInfo1Names; + uint32 status; + unistr *dns_domain_name; + unistr *result_name; + } drsuapi_DsNameInfo1; typedef struct { uint32 count; - [size_is(count)] drsuapi_DsCrackNamesOutInfo1Names *names; - } drsuapi_DsCrackNamesOutInfo1; + [size_is(count)] drsuapi_DsNameInfo1 *array; + } drsuapi_DsNameCtr1; typedef union { - [case(1)] drsuapi_DsCrackNamesOutInfo1 *info1; - } drsuapi_DsCrackNamesOutInfo; + [case(1)] drsuapi_DsNameCtr1 *ctr1; + } drsuapi_DsNameCtr; NTSTATUS drsuapi_DsCrackNames( [in,ref] policy_handle *bind_handle, [in, out] uint32 level, - [in,switch_is(level)] drsuapi_DsCrackNamesInInfo in, - [out,switch_is(level)] drsuapi_DsCrackNamesOutInfo out + [in,switch_is(level)] drsuapi_DsNameRequest req, + [out,switch_is(level)] drsuapi_DsNameCtr ctr ); /*****************/ diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk index 350803afd9..9c0751a1b9 100644 --- a/source4/rpc_server/config.mk +++ b/source4/rpc_server/config.mk @@ -153,6 +153,8 @@ REQUIRED_SUBSYSTEMS = \ [MODULE::dcerpc_drsuapi] INIT_OBJ_FILES = \ rpc_server/drsuapi/dcesrv_drsuapi.o +ADD_OBJ_FILES = \ + rpc_server/drsuapi/drsuapi_cracknames.o REQUIRED_SUBSYSTEMS = \ SAMDB \ DCERPC_COMMON diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index 06fa1bba95..503a54b6b3 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -190,54 +190,10 @@ static NTSTATUS DRSUAPI_GET_NT4_CHANGELOG(struct dcesrv_call_state *dce_call, TA /* - drsuapi_DsCrackNames + drsuapi_DsCrackNames => drsuapip_cracknames.c */ -static NTSTATUS drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct drsuapi_DsCrackNames *r) -{ - struct dcesrv_handle *h; - - r->out.level = r->in.level; - ZERO_STRUCT(r->out.out); - - DCESRV_PULL_HANDLE(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); - - switch (r->in.level) { - case 1: { - int i; - - r->out.out.info1 = talloc_p(mem_ctx, struct drsuapi_DsCrackNamesOutInfo1); - NTSTATUS_TALLOC_CHECK(r->out.out.info1); - - r->out.out.info1->names = talloc_array_p(mem_ctx, - struct drsuapi_DsCrackNamesOutInfo1Names, - r->in.in.info1.count); - NTSTATUS_TALLOC_CHECK(r->out.out.info1->names); - - r->out.out.info1->count = r->in.in.info1.count; - - for (i=0; i < r->out.out.info1->count; i++) { - const char *name; - r->out.out.info1->names[i].unknown1 = 2; - r->out.out.info1->names[i].name1 = NULL; - r->out.out.info1->names[i].name2 = NULL; - - /* TODO: fill crack the right names! */ - name = talloc_asprintf(mem_ctx, "%s/", lp_realm()); - if (strcmp(name, r->in.in.info1.names[i].str) != 0) { - continue; - } - r->out.out.info1->names[i].unknown1 = 0; - r->out.out.info1->names[i].name1 = talloc_asprintf(mem_ctx, "%s", lp_realm()); - r->out.out.info1->names[i].name2 = talloc_asprintf(mem_ctx, "%s\\", lp_workgroup()); - } - return NT_STATUS_OK; - } - } - - return NT_STATUS_INVALID_LEVEL; -} - +static NTSTATUS (*drsuapi_DsCrackNames)(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct drsuapi_DsCrackNames *r) = dcesrv_drsuapi_DsCrackNames; /* DRSUAPI_WRITE_SPN diff --git a/source4/rpc_server/drsuapi/drsuapi_cracknames.c b/source4/rpc_server/drsuapi/drsuapi_cracknames.c new file mode 100644 index 0000000000..1a31d541ba --- /dev/null +++ b/source4/rpc_server/drsuapi/drsuapi_cracknames.c @@ -0,0 +1,128 @@ +/* + Unix SMB/CIFS implementation. + + endpoint server for the drsuapi pipe + DsCrackNames() + + Copyright (C) Stefan Metzmacher 2004 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "rpc_server/common/common.h" +#include "rpc_server/drsuapi/dcesrv_drsuapi.h" + + +static NTSTATUS DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx, + uint32 format_offered, uint32 format_desired, const char *name, + struct drsuapi_DsNameInfo1 *info1) +{ + info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; + info1->dns_domain_name = NULL; + info1->result_name = NULL; + + /* TODO: fill crack the correct names in all cases! */ + switch (format_offered) { + case DRSUAPI_DS_NAME_FORMAT_CANONICAL: { + int ret; + char *str; + + str = talloc_asprintf(mem_ctx, "%s/", lp_realm()); + NTSTATUS_TALLOC_CHECK(str); + + ret = strcasecmp(str, name); + talloc_free(str); + if (ret != 0) { + info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; + return NT_STATUS_OK; + } + + info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY; + info1->dns_domain_name = talloc_asprintf(mem_ctx, "%s", lp_realm()); + NTSTATUS_TALLOC_CHECK(info1->dns_domain_name); + switch (format_desired) { + case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: + info1->status = DRSUAPI_DS_NAME_STATUS_OK; + info1->result_name = talloc_asprintf(mem_ctx, "%s\\", + lp_workgroup()); + NTSTATUS_TALLOC_CHECK(info1->result_name); + return NT_STATUS_OK; + default: + return NT_STATUS_OK; + } + return NT_STATUS_INVALID_PARAMETER; + } + default: { + info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; + return NT_STATUS_OK; + } + } + + return NT_STATUS_INVALID_PARAMETER; +} + +/* + drsuapi_DsCrackNames +*/ +NTSTATUS dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct drsuapi_DsCrackNames *r) +{ + NTSTATUS status; + struct drsuapi_bind_state *b_state; + struct dcesrv_handle *h; + + r->out.level = r->in.level; + ZERO_STRUCT(r->out.ctr); + + DCESRV_PULL_HANDLE(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); + b_state = h->data; + + switch (r->in.level) { + case 1: { + struct drsuapi_DsNameInfo1 *names; + int count; + int i; + + r->out.ctr.ctr1 = talloc_p(mem_ctx, struct drsuapi_DsNameCtr1); + NTSTATUS_TALLOC_CHECK(r->out.ctr.ctr1); + + r->out.ctr.ctr1->count = 0; + r->out.ctr.ctr1->array = NULL; + + count = r->in.req.req1.count; + names = talloc_array_p(mem_ctx, struct drsuapi_DsNameInfo1, count); + NTSTATUS_TALLOC_CHECK(names); + + for (i=0; i < count; i++) { + status = DsCrackNameOneName(b_state, mem_ctx, + r->in.req.req1.format_offered, + r->in.req.req1.format_desired, + r->in.req.req1.names[i].str, + &names[i]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + r->out.ctr.ctr1->count = count; + r->out.ctr.ctr1->array = names; + + return NT_STATUS_OK; + } + } + + return NT_STATUS_INVALID_LEVEL; +} diff --git a/source4/torture/rpc/drsuapi.c b/source4/torture/rpc/drsuapi.c index aed7f884d2..562291c6de 100644 --- a/source4/torture/rpc/drsuapi.c +++ b/source4/torture/rpc/drsuapi.c @@ -53,20 +53,24 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, { NTSTATUS status; struct drsuapi_DsCrackNames r; - struct drsuapi_DsCrackNamesInInfo1Names names[1]; + struct drsuapi_DsNameString names[1]; BOOL ret = True; + const char *dns_domain; + const char *nt4_domain; + const char *FQDN_1779_domain; + const char *FQDN_1779_name; ZERO_STRUCT(r); - r.in.bind_handle = bind_handle; - r.in.level = 1; - r.in.in.info1.unknown1 = 0x000004e4; - r.in.in.info1.unknown2 = 0x00000407; - r.in.in.info1.unknown3 = 0x00000000; - r.in.in.info1.unknown4 = 0x00000007; - r.in.in.info1.unknown5 = 0x00000002; - r.in.in.info1.count = 1; - r.in.in.info1.names = names; - + r.in.bind_handle = bind_handle; + r.in.level = 1; + r.in.req.req1.unknown1 = 0x000004e4; + r.in.req.req1.unknown2 = 0x00000407; + r.in.req.req1.count = 1; + r.in.req.req1.names = names; + r.in.req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; + + r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL; + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; names[0].str = talloc_asprintf(mem_ctx, "%s/", lp_realm()); status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); @@ -79,6 +83,135 @@ static BOOL test_DsCrackNames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ret = False; } + if (!ret) { + return ret; + } + + dns_domain = r.out.ctr.ctr1->array[0].dns_domain_name; + nt4_domain = r.out.ctr.ctr1->array[0].result_name; + + r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; + names[0].str = nt4_domain; + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + + FQDN_1779_domain = r.out.ctr.ctr1->array[0].result_name; + + r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; + names[0].str = talloc_asprintf(mem_ctx, "%s%s$", nt4_domain, dcerpc_server_name(p)); + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + + FQDN_1779_name = r.out.ctr.ctr1->array[0].result_name; + + r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL; + names[0].str = FQDN_1779_name; + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_DISPLAY; + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_GUID; + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL; + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL; + + status = dcerpc_drsuapi_DsCrackNames(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(mem_ctx, p->last_fault_code); + } + printf("drsuapi_DsCrackNames failed - %s\n", errstr); + ret = False; + } + + if (!ret) { + return ret; + } + return ret; } |