r4627: - simplified the dcerpc auth code using a common function
authorAndrew Tridgell <tridge@samba.org>
Mon, 10 Jan 2005 07:14:12 +0000 (07:14 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:08:35 +0000 (13:08 -0500)
- added support for "spnego" in binding strings. This enables SPNEGO
  auth in the dcerpc client code, using as many allter_context calls as
  are needed

To try SPNEGO do this:

  smbtorture ncacn_ip_tcp:SERVER[spnego,seal] -Uadministrator%password RPC-SAMR
(This used to be commit 9c0a3423f03111c110d21c0d3910e16aa1a8bf87)

source4/librpc/rpc/dcerpc.h
source4/librpc/rpc/dcerpc_auth.c
source4/librpc/rpc/dcerpc_ntlm.c
source4/librpc/rpc/dcerpc_schannel.c
source4/librpc/rpc/dcerpc_spnego.c
source4/librpc/rpc/dcerpc_util.c

index 40ac18d13cdcddf68d18272efdc15db9ae1bab80..289e17fb81b6f21b8f25d7d7e3c913630610415e 100644 (file)
@@ -119,17 +119,21 @@ struct dcerpc_pipe {
 #define DCERPC_SCHANNEL_ANY            (DCERPC_SCHANNEL_BDC| \
                                        DCERPC_SCHANNEL_DOMAIN| \
                                        DCERPC_SCHANNEL_WORKSTATION)
-/* use a 128 bit session key */
-#define DCERPC_SCHANNEL_128            (1<<12)
 
 #define DCERPC_AUTH_OPTIONS    (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL_ANY)
 
+/* use a 128 bit session key */
+#define DCERPC_SCHANNEL_128            (1<<12)
+
 /* check incoming pad bytes */
 #define DCERPC_DEBUG_PAD_CHECK         (1<<13)
 
 /* set LIBNDR_FLAG_REF_ALLOC flag when decoding NDR */
 #define DCERPC_NDR_REF_ALLOC           (1<<14)
 
+/* enable spnego auth */
+#define DCERPC_AUTH_SPNEGO             (1<<15)
+
 /*
   this is used to find pointers to calls
 */
index 4ff8fe549eb5821035bef0b4cac7e378d39c13c2..228a99d5c5da0e37599259368d842d0af63b95f7 100644 (file)
 NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
                               const char *uuid, uint_t version)
 {
-       TALLOC_CTX *mem_ctx;
+       TALLOC_CTX *tmp_ctx = talloc_new(p);
        NTSTATUS status;
 
-       mem_ctx = talloc_init("dcerpc_bind_auth_ntlm");
-       if (!mem_ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
-       talloc_destroy(mem_ctx);
+       status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version);
+       talloc_free(tmp_ctx);
 
        return status;
 }
 
-NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t auth_level,
+/*
+  perform a multi-part authenticated bind
+*/
+NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t auth_level,
                           const char *uuid, uint_t version)
 {
        NTSTATUS status;
-       TALLOC_CTX *mem_ctx;
+       TALLOC_CTX *tmp_ctx = talloc_new(p);
        DATA_BLOB credentials;
        DATA_BLOB null_data_blob = data_blob(NULL, 0);
 
-       mem_ctx = talloc_init("dcerpc_bind_auth");
-       if (!mem_ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       
        if (!p->conn->security_state.generic_state) {
                status = gensec_client_start(p, &p->conn->security_state.generic_state);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+               if (!NT_STATUS_IS_OK(status)) goto done;
 
                status = gensec_start_mech_by_authtype(p->conn->security_state.generic_state, 
                                                       auth_type, auth_level);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+               if (!NT_STATUS_IS_OK(status)) goto done;
        }
 
        p->conn->security_state.auth_info = talloc(p, struct dcerpc_auth);
@@ -84,34 +72,44 @@ NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t aut
        p->conn->security_state.auth_info->auth_context_id = random();
        p->conn->security_state.auth_info->credentials = null_data_blob;
 
-       status = gensec_update(p->conn->security_state.generic_state, mem_ctx,
+       status = gensec_update(p->conn->security_state.generic_state, tmp_ctx,
                               null_data_blob,
                               &credentials);
-       
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                goto done;
        }
 
        p->conn->security_state.auth_info->credentials = credentials;
 
-       status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
+       status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
 
-       status = gensec_update(p->conn->security_state.generic_state, mem_ctx,
+       status = gensec_update(p->conn->security_state.generic_state, tmp_ctx,
                               p->conn->security_state.auth_info->credentials,
                               &credentials);
-
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                goto done;
        }
 
-       p->conn->security_state.auth_info->credentials = credentials;
-       
-       status = dcerpc_auth3(p->conn, mem_ctx);
+       do {
+               p->conn->security_state.auth_info->credentials = credentials;
+
+               if (auth_type == DCERPC_AUTH_TYPE_SPNEGO) {
+                       status = dcerpc_alter_context(p, tmp_ctx, &p->syntax, &p->transfer_syntax);
+                       if (NT_STATUS_IS_OK(status)) {
+                               status = gensec_update(p->conn->security_state.generic_state, tmp_ctx,
+                                                      p->conn->security_state.auth_info->credentials,
+                                                      &credentials);
+                       }
+               } else {
+                       status = dcerpc_auth3(p->conn, tmp_ctx);
+               }
+       } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+
 done:
-       talloc_destroy(mem_ctx);
+       talloc_free(tmp_ctx);
 
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(p->conn->security_state.generic_state);
@@ -123,3 +121,4 @@ done:
 
        return status;
 }
+
index 8a83cea144d47784de6496647053a39726fd0840..39b5e1c28cbdeee7ab5fd80259d27239946dff03 100644 (file)
@@ -72,9 +72,9 @@ NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
                return status;
        }
        
