summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/librpc/rpc/dcerpc.c52
-rw-r--r--source4/librpc/rpc/dcerpc.h46
-rw-r--r--source4/librpc/rpc/dcerpc_auth.c99
-rw-r--r--source4/librpc/rpc/dcerpc_ntlm.c178
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c273
-rw-r--r--source4/librpc/rpc/dcerpc_util.c4
6 files changed, 370 insertions, 282 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 5d317794e1..e80e168c89 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -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;
}
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 7bd6f98118..7694a9c230 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -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 {
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index 3faf0603ce..021249847a 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -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;
+}
diff --git a/source4/librpc/rpc/dcerpc_ntlm.c b/source4/librpc/rpc/dcerpc_ntlm.c
index db707be1b5..2cfecd939f 100644
--- a/source4/librpc/rpc/dcerpc_ntlm.c
+++ b/source4/librpc/rpc/dcerpc_ntlm.c
@@ -25,174 +25,138 @@
/*
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;
}
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index c2645d36a2..df15edfb6f 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -22,54 +22,160 @@
#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;
}
-
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index c7edf043ec..59233295a3 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -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);