r1068: make the dcerpc client side auth/crypto code much more generic
authorStefan Metzmacher <metze@samba.org>
Mon, 7 Jun 2004 12:30:22 +0000 (12:30 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:56:36 +0000 (12:56 -0500)
metze
(This used to be commit 1706ff88a72c6578a109c2cf24f2f009812c3892)

source4/librpc/rpc/dcerpc.c
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_util.c

index 5d317794e1867105f7d3072736d5150a47d8a662..e80e168c893c59c407c885557c58be750a144f95 100644 (file)
@@ -41,8 +41,10 @@ struct dcerpc_pipe *dcerpc_pipe_init(void)
        p->reference_count = 0;
        p->mem_ctx = mem_ctx;
        p->call_id = 1;
-       p->auth_info = NULL;
-       p->security_state = NULL;
+       p->security_state.auth_info = NULL;
+       ZERO_STRUCT(p->security_state.user);
+       p->security_state.private_data = NULL;
+       p->security_state.ops = NULL;
        p->flags = 0;
        p->srv_max_xmit_frag = 0;
        p->srv_max_recv_frag = 0;
@@ -56,8 +58,8 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p)
        if (!p) return;
        p->reference_count--;
        if (p->reference_count <= 0) {
-               if (p->security_state) {
-                       p->security_state->security_end(p->security_state);
+               if (p->security_state.ops) {
+                       p->security_state.ops->end(&p->security_state);
                }
                p->transport.shutdown_pipe(p);
                talloc_destroy(p->mem_ctx);
@@ -128,7 +130,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
        DATA_BLOB auth_blob;
 
        /* non-signed packets are simpler */
-       if (!p->auth_info || !p->security_state) {
+       if (!p->security_state.auth_info || !p->security_state.ops) {
                return dcerpc_pull(blob, mem_ctx, pkt);
        }
 
@@ -180,9 +182,9 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
 
 
        /* check signature or unseal the packet */
-       switch (p->auth_info->auth_level) {
+       switch (p->security_state.auth_info->auth_level) {
        case DCERPC_AUTH_LEVEL_PRIVACY:
-               status = p->security_state->unseal_packet(p->security_state, 
+               status = p->security_state.ops->unseal(&p->security_state, 
                                                          mem_ctx, 
                                                          pkt->u.response.stub_and_verifier.data, 
                                                          pkt->u.response.stub_and_verifier.length, 
@@ -190,7 +192,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
                break;
 
        case DCERPC_AUTH_LEVEL_INTEGRITY:
-               status = p->security_state->check_packet(p->security_state, 
+               status = p->security_state.ops->check_sig(&p->security_state, 
                                                         mem_ctx, 
                                                         pkt->u.response.stub_and_verifier.data, 
                                                         pkt->u.response.stub_and_verifier.length, 
@@ -226,8 +228,8 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
        struct ndr_push *ndr;
 
        /* non-signed packets are simpler */
-       if (!p->auth_info || !p->security_state) {
-               return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info);
+       if (!p->security_state.auth_info || !p->security_state.ops) {
+               return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
        }
 
        ndr = ndr_push_init_ctx(mem_ctx);
@@ -245,29 +247,29 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
        }
 
        /* pad to 8 byte multiple */
-       p->auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
-       ndr_push_zero(ndr, p->auth_info->auth_pad_length);
+       p->security_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
+       ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
 
        /* sign or seal the packet */
-       switch (p->auth_info->auth_level) {
+       switch (p->security_state.auth_info->auth_level) {
        case DCERPC_AUTH_LEVEL_PRIVACY:
-               status = p->security_state->seal_packet(p->security_state, 
+               status = p->security_state.ops->seal(&p->security_state, 
                                                        mem_ctx, 
                                                        ndr->data + DCERPC_REQUEST_LENGTH, 
                                                        ndr->offset - DCERPC_REQUEST_LENGTH,
-                                                       &p->auth_info->credentials);
+                                                       &p->security_state.auth_info->credentials);
                break;
 
        case DCERPC_AUTH_LEVEL_INTEGRITY:
-               status = p->security_state->sign_packet(p->security_state, 
+               status = p->security_state.ops->sign(&p->security_state, 
                                                        mem_ctx, 
                                                        ndr->data + DCERPC_REQUEST_LENGTH, 
                                                        ndr->offset - DCERPC_REQUEST_LENGTH,
-                                                       &p->auth_info->credentials);
+                                                       &p->security_state.auth_info->credentials);
                break;
 
        case DCERPC_AUTH_LEVEL_NONE:
-               p->auth_info->credentials = data_blob(NULL, 0);
+               p->security_state.auth_info->credentials = data_blob(NULL, 0);
                break;
 
        default:
@@ -280,7 +282,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
        }       
 
        /* add the auth verifier */
-       status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->auth_info);
+       status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -292,9 +294,9 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
           in these earlier as we don't know the signature length (it
           could be variable length) */
        dcerpc_set_frag_length(blob, blob->length);
-       dcerpc_set_auth_length(blob, p->auth_info->credentials.length);
+       dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
 
-       data_blob_free(&p->auth_info->credentials);
+       data_blob_free(&p->security_state.auth_info->credentials);
 
        return NT_STATUS_OK;
 }
@@ -357,7 +359,7 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
        pkt.u.bind.auth_info = data_blob(NULL, 0);
 
        /* construct the NDR form of the packet */
-       status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
+       status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -386,10 +388,10 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
        }
 
        /* the bind_ack might contain a reply set of credentials */
-       if (p->auth_info && pkt.u.bind_ack.auth_info.length) {
+       if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
                status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
                                              mem_ctx,
-                                             p->auth_info,
+                                             p->security_state.auth_info,
                                              (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
        }
 
@@ -416,7 +418,7 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
        pkt.u.auth.auth_info = data_blob(NULL, 0);
 
        /* construct the NDR form of the packet */
-       status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
+       status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
index 7bd6f98118ceb6071f73f2c03502c0dbf84d3dff..7694a9c2300bb8e2f7b7cb3eb70dfc7660ef6d34 100644 (file)
@@ -25,24 +25,39 @@ enum dcerpc_transport_t {NCACN_NP, NCACN_IP_TCP};
 /*
   this defines a generic security context for signed/sealed dcerpc pipes.
 */
-struct dcerpc_security {
-       void *private;
-       NTSTATUS (*unseal_packet)(struct dcerpc_security *, 
-                                 TALLOC_CTX *mem_ctx, 
-                                 uint8_t *data, size_t length, DATA_BLOB *sig);
-       NTSTATUS (*check_packet)(struct dcerpc_security *, 
-                                TALLOC_CTX *mem_ctx, 
-                                const uint8_t *data, size_t length, const DATA_BLOB *sig);
-       NTSTATUS (*seal_packet)(struct dcerpc_security *, 
-                               TALLOC_CTX *mem_ctx, 
+struct dcerpc_security;
+struct dcerpc_pipe;
+
+struct dcerpc_user {
+       const char *domain;
+       const char *name;
+       const char *password;
+};
+
+struct dcesrv_security_ops {
+       const char *name;
+       uint8 auth_type;
+       NTSTATUS (*start)(struct dcerpc_pipe *dce_pipe, struct dcerpc_security *dce_sec);
+       NTSTATUS (*update)(struct dcerpc_security *dce_sec, TALLOC_CTX *out_mem_ctx,
+                               const DATA_BLOB in, DATA_BLOB *out);
+       NTSTATUS (*seal)(struct dcerpc_security *dce_sec, TALLOC_CTX *sig_mem_ctx,
                                uint8_t *data, size_t length, DATA_BLOB *sig);
-       NTSTATUS (*sign_packet)(struct dcerpc_security *, 
-                               TALLOC_CTX *mem_ctx, 
+       NTSTATUS (*sign)(struct dcerpc_security *dce_sec, TALLOC_CTX *sig_mem_ctx,
                                const uint8_t *data, size_t length, DATA_BLOB *sig);
+       NTSTATUS (*check_sig)(struct dcerpc_security *dce_sec, TALLOC_CTX *sig_mem_ctx, 
+                               const uint8_t *data, size_t length, const DATA_BLOB *sig);
+       NTSTATUS (*unseal)(struct dcerpc_security *dce_sec, TALLOC_CTX *sig_mem_ctx,
+                               uint8_t *data, size_t length, DATA_BLOB *sig);
        NTSTATUS (*session_key)(struct dcerpc_security *, DATA_BLOB *session_key);
-       void (*security_end)(struct dcerpc_security *);
+       void (*end)(struct dcerpc_security *dce_sec);
+};
+       
+struct dcerpc_security {
+       struct dcerpc_auth *auth_info;
+       struct dcerpc_user user;
+       void *private_data;
+       const struct dcesrv_security_ops *ops;
 };
-
 
 struct dcerpc_pipe {
        TALLOC_CTX *mem_ctx;
@@ -51,8 +66,7 @@ struct dcerpc_pipe {
        uint32_t srv_max_xmit_frag;
        uint32_t srv_max_recv_frag;
        uint_t flags;
-       struct dcerpc_security *security_state;
-       struct dcerpc_auth *auth_info;
+       struct dcerpc_security security_state;
        const char *binding_string;
        
        struct dcerpc_transport {
index 3faf0603ce1f59c8d4deb45dac6d1fcdf687507d..021249847aba8bf97fb5801faa77c1685b48e8fd 100644 (file)
@@ -41,3 +41,102 @@ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
 
        return status;
 }
+
+const struct dcesrv_security_ops *dcerpc_security_by_authtype(uint8_t auth_type)
+{
+       switch (auth_type) {
+               case DCERPC_AUTH_TYPE_SCHANNEL:
+                       return dcerpc_schannel_security_get_ops();
+
+               case DCERPC_AUTH_TYPE_NTLMSSP:
+                       return dcerpc_ntlmssp_security_get_ops();
+       }
+
+       return NULL;
+}
+
+NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type,
+                                      const char *uuid, uint_t version,
+                                      const char *domain,
+                                      const char *username,
+                                      const char *password)
+{
+       NTSTATUS status;
+       TALLOC_CTX *mem_ctx;
+       DATA_BLOB credentials;
+
+       mem_ctx = talloc_init("dcerpc_bind_auth");
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       p->security_state.ops = dcerpc_security_by_authtype(auth_type);
+       if (!p->security_state.ops) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto done;
+       }
+
+       p->security_state.user.domain = domain;
+       p->security_state.user.name = username;
+       p->security_state.user.password = password;
+
+       status = p->security_state.ops->start(p, &p->security_state);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       p->security_state.auth_info = talloc(p->mem_ctx, sizeof(*p->security_state.auth_info));
+       if (!p->security_state.auth_info) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       p->security_state.auth_info->auth_type = auth_type;
+       p->security_state.auth_info->auth_pad_length = 0;
+       p->security_state.auth_info->auth_reserved = 0;
+       p->security_state.auth_info->auth_context_id = random();
+       p->security_state.auth_info->credentials = data_blob(NULL, 0);
+
+       if (p->flags & DCERPC_SEAL) {
+               p->security_state.auth_info->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+       } else if (p->flags & DCERPC_SIGN) {
+               p->security_state.auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+       } else {
+               p->security_state.auth_info->auth_level = DCERPC_AUTH_LEVEL_NONE;
+       }
+
+       status = p->security_state.ops->update(&p->security_state, mem_ctx,
+                                       p->security_state.auth_info->credentials,
+                                       &credentials);
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               goto done;
+       }
+
+       p->security_state.auth_info->credentials = credentials;
+
+       status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+
+       status = p->security_state.ops->update(&p->security_state, mem_ctx,
+                                       p->security_state.auth_info->credentials,
+                                       &credentials);
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               goto done;
+       }
+
+       p->security_state.auth_info->credentials = credentials;
+
+       status = dcerpc_auth3(p, mem_ctx);
+done:
+       talloc_destroy(mem_ctx);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               ZERO_STRUCT(p->security_state);
+       }
+
+       return status;
+}
index db707be1b5dc3c4b0d74b0789716e9af2a103ade..2cfecd939f63a7564c86a72373038d812c011306 100644 (file)
 /*
   wrappers for the ntlmssp_*() functions
 */
-static NTSTATUS ntlm_unseal_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_ntlmssp_unseal(struct dcerpc_security *dcerpc_security, 
                                   TALLOC_CTX *mem_ctx, 
                                   uint8_t *data, size_t length, DATA_BLOB *sig)
 {
-       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
+
        return ntlmssp_unseal_packet(ntlmssp_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS ntlm_check_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_ntlmssp_check_sig(struct dcerpc_security *dcerpc_security, 
                                  TALLOC_CTX *mem_ctx, 
                                  const uint8_t *data, size_t length, 
                                  const DATA_BLOB *sig)
 {
-       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
+
        return ntlmssp_check_packet(ntlmssp_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS ntlm_seal_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_ntlmssp_seal(struct dcerpc_security *dcerpc_security, 
                                 TALLOC_CTX *mem_ctx, 
                                 uint8_t *data, size_t length, 
                                 DATA_BLOB *sig)
 {
-       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
+
        return ntlmssp_seal_packet(ntlmssp_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS ntlm_sign_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_ntlmssp_sign(struct dcerpc_security *dcerpc_security, 
                                 TALLOC_CTX *mem_ctx, 
                                 const uint8_t *data, size_t length, 
                                 DATA_BLOB *sig)
 {
-       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
+
        return ntlmssp_sign_packet(ntlmssp_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS ntlm_session_key(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_ntlmssp_session_key(struct dcerpc_security *dcerpc_security, 
                                 DATA_BLOB *session_key)
 {
-       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
+
        if (!ntlmssp_state->session_key.data) {
                return NT_STATUS_NO_USER_SESSION_KEY;
        }
        *session_key = ntlmssp_state->session_key;
-       return NT_STATUS_OK;
-}
 
-static void ntlm_security_end(struct dcerpc_security *dcerpc_security)
-{
-       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
-       ntlmssp_end(&ntlmssp_state);
+       return NT_STATUS_OK;
 }
 
-
-
-/*
-  do ntlm style authentication on a dcerpc pipe
-*/
-NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
-                              const char *uuid, uint_t version,
-                              const char *domain,
-                              const char *username,
-                              const char *password)
+static NTSTATUS dcerpc_ntlmssp_start(struct dcerpc_pipe *dce_pipe, struct dcerpc_security *dcerpc_security)
 {
+       struct ntlmssp_state *ntlmssp_state = NULL;
        NTSTATUS status;
-       struct ntlmssp_state *state;
-       TALLOC_CTX *mem_ctx;
-       DATA_BLOB credentials;
-
-       mem_ctx = talloc_init("dcerpc_bind_auth_ntlm");
-       if (!mem_ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
 
-       status = ntlmssp_client_start(&state);
+       status = ntlmssp_client_start(&ntlmssp_state);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       status = ntlmssp_set_domain(state, domain);
+       status = ntlmssp_set_domain(ntlmssp_state, dcerpc_security->user.domain);
        if (!NT_STATUS_IS_OK(status)) {
-               goto done;
+               return status;
        }
        
-       status = ntlmssp_set_username(state, username);
+       status = ntlmssp_set_username(ntlmssp_state, dcerpc_security->user.name);
        if (!NT_STATUS_IS_OK(status)) {
-               goto done;
+               return status;
        }
 
-       status = ntlmssp_set_password(state, password);
+       status = ntlmssp_set_password(ntlmssp_state, dcerpc_security->user.password);
        if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
-
-       p->auth_info = talloc(p->mem_ctx, sizeof(*p->auth_info));
-       if (!p->auth_info) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
+               return status;
        }
-
-       p->auth_info->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
        
-       if (p->flags & DCERPC_SEAL) {
-               p->auth_info->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
-               state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL;
-       } else {
-               /* ntlmssp does not work on dcerpc with
-                  AUTH_LEVEL_NONE */
-               state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
-               p->auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
-       }
-       p->auth_info->auth_pad_length = 0;
-       p->auth_info->auth_reserved = 0;
-       p->auth_info->auth_context_id = random();
-       p->auth_info->credentials = data_blob(NULL, 0);
-       p->security_state = NULL;
-
-       status = ntlmssp_update(state, mem_ctx,
-                               p->auth_info->credentials,
-                               &credentials);
-
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-               goto done;
-       }
+       dcerpc_security->private_data = ntlmssp_state;
 
-       p->auth_info->credentials = credentials;
-
-       status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
-
-       status = ntlmssp_update(state, mem_ctx,
-                               p->auth_info->credentials, 
-                               &credentials);
+       return status;
+}
 
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-               goto done;
-       }
+static NTSTATUS dcerpc_ntlmssp_update(struct dcerpc_security *dcerpc_security, TALLOC_CTX *out_mem_ctx, 
+                                               const DATA_BLOB in, DATA_BLOB *out) 
+{
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
 
-       p->auth_info->credentials = credentials;
+       return ntlmssp_update(ntlmssp_state, out_mem_ctx, in, out);
+}
 
-       status = dcerpc_auth3(p, mem_ctx);
+static void dcerpc_ntlmssp_end(struct dcerpc_security *dcerpc_security)
+{
+       struct ntlmssp_state *ntlmssp_state = dcerpc_security->private_data;
 
-       if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
+       ntlmssp_end(&ntlmssp_state);
 
-       p->security_state = talloc_p(p->mem_ctx, struct dcerpc_security);
-       if (!p->security_state) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
+       dcerpc_security->private_data = NULL;
+}
 
-       p->security_state->private = state;
-       p->security_state->unseal_packet = ntlm_unseal_packet;
-       p->security_state->check_packet = ntlm_check_packet;
-       p->security_state->seal_packet = ntlm_seal_packet;
-       p->security_state->sign_packet = ntlm_sign_packet;
-       p->security_state->session_key = ntlm_session_key;
-       p->security_state->security_end = ntlm_security_end;
+static const struct dcesrv_security_ops dcerpc_ntlmssp_security_ops = {
+       .name           = "ntlmssp",
+       .auth_type      = DCERPC_AUTH_TYPE_NTLMSSP,
+       .start          = dcerpc_ntlmssp_start,
+       .update         = dcerpc_ntlmssp_update,
+       .seal           = dcerpc_ntlmssp_seal,
+       .sign           = dcerpc_ntlmssp_sign,
+       .check_sig      = dcerpc_ntlmssp_check_sig,
+       .unseal         = dcerpc_ntlmssp_unseal,
+       .session_key    = dcerpc_ntlmssp_session_key,
+       .end            = dcerpc_ntlmssp_end
+};
+
+const struct dcesrv_security_ops *dcerpc_ntlmssp_security_get_ops(void)
+{
+       return &dcerpc_ntlmssp_security_ops;
+}
 
-done:
-       talloc_destroy(mem_ctx);
+/*
+  do ntlm style authentication on a dcerpc pipe
+*/
+NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
+                              const char *uuid, uint_t version,
+                              const char *domain,
+                              const char *username,
+                              const char *password)
+{
+       NTSTATUS status;
 
-       if (!NT_STATUS_IS_OK(status)) {
-               p->security_state = NULL;
-               p->auth_info = NULL;
-       }
+       status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_NTLMSSP,
+                               uuid, version,
+                               domain, username, 
+                               password);
 
        return status;
 }
index c2645d36a269fde7584fb273ff2c9de59dae7ddb..df15edfb6f1327b2f0d590d3dc0d68efee092cc9 100644 (file)
 
 #include "includes.h"
 
+#define DCERPC_SCHANNEL_STATE_START 0
+#define DCERPC_SCHANNEL_STATE_UPDATE_1 1
+
+struct dcerpc_schannel_state {
+       TALLOC_CTX *mem_ctx;
+       uint8_t state;
+       struct schannel_bind bind_schannel;
+       struct schannel_state *schannel_state;
+};
+
 /*
   wrappers for the schannel_*() functions
 */
-static NTSTATUS schan_unseal_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_schannel_unseal(struct dcerpc_security *dcerpc_security, 
                                    TALLOC_CTX *mem_ctx, 
                                    uint8_t *data, size_t length, DATA_BLOB *sig)
 {
-       struct schannel_state *schannel_state = dcerpc_security->private;
-       return schannel_unseal_packet(schannel_state, mem_ctx, data, length, sig);
+       struct dcerpc_schannel_state *dce_schan_state = dcerpc_security->private_data;
+
+       return schannel_unseal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS schan_check_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_schannel_check_sig(struct dcerpc_security *dcerpc_security, 
                                   TALLOC_CTX *mem_ctx, 
                                   const uint8_t *data, size_t length, 
                                   const DATA_BLOB *sig)
 {
-       struct schannel_state *schannel_state = dcerpc_security->private;
-       return schannel_check_packet(schannel_state, data, length, sig);
+       struct dcerpc_schannel_state *dce_schan_state = dcerpc_security->private_data;
+
+       return schannel_check_packet(dce_schan_state->schannel_state, data, length, sig);
 }
 
-static NTSTATUS schan_seal_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_schannel_seal(struct dcerpc_security *dcerpc_security, 
                                  TALLOC_CTX *mem_ctx, 
                                  uint8_t *data, size_t length, 
                                  DATA_BLOB *sig)
 {
-       struct schannel_state *schannel_state = dcerpc_security->private;
-       return schannel_seal_packet(schannel_state, mem_ctx, data, length, sig);
+       struct dcerpc_schannel_state *dce_schan_state = dcerpc_security->private_data;
+
+       return schannel_seal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS schan_sign_packet(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_schannel_sign(struct dcerpc_security *dcerpc_security, 
                                 TALLOC_CTX *mem_ctx, 
                                 const uint8_t *data, size_t length, 
                                 DATA_BLOB *sig)
 {
-       struct schannel_state *schannel_state = dcerpc_security->private;
-       return schannel_sign_packet(schannel_state, mem_ctx, data, length, sig);
+       struct dcerpc_schannel_state *dce_schan_state = dcerpc_security->private_data;
+
+       return schannel_sign_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
 }
 
-static NTSTATUS schan_session_key(struct dcerpc_security *dcerpc_security, 
+static NTSTATUS dcerpc_schannel_session_key(struct dcerpc_security *dcerpc_security, 
                                  DATA_BLOB *session_key)
 {
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
-static void schan_security_end(struct dcerpc_security *dcerpc_security)
+static NTSTATUS dcerpc_schannel_start(struct dcerpc_pipe *p, struct dcerpc_security *dcerpc_security)
+{
+       struct dcerpc_schannel_state *dce_schan_state;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+       uint8_t session_key[16];
+       int chan_type = 0;
+
+       if (p->flags & DCERPC_SCHANNEL_BDC) {
+               chan_type = SEC_CHAN_BDC;
+       } else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) {
+               chan_type = SEC_CHAN_WKSTA;
+       } else if (p->flags & DCERPC_SCHANNEL_DOMAIN) {
+               chan_type = SEC_CHAN_DOMAIN;
+       }
+
+       status = dcerpc_schannel_key(p, dcerpc_security->user.domain, 
+                                       dcerpc_security->user.name,
+                                       dcerpc_security->user.password, 
+                                       chan_type, session_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       mem_ctx = talloc_init("dcerpc_schannel_start");
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       dce_schan_state = talloc_p(mem_ctx, struct dcerpc_schannel_state);
+       if (!dce_schan_state) {
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       dce_schan_state->mem_ctx = mem_ctx;
+
+       status = schannel_start(&dce_schan_state->schannel_state, session_key, True);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       dce_schan_state->state = DCERPC_SCHANNEL_STATE_START;
+
+       dcerpc_security->private_data = dce_schan_state;
+
+       dump_data_pw("session key:\n", dce_schan_state->schannel_state->session_key, 16);
+
+       return status;
+}
+
+static NTSTATUS dcerpc_schannel_update(struct dcerpc_security *dcerpc_security, TALLOC_CTX *out_mem_ctx, 
+                                               const DATA_BLOB in, DATA_BLOB *out) 
 {
-       struct schannel_state *schannel_state = dcerpc_security->private;
-       schannel_end(&schannel_state);
+       struct dcerpc_schannel_state *dce_schan_state = dcerpc_security->private_data;
+       NTSTATUS status;
+       struct schannel_bind bind_schannel;
+
+       if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) {
+               return NT_STATUS_OK;
+       }
+
+       dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1;
+
+       bind_schannel.unknown1 = 0;
+#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 = dcerpc_security->user.domain;
+       bind_schannel.u.info23.account_name = dcerpc_security->user.name;
+       bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(dce_schan_state->mem_ctx, fulldomainname);
+       bind_schannel.u.info23.workstation = str_format_nbt_domain(dce_schan_state->mem_ctx, dcerpc_security->user.name);
+#else
+       bind_schannel.bind_type = 3;
+       bind_schannel.u.info3.domain = dcerpc_security->user.domain;
+       bind_schannel.u.info3.account_name = dcerpc_security->user.name;
+#endif
+
+       status = ndr_push_struct_blob(out, dce_schan_state->mem_ctx, &bind_schannel,
+                                     (ndr_push_flags_fn_t)ndr_push_schannel_bind);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static void dcerpc_schannel_end(struct dcerpc_security *dcerpc_security)
+{
+       struct dcerpc_schannel_state *dce_schan_state = dcerpc_security->private_data;
+
+       schannel_end(&dce_schan_state->schannel_state);
+
+       talloc_destroy(dce_schan_state->mem_ctx);
+
+       dcerpc_security->private_data = NULL;
 }
 
 
@@ -163,107 +269,24 @@ NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
        return NT_STATUS_OK;
 }
 
-
-/*
-  do a schannel style bind on a dcerpc pipe with the given schannel
-  key. The username is usually of the form HOSTNAME$ and the password
-  is the domain trust password
-*/
-NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
-                                      const char *uuid, uint_t version,
-                                      const char *domain,
-                                      const char *username,
-                                      const uint8_t session_key[16])
+const struct dcesrv_security_ops dcerpc_schannel_security_ops = {
+       .name           = "schannel",
+       .auth_type      = DCERPC_AUTH_TYPE_SCHANNEL,
+       .start          = dcerpc_schannel_start,
+       .update         = dcerpc_schannel_update,
+       .seal           = dcerpc_schannel_seal,
+       .sign           = dcerpc_schannel_sign,
+       .check_sig      = dcerpc_schannel_check_sig,
+       .unseal         = dcerpc_schannel_unseal,
+       .session_key    = dcerpc_schannel_session_key,
+       .end            = dcerpc_schannel_end
+};
+
+const struct dcesrv_security_ops *dcerpc_schannel_security_get_ops(void)
 {
-       NTSTATUS status;
-       struct schannel_state *schannel_state;
-       const char *workgroup, *workstation;
-       struct schannel_bind bind_schannel;
-
-       workstation = username;
-       workgroup = domain;
-
-       /*
-         perform a bind with security type schannel
-       */
-       p->auth_info = talloc(p->mem_ctx, sizeof(*p->auth_info));
-       if (!p->auth_info) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-
-       p->auth_info->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
-       
-       if (p->flags & DCERPC_SEAL) {
-               p->auth_info->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
-       } else {
-               /* note that DCERPC_AUTH_LEVEL_NONE does not make any 
-                  sense, and would be rejected by the server */
-               p->auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
-       }
-       p->auth_info->auth_pad_length = 0;
-       p->auth_info->auth_reserved = 0;
-       p->auth_info->auth_context_id = random();
-       p->security_state = NULL;
-
-       bind_schannel.unknown1 = 0;
-#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_schannel_bind);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
-
-       /* send the authenticated bind request */
-       status = dcerpc_bind_byuuid(p, p->mem_ctx, uuid, version);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
-
-       p->security_state = talloc_p(p->mem_ctx, struct dcerpc_security);
-       if (!p->security_state) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-
-       schannel_state = talloc_p(p->mem_ctx, struct schannel_state);
-       if (!schannel_state) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
-
-       status = schannel_start(&schannel_state, session_key, True);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto done;
-       }
-
-       dump_data_pw("session key:\n", schannel_state->session_key, 16);
-
-       p->security_state->private = schannel_state;
-       p->security_state->unseal_packet = schan_unseal_packet;
-       p->security_state->check_packet = schan_check_packet;
-       p->security_state->seal_packet = schan_seal_packet;
-       p->security_state->sign_packet = schan_sign_packet;
-       p->security_state->session_key = schan_session_key;
-       p->security_state->security_end = schan_security_end;
-
-done:
-       return status;
+       return &dcerpc_schannel_security_ops;
 }
 
-
 /*
   do a schannel style bind on a dcerpc pipe. The username is usually
   of the form HOSTNAME$ and the password is the domain trust password
@@ -275,25 +298,11 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
                                   const char *password)
 {
        NTSTATUS status;
-       uint8_t session_key[16];
-       int chan_type = 0;
 
-       if (p->flags & DCERPC_SCHANNEL_BDC) {
-               chan_type = SEC_CHAN_BDC;
-       } else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) {
-               chan_type = SEC_CHAN_WKSTA;
-       } else if (p->flags & DCERPC_SCHANNEL_DOMAIN) {
-               chan_type = SEC_CHAN_DOMAIN;
-       } 
-
-       status = dcerpc_schannel_key(p, domain, username, password, 
-                                    chan_type, session_key);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       status = dcerpc_bind_auth_schannel_key(p, uuid, version, domain, username, session_key);
+       status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL,
+                               uuid, version,
+                               domain, username, 
+                               password);
 
        return status;
 }
-
index c7edf043ece5735d9f1345cc7262869e88332858..59233295a3803b0d2e25284cf8b15a43633f6257 100644 (file)
@@ -697,8 +697,8 @@ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
 {
        struct cli_tree *tree;
 
-       if (p->security_state) {
-               return p->security_state->session_key(p->security_state, session_key);
+       if (p->security_state.ops) {
+               return p->security_state.ops->session_key(&p->security_state, session_key);
        }
        
        tree = dcerpc_smb_tree(p);