summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source4/build/pidl/server.pm3
-rw-r--r--source4/lib/util_str.c34
-rw-r--r--source4/librpc/config.m43
-rw-r--r--source4/librpc/idl/dcerpc.idl11
-rw-r--r--source4/librpc/idl/schannel.idl43
-rw-r--r--source4/librpc/ndr/ndr.c2
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c20
-rw-r--r--source4/rpc_server/dcesrv_crypto_schannel.c27
8 files changed, 121 insertions, 22 deletions
diff --git a/source4/build/pidl/server.pm b/source4/build/pidl/server.pm
index 1e670d724b..72ebc22379 100644
--- a/source4/build/pidl/server.pm
+++ b/source4/build/pidl/server.pm
@@ -39,6 +39,9 @@ sub gen_dispatch_switch($)
pidl "\t\tif (DEBUGLEVEL > 10 && dce_call->fault_code == 0) {\n";
pidl "\t\t\tNDR_PRINT_OUT_DEBUG($d->{NAME}, r2);\n";
pidl "\t\t}\n";
+ pidl "\t\tif (dce_call->fault_code != 0) {\n";
+ pidl "\t\t\tDEBUG(2,(\"dcerpc_fault 0x%x in $d->{NAME}\\n\", dce_call->fault_code));\n";
+ pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
$count++;
}
diff --git a/source4/lib/util_str.c b/source4/lib/util_str.c
index 7b1a81bdfd..bb94d3fce6 100644
--- a/source4/lib/util_str.c
+++ b/source4/lib/util_str.c
@@ -1396,3 +1396,37 @@ size_t valgrind_strlen(const char *s)
return count;
}
#endif
+
+
+/*
+ format a string into length-prefixed dotted domain format, as used in NBT
+ and in some ADS structures
+*/
+const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s)
+{
+ char *ret;
+ int i;
+ if (!s || !*s) {
+ return talloc_strdup(mem_ctx, "");
+ }
+ ret = talloc(mem_ctx, strlen(s)+2);
+ if (!ret) {
+ return ret;
+ }
+
+ memcpy(ret+1, s, strlen(s)+1);
+ ret[0] = '.';
+
+ for (i=0;ret[i];i++) {
+ if (ret[i] == '.') {
+ char *p = strchr(ret+i+1, '.');
+ if (p) {
+ ret[i] = p-(ret+i+1);
+ } else {
+ ret[i] = strlen(ret+i+1);
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/source4/librpc/config.m4 b/source4/librpc/config.m4
index e489538aeb..4df76e96be 100644
--- a/source4/librpc/config.m4
+++ b/source4/librpc/config.m4
@@ -30,7 +30,8 @@ SMB_SUBSYSTEM(LIBNDR_RAW,[],
librpc/gen_ndr/ndr_ntsvcs.o
librpc/gen_ndr/ndr_netlogon.o
librpc/gen_ndr/ndr_trkwks.o
- librpc/gen_ndr/ndr_keysvc.o])
+ librpc/gen_ndr/ndr_keysvc.o
+ librpc/gen_ndr/ndr_schannel.o])
SMB_SUBSYSTEM(LIBRPC_RAW,[],
[librpc/rpc/dcerpc.o
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl
index 8805b61da6..0ee3d7b69b 100644
--- a/source4/librpc/idl/dcerpc.idl
+++ b/source4/librpc/idl/dcerpc.idl
@@ -23,17 +23,6 @@ interface dcerpc
dcerpc_syntax_id transfer_syntaxes[num_transfer_syntaxes];
} dcerpc_ctx_list;
- /*
- a schannel bind blob - used in auth_info
- on a schannel bind
- */
- typedef [public] struct {
- uint32 unknown1;
- uint32 unknown2;
- astring domain;
- astring hostname;
- } dcerpc_bind_schannel;
-
typedef struct {
uint16 max_xmit_frag;
uint16 max_recv_frag;
diff --git a/source4/librpc/idl/schannel.idl b/source4/librpc/idl/schannel.idl
new file mode 100644
index 0000000000..a208ee89a3
--- /dev/null
+++ b/source4/librpc/idl/schannel.idl
@@ -0,0 +1,43 @@
+#include "idl_types.h"
+
+/*
+ schannel structures
+*/
+
+[]
+interface schannel
+{
+ /*
+ a schannel bind blob - used in dcerpc auth_info
+ on a schannel
+ */
+ typedef struct {
+ astring domain;
+ astring account_name;
+ } schannel_bind_3;
+
+ typedef struct {
+ astring domain;
+ astring account_name;
+ astring dnsdomain; /* in NBT dotted format */
+ astring workstation;
+ } schannel_bind_23;
+
+ typedef [nodiscriminant] union {
+ [case (3)] schannel_bind_3 info3;
+ [case (23)] schannel_bind_23 info23;
+ } schannel_bind_info;
+
+ typedef [public] struct {
+ uint32 unknown1; /* seems to need to be 0 */
+ uint32 bind_type;
+ [switch_is(bind_type)] schannel_bind_info u;
+ } schannel_bind;
+
+ /* a bind_ack blob */
+ typedef [public] struct {
+ uint32 unknown1; /* 1 */
+ uint32 unknown2; /* 0 */
+ uint32 unknown3; /* 0x006c0000 */
+ } schannel_bind_ack;
+}
diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c
index 57a1e517b5..8b88a2d2e2 100644
--- a/source4/librpc/ndr/ndr.c
+++ b/source4/librpc/ndr/ndr.c
@@ -314,6 +314,7 @@ void ndr_print_debug(void (*fn)(struct ndr_print *, const char *, void *),
if (!ndr.mem_ctx) return;
ndr.print = ndr_print_debug_helper;
ndr.depth = 1;
+ ndr.flags = 0;
fn(&ndr, name, ptr);
talloc_destroy(ndr.mem_ctx);
}
@@ -333,6 +334,7 @@ void ndr_print_union_debug(void (*fn)(struct ndr_print *, const char *, uint32_t
if (!ndr.mem_ctx) return;
ndr.print = ndr_print_debug_helper;
ndr.depth = 1;
+ ndr.flags = 0;
fn(&ndr, name, level, ptr);
talloc_destroy(ndr.mem_ctx);
}
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index 22285bd56b..c2645d36a2 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -178,7 +178,7 @@ NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
NTSTATUS status;
struct schannel_state *schannel_state;
const char *workgroup, *workstation;
- struct dcerpc_bind_schannel bind_schannel;
+ struct schannel_bind bind_schannel;
workstation = username;
workgroup = domain;
@@ -206,14 +206,22 @@ NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
p->auth_info->auth_context_id = random();
p->security_state = NULL;
- /* TODO: what are these?? */
bind_schannel.unknown1 = 0;
- bind_schannel.unknown2 = 3;
- bind_schannel.domain = workgroup;
- bind_schannel.hostname = workstation;
+#if 0
+ /* to support this we'd need to have access to the full domain name */
+ bind_schannel.bind_type = 23;
+ bind_schannel.u.info23.domain = domain;
+ bind_schannel.u.info23.account_name = username;
+ bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(p->mem_ctx, fulldomainname);
+ bind_schannel.u.info23.workstation = str_format_nbt_domain(p->mem_ctx, username);
+#else
+ bind_schannel.bind_type = 3;
+ bind_schannel.u.info3.domain = domain;
+ bind_schannel.u.info3.account_name = username;
+#endif
status = ndr_push_struct_blob(&p->auth_info->credentials, p->mem_ctx, &bind_schannel,
- (ndr_push_flags_fn_t)ndr_push_dcerpc_bind_schannel);
+ (ndr_push_flags_fn_t)ndr_push_schannel_bind);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
diff --git a/source4/rpc_server/dcesrv_crypto_schannel.c b/source4/rpc_server/dcesrv_crypto_schannel.c
index a9256fb664..68eff453de 100644
--- a/source4/rpc_server/dcesrv_crypto_schannel.c
+++ b/source4/rpc_server/dcesrv_crypto_schannel.c
@@ -24,7 +24,7 @@
struct srv_schannel_state {
TALLOC_CTX *mem_ctx;
- struct dcerpc_bind_schannel bind_info;
+ struct schannel_bind bind_info;
struct schannel_state *state;
};
@@ -37,6 +37,8 @@ static NTSTATUS dcesrv_crypto_schannel_start(struct dcesrv_auth *auth, DATA_BLOB
NTSTATUS status;
TALLOC_CTX *mem_ctx;
uint8_t session_key[16];
+ const char *account_name;
+ struct schannel_bind_ack ack;
mem_ctx = talloc_init("schannel_start");
if (!mem_ctx) {
@@ -53,14 +55,20 @@ static NTSTATUS dcesrv_crypto_schannel_start(struct dcesrv_auth *auth, DATA_BLOB
/* parse the schannel startup blob */
status = ndr_pull_struct_blob(auth_blob, mem_ctx, &schannel->bind_info,
- (ndr_pull_flags_fn_t)ndr_pull_dcerpc_bind_schannel);
+ (ndr_pull_flags_fn_t)ndr_pull_schannel_bind);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return NT_STATUS_INVALID_PARAMETER;
}
+ if (schannel->bind_info.bind_type == 23) {
+ account_name = schannel->bind_info.u.info23.account_name;
+ } else {
+ account_name = schannel->bind_info.u.info3.account_name;
+ }
+
/* pull the session key for this client */
- status = schannel_fetch_session_key(mem_ctx, schannel->bind_info.hostname, session_key);
+ status = schannel_fetch_session_key(mem_ctx, account_name, session_key);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return NT_STATUS_INVALID_HANDLE;
@@ -75,6 +83,17 @@ static NTSTATUS dcesrv_crypto_schannel_start(struct dcesrv_auth *auth, DATA_BLOB
auth->crypto_ctx.private_data = schannel;
+ ack.unknown1 = 1;
+ ack.unknown2 = 0;
+ ack.unknown3 = 0x6c0000;
+
+ status = ndr_push_struct_blob(auth_blob, mem_ctx, &ack,
+ (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
return status;
}
@@ -102,7 +121,7 @@ static NTSTATUS dcesrv_crypto_schannel_seal(struct dcesrv_auth *auth, TALLOC_CTX
sign a packet
*/
static NTSTATUS dcesrv_crypto_schannel_sign(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, DATA_BLOB *sig)
+ const uint8_t *data, size_t length, DATA_BLOB *sig)
{
struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;