-       status = dcerpc_bind_auth3(p, DCERPC_AUTH_TYPE_NTLMSSP,
-                                  dcerpc_auth_level(p->conn),
-                                  uuid, version);
+       status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_NTLMSSP,
+                                 dcerpc_auth_level(p->conn),
+                                 uuid, version);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(2, ("Failed to bind to pipe with NTLMSSP: %s\n", nt_errstr(status)));
index 10852159a89bae8d0b60b9483e261099b188b3d2..0e218c478f1528ecf01ff07f1ed91c237a0a924a 100644 (file)
@@ -448,8 +448,8 @@ NTSTATUS dcerpc_bind_auth_schannel_withkey(struct dcerpc_pipe *p,
        dce_schan_state = p->conn->security_state.generic_state->private_data;
        dce_schan_state->creds = talloc_reference(dce_schan_state, creds);
 
-       status = dcerpc_bind_auth3(p, DCERPC_AUTH_TYPE_SCHANNEL, dcerpc_auth_level(p->conn),
-                                  uuid, version);
+       status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL, dcerpc_auth_level(p->conn),
+                                 uuid, version);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to bind to pipe with SCHANNEL: %s\n", nt_errstr(status)));
index f67dd2c7cb5c7db5bc84176698e38e6cd265ac75..7290139f6eeb14a050bf6e59b99e299481481808 100644 (file)
 
 #include "includes.h"
 
-#if 0
-/*
-  metze, can you tell me what you're trying to do with this?
-*/
-
 /*
   do spnego style authentication on a gensec pipe
 */
 NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p,
-                              const char *uuid, uint_t version,
-                              const char *domain,
-                              const char *username,
-                              const char *password)
+                                const char *uuid, uint_t version,
+                                const char *domain,
+                                const char *username,
+                                const char *password)
 {
        NTSTATUS status;
 
+       if (!(p->conn->flags & (DCERPC_SIGN | DCERPC_SEAL))) {
+               p->conn->flags |= DCERPC_CONNECT;
+       }
+
        status = gensec_client_start(p, &p->conn->security_state.generic_state);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
@@ -84,10 +83,9 @@ NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p,
                return status;
        }
        
-       status = dcerpc_bind_alter(p, DCERPC_AUTH_TYPE_SPNEGO, 
-                                  dcerpc_auth_level(p->conn),
-                                  uuid, version);
-
+       status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SPNEGO,
+                                 dcerpc_auth_level(p->conn),
+                                 uuid, version);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(2, ("Failed to bind to pipe with SPNEGO: %s\n", nt_errstr(status)));
                return status;
@@ -95,4 +93,3 @@ NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p,
 
        return status;
 }
