summaryrefslogtreecommitdiff
path: root/source4/rpc_server
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-12-14 10:45:50 +0000
committerAndrew Tridgell <tridge@samba.org>2003-12-14 10:45:50 +0000
commitd009dc61f90e45b695fb9eaaf11899c7572dc9a7 (patch)
tree95106415da035447f3b5a7779d6e149ce6512f2c /source4/rpc_server
parente2898c098fa090303ad0df67d5a9c454bac63e86 (diff)
downloadsamba-d009dc61f90e45b695fb9eaaf11899c7572dc9a7.tar.gz
samba-d009dc61f90e45b695fb9eaaf11899c7572dc9a7.tar.bz2
samba-d009dc61f90e45b695fb9eaaf11899c7572dc9a7.zip
ntlmssp over rpc over tcp now fully works
I needed to hack the ntlmssp code a little, as the auth code in samba4 is out of date relative to the samba3 auth code. I need to do a merge :) (This used to be commit 6ee0935afe9444bf9bb24eed4e02e8377dc746b7)
Diffstat (limited to 'source4/rpc_server')
-rw-r--r--source4/rpc_server/dcerpc_server.c44
-rw-r--r--source4/rpc_server/dcerpc_server.h2
-rw-r--r--source4/rpc_server/dcesrv_auth.c253
3 files changed, 290 insertions, 9 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 7fa7a7aa8b..16b573cfad 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -369,7 +369,8 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return NT_STATUS_NO_MEMORY;
}
- status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
+ status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt,
+ call->dce->auth_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -377,7 +378,26 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length);
DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
+ DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ handle a auth3 request
+*/
+static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
+{
+ /* handle the auth3 in the auth code */
+ if (!dcesrv_auth_auth3(call)) {
+ return dcesrv_fault(call, DCERPC_FAULT_OTHER);
+ }
+
+ talloc_destroy(call->mem_ctx);
+ /* we don't send a reply to a auth3 request, except by a
+ fault */
return NT_STATUS_OK;
}
@@ -473,10 +493,8 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
pkt.u.response.stub_and_verifier.data = stub.data;
pkt.u.response.stub_and_verifier.length = length;
-
- status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
+ return dcesrv_fault(call, DCERPC_FAULT_OTHER);
}
SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length);
@@ -487,6 +505,8 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
stub.length -= length;
} while (stub.length != 0);
+ DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
+
return NT_STATUS_OK;
}
@@ -568,6 +588,13 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
dce_partial_advance(dce, blob.length);
+ /* we have to check the signing here, before combining the
+ pdus */
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+ !dcesrv_auth_request(call)) {
+ return dcesrv_fault(call, DCERPC_FAULT_OTHER);
+ }
+
/* see if this is a continued packet */
if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
struct dcesrv_call_state *call2 = call;
@@ -623,6 +650,9 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
case DCERPC_PKT_BIND:
status = dcesrv_bind(call);
break;
+ case DCERPC_PKT_AUTH3:
+ status = dcesrv_auth3(call);
+ break;
case DCERPC_PKT_REQUEST:
status = dcesrv_request(call);
break;
@@ -634,9 +664,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
/* if we are going to be sending a reply then add
it to the list of pending calls. We add it to the end to keep the call
list in the order we will answer */
- if (NT_STATUS_IS_OK(status)) {
- DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
- } else {
+ if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
}
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index a2be1d8e06..e731a5719c 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -72,7 +72,7 @@ struct dcesrv_handle {
/* hold the authentication state information */
struct dcesrv_auth {
- struct ntlmssp_state *ntlmssp_state;
+ struct auth_ntlmssp_state *ntlmssp_state;
struct dcerpc_auth *auth_info;
};
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index aea79f2927..f290c741cb 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -25,10 +25,49 @@
/*
parse any auth information from a dcerpc bind request
+ return False if we can't handle the auth request for some
+ reason (in which case we send a bind_nak)
*/
BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
{
struct dcerpc_packet *pkt = &call->pkt;
+ struct dcesrv_state *dce = call->dce;
+ NTSTATUS status;
+
+ if (pkt->u.bind.auth_info.length == 0) {
+ dce->auth_state.auth_info = NULL;
+ return True;
+ }
+
+ dce->auth_state.auth_info = talloc_p(dce->mem_ctx, struct dcerpc_auth);
+ if (!dce->auth_state.auth_info) {
+ return False;
+ }
+
+ status = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
+ call->mem_ctx,
+ dce->auth_state.auth_info,
+ (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (dce->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
+ /* only do NTLMSSP for now */
+ DEBUG(2,("auth_type %d not supported\n", dce->auth_state.auth_info->auth_type));
+ return False;
+ }
+
+ if (dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
+ dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ DEBUG(2,("auth_level %d not supported\n", dce->auth_state.auth_info->auth_level));
+ return False;
+ }
+
+ status = auth_ntlmssp_start(&dce->auth_state.ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
return True;
}
@@ -38,5 +77,219 @@ BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
*/
BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt)
{
+ struct dcesrv_state *dce = call->dce;
+ NTSTATUS status;
+
+ if (!call->dce->auth_state.ntlmssp_state) {
+ return True;
+ }
+
+ status = auth_ntlmssp_update(dce->auth_state.ntlmssp_state,
+ dce->auth_state.auth_info->credentials,
+ &dce->auth_state.auth_info->credentials);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return False;
+ }
+
+ dce->auth_state.auth_info->auth_pad_length = 0;
+ dce->auth_state.auth_info->auth_reserved = 0;
+
+ return True;
+}
+
+
+/*
+ process the final stage of a NTLMSSP auth request
+*/
+BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
+{
+ struct dcerpc_packet *pkt = &call->pkt;
+ struct dcesrv_state *dce = call->dce;
+ NTSTATUS status;
+
+ if (!dce->auth_state.auth_info ||
+ !dce->auth_state.ntlmssp_state ||
+ pkt->u.auth.auth_info.length == 0) {
+ return False;
+ }
+
+ status = ndr_pull_struct_blob(&pkt->u.auth.auth_info,
+ call->mem_ctx,
+ dce->auth_state.auth_info,
+ (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (dce->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
+ return False;
+ }
+ if (dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
+ dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ return False;
+ }
+
+ status = auth_ntlmssp_update(dce->auth_state.ntlmssp_state,
+ dce->auth_state.auth_info->credentials,
+ &dce->auth_state.auth_info->credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ switch (dce->auth_state.auth_info->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ /* setup for signing */
+ status = ntlmssp_sign_init(dce->auth_state.ntlmssp_state->ntlmssp_state);
+ break;
+ }
+
+ return True;
+}
+
+
+/*
+ check credentials on a request
+*/
+BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
+{
+ struct dcerpc_packet *pkt = &call->pkt;
+ struct dcesrv_state *dce = call->dce;
+ DATA_BLOB auth_blob;
+ struct dcerpc_auth auth;
+ struct ndr_pull *ndr;
+ NTSTATUS status;
+
+ if (!dce->auth_state.auth_info ||
+ !dce->auth_state.ntlmssp_state) {
+ return True;
+ }
+
+ auth_blob.length = 8 + pkt->auth_length;
+
+ /* check for a valid length */
+ if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
+ return False;
+ }
+
+ auth_blob.data =
+ pkt->u.request.stub_and_verifier.data +
+ pkt->u.request.stub_and_verifier.length - auth_blob.length;
+ pkt->u.request.stub_and_verifier.length -= auth_blob.length;
+
+ /* pull the auth structure */
+ ndr = ndr_pull_init_blob(&auth_blob, call->mem_ctx);
+ if (!ndr) {
+ return False;
+ }
+
+ status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* check signature or unseal the packet */
+ switch (dce->auth_state.auth_info->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = ntlmssp_unseal_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
+ pkt->u.request.stub_and_verifier.data,
+ pkt->u.request.stub_and_verifier.length,
+ &auth.credentials);
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ status = ntlmssp_check_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
+ pkt->u.request.stub_and_verifier.data,
+ pkt->u.request.stub_and_verifier.length,
+ &auth.credentials);
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ /* remove the indicated amount of paddiing */
+ if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
+ return False;
+ }
+ pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/*
+ push a signed or sealed dcerpc request packet into a blob
+*/
+BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
+ DATA_BLOB *blob, struct dcerpc_packet *pkt)
+{
+ struct dcesrv_state *dce = call->dce;
+ NTSTATUS status;
+ struct ndr_push *ndr;
+
+ /* non-signed packets are simple */
+ if (!dce->auth_state.auth_info || !dce->auth_state.ntlmssp_state) {
+ status = dcerpc_push_auth(blob, call->mem_ctx, pkt, NULL);
+ return NT_STATUS_IS_OK(status);
+ }
+
+ ndr = ndr_push_init_ctx(call->mem_ctx);
+ if (!ndr) {
+ return False;
+ }
+
+ status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* pad to 8 byte multiple */
+ dce->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
+ ndr_push_zero(ndr, dce->auth_state.auth_info->auth_pad_length);
+
+ /* sign or seal the packet */
+ switch (dce->auth_state.auth_info->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = ntlmssp_seal_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &dce->auth_state.auth_info->credentials);
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ status = ntlmssp_sign_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &dce->auth_state.auth_info->credentials);
+ break;
+ default:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* add the auth verifier */
+ status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce->auth_state.auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* extract the whole packet as a blob */
+ *blob = ndr_push_blob(ndr);
+
+ /* fill in the fragment length and auth_length, we can't fill
+ in these earlier as we don't know the signature length (it
+ could be variable length) */
+ SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, blob->length);
+ SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, dce->auth_state.auth_info->credentials.length);
+
+ data_blob_free(&dce->auth_state.auth_info->credentials);
+
return True;
}