From 42eadaf3d94afc7abf8ba2f1a67c55f317215483 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 6 Jun 2004 12:59:14 +0000 Subject: r1048: - moved the schannel definitions into a separate schannel.idl - added server side support for schannel type 23. This allows WinXP to establish a schannel connection to Samba4 as an ADS DC - added client side support for schannel type 23, but disabled it as currently the client code has now way of getting the fully qualified domain name (which is needed) - report dcerpc faults in the server code in the log (This used to be commit 55e0b014fe14ca8811b55887208a1c3147ddb0d2) --- source4/build/pidl/server.pm | 3 ++ source4/lib/util_str.c | 34 +++++++++++++++++++++++ source4/librpc/config.m4 | 3 +- source4/librpc/idl/dcerpc.idl | 11 -------- source4/librpc/idl/schannel.idl | 43 +++++++++++++++++++++++++++++ source4/librpc/ndr/ndr.c | 2 ++ source4/librpc/rpc/dcerpc_schannel.c | 20 ++++++++++---- source4/rpc_server/dcesrv_crypto_schannel.c | 27 +++++++++++++++--- 8 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 source4/librpc/idl/schannel.idl 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; -- cgit