-#endif
index 305c1c7725ba2d58f2478f011386bd8f7c4dc4a1..534c17678d9e22f9500903044e1cb8455b58830f 100644 (file)
@@ -176,6 +176,7 @@ static const struct {
        {"sign", DCERPC_SIGN},
        {"seal", DCERPC_SEAL},
        {"connect", DCERPC_CONNECT},
+       {"spnego", DCERPC_AUTH_SPNEGO},
        {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
        {"print", DCERPC_DEBUG_PRINT_BOTH},
        {"padcheck", DCERPC_DEBUG_PAD_CHECK},
@@ -772,6 +773,42 @@ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *bind
 }
 
 
+/* 
+   perform an authenticated bind if needed
+*/
+static NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, 
+                                struct dcerpc_binding *binding,
+                                const char *pipe_uuid, 
+                                uint32_t pipe_version,
+                                const char *domain,
+                                const char *username,
+                                const char *password)
+{
+       NTSTATUS status;
+
+       p->conn->flags = binding->flags;
+
+       /* remember the binding string for possible secondary connections */
+       p->conn->binding_string = dcerpc_binding_string(p, binding);
+
+       if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
+               status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, 
+                                                  domain, username, password);
+       } else if (username && username[0] && (binding->flags & DCERPC_AUTH_SPNEGO)) {
+               status = dcerpc_bind_auth_spnego(p, pipe_uuid, pipe_version, domain, username, password);
+       } else if (username && username[0]) {
+               status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password);
+       } else {    
+               status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
+       }
+       return status;
+}
+
+
 /* open a rpc connection to a rpc pipe on SMB using the binding
    structure to determine the endpoint and options */
 static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **pp, 
@@ -846,24 +883,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **pp,
                return status;
        }
        
-       p->conn->flags = binding->flags;
-
-       /* remember the binding string for possible secondary connections */
-       p->conn->binding_string = dcerpc_binding_string(p, binding);
-
-       if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
-               status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, 
-                                                  domain, username, password);
-       } else if (username && username[0] &&
-                  (binding->flags & (DCERPC_CONNECT|DCERPC_SIGN|DCERPC_SEAL))) {
-               status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password);
-       } else {    
-               status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
-
-       }
-
+       status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
                talloc_free(p);
                return status;
        }
@@ -916,22 +937,8 @@ static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **pp,
                return status;
        }
 
-       p->conn->flags = binding->flags;
-
-       /* remember the binding string for possible secondary connections */
-       p->conn->binding_string = dcerpc_binding_string(p, binding);
-
-       if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
-               status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, 
-                                                  domain, username, password);
-       } else if (username && username[0]) {
-               status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password);
-       } else {    
-               status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
-       }
-
+       status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
                talloc_free(p);
                return status;
        }
@@ -977,22 +984,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **pp,
                 return status;
        }
 
-       p->conn->flags = binding->flags;
-
-       /* remember the binding string for possible secondary connections */
-       p->conn->binding_string = dcerpc_binding_string(p, binding);
-
-       if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
-               status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, 
-                                                  domain, username, password);
-       } else if (username && username[0]) {
-               status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password);
-       } else {    
-               status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
-       }
-
+       status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
                talloc_free(p);
                return status;
        }
@@ -1047,23 +1040,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **pp,
                 return status;
         }
 
-       p->conn->flags = binding->flags;
-
-       /* remember the binding string for possible secondary connections */
-       p->conn->binding_string = dcerpc_binding_string(p, binding);
-
-       if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
-               status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, 
-                                                  domain, username, password);
-       } else if (username && username[0]) {
-               status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password);
-       } else {    
-               status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
-       }
-
+       status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("Failed to bind to uuid %s - %s\n", 
-                        pipe_uuid, nt_errstr(status)));
                talloc_free(p);
                return status;
        }
@@ -1171,7 +1149,6 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe *
                if (!tree) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
-
                status = dcerpc_pipe_open_smb((*p2)->conn, tree, pipe_name);
                break;
 
@@ -1180,7 +1157,6 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe *
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
-               b.flags &= ~DCERPC_AUTH_OPTIONS;
                status = dcerpc_pipe_open_tcp((*p2)->conn, b.host, atoi(b.endpoint));
                break;
 
@@ -1189,7 +1165,6 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe *
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
-               b.flags &= ~DCERPC_AUTH_OPTIONS;
                status = dcerpc_pipe_open_pipe((*p2)->conn, b.endpoint);
                break;