r1048: - moved the schannel definitions into a separate schannel.idl
authorAndrew Tridgell <tridge@samba.org>
Sun, 6 Jun 2004 12:59:14 +0000 (12:59 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:56:34 +0000 (12:56 -0500)
- 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
source4/lib/util_str.c
source4/librpc/config.m4
source4/librpc/idl/dcerpc.idl
source4/librpc/idl/schannel.idl [new file with mode: 0644]
source4/librpc/ndr/ndr.c
source4/librpc/rpc/dcerpc_schannel.c
source4/rpc_server/dcesrv_crypto_schannel.c

index 1e670d724b4f04c5f6b560340d012a453393767e..72ebc22379f1caf743e703cf8784ace90f1dab02 100644 (file)
@@ -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++; 
        }
index 7b1a81bdfd484d6f9194895a2c744ab657703741..bb94d3fce68a390fb6a6c70e643ebfd90d327777 100644 (file)
@@ -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;
+}
index e489538aebea0c74d64eb12943388ad1bd66185b..4df76e96be3791c5fe5774e925ce9535cf031b39 100644 (file)
@@ -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
index 8805b61da61adff0d126a417c9426b4499a0112c..0ee3d7b69b4f98b01a2df8e01c06e19aeac5bd99 100644 (file)
@@ -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 (file)
index 0000000..a208ee8
--- /dev/null
@@ -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;
+}
index 57a1e517b51ec915c8896cd321b9efc2754269ed..8b88a2d2e2d6a2bf7dd24b19e49aa053e155b827 100644 (file)
@@ -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);
 }
index 22285bd56b17ba8e3cb365690bafca723de72b6a..c2645d36a269fde7584fb273ff2c9de59dae7ddb 100644 (file)
@@ -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;
        }
index a9256fb664b97a0dfb6de13c9fbb8b0f8fee2527..68eff453de13e20be1e3f2672cad1a4570b1d682 100644 (file)
@@ -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;