From 8f6b3eb1a9c1e996330b0edfb312b2345e292819 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 14 Dec 2003 01:09:10 +0000 Subject: fixed a bug handling multiple PDUs being read from a socket at one time in the rpc server. started on the framework for the dcerpc authentication server code (This used to be commit 74041b6a0a60d792e1b220496d66ec27b9ee6c25) --- source4/Makefile.in | 1 + source4/librpc/rpc/dcerpc.c | 47 +------------- source4/librpc/rpc/dcerpc_util.c | 40 ++++++++++++ source4/rpc_server/dcerpc_server.c | 121 +++++++++++++++++++------------------ source4/rpc_server/dcerpc_server.h | 10 +++ source4/rpc_server/dcerpc_tcp.c | 2 + source4/rpc_server/dcesrv_auth.c | 42 +++++++++++++ 7 files changed, 160 insertions(+), 103 deletions(-) create mode 100644 source4/rpc_server/dcesrv_auth.c diff --git a/source4/Makefile.in b/source4/Makefile.in index dca9c8b7bd..e8705da4cc 100644 --- a/source4/Makefile.in +++ b/source4/Makefile.in @@ -285,6 +285,7 @@ SMBD_NTVFS_OBJ = ntvfs/ntvfs_base.o ntvfs/ntvfs_util.o \ ntvfs/ntvfs_generic.o @NTVFS_STATIC@ SMBD_RPC_OBJ = rpc_server/dcerpc_server.o \ + rpc_server/dcesrv_auth.o \ rpc_server/dcerpc_tcp.o \ rpc_server/handles.o \ rpc_server/echo/rpc_echo.o \ diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index e0b3a550a7..f1756215b1 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -172,47 +172,6 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, } -/* - push a dcerpc_packet into a blob. This handles both input and - output packets -*/ -static NTSTATUS dcerpc_push(struct dcerpc_pipe *p, - DATA_BLOB *blob, TALLOC_CTX *mem_ctx, - struct dcerpc_packet *pkt) -{ - NTSTATUS status; - struct ndr_push *ndr; - - ndr = ndr_push_init_ctx(mem_ctx); - if (!ndr) { - return NT_STATUS_NO_MEMORY; - } - - if (p->auth_info) { - pkt->auth_length = p->auth_info->credentials.length; - } else { - pkt->auth_length = 0; - } - - status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (p->auth_info) { - status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, - p->auth_info); - } - - *blob = ndr_push_blob(ndr); - - /* fill in the frag length */ - SSVAL(blob->data, 8, blob->length); - - return NT_STATUS_OK; -} - - /* push a dcerpc request packet into a blob, possibly signing it. */ @@ -225,7 +184,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* non-signed packets are simpler */ if (!p->auth_info || !p->ntlmssp_state) { - return dcerpc_push(p, blob, mem_ctx, pkt); + return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info); } ndr = ndr_push_init_ctx(mem_ctx); @@ -345,7 +304,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(p, &blob, mem_ctx, &pkt); + status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -404,7 +363,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(p, &blob, mem_ctx, &pkt); + status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info); if (!NT_STATUS_IS_OK(status)) { return status; } diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index de46f532c6..335761e10f 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -201,3 +201,43 @@ const struct dcerpc_interface_table *idl_iface_by_name(const char *name) } return NULL; } + + + +/* + push a dcerpc_packet into a blob, potentially with auth info +*/ +NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + struct dcerpc_packet *pkt, + struct dcerpc_auth *auth_info) +{ + NTSTATUS status; + struct ndr_push *ndr; + + ndr = ndr_push_init_ctx(mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + + if (auth_info) { + pkt->auth_length = auth_info->credentials.length; + } else { + pkt->auth_length = 0; + } + + status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (auth_info) { + status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info); + } + + *blob = ndr_push_blob(ndr); + + /* fill in the frag length */ + SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, blob->length); + + return NT_STATUS_OK; +} diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 4493ffdaa5..81715f038b 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -130,6 +130,8 @@ NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce, (*p)->handles = NULL; (*p)->next_handle = 0; (*p)->partial_input = data_blob(NULL, 0); + (*p)->auth_state.ntlmssp_state = NULL; + (*p)->auth_state.auth_info = NULL; /* make sure the endpoint server likes the connection */ status = ops->connect(*p); @@ -182,7 +184,6 @@ void dcesrv_endpoint_disconnect(struct dcesrv_state *p) */ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code) { - struct ndr_push *push; struct dcerpc_packet pkt; struct dcesrv_call_reply *rep; NTSTATUS status; @@ -203,23 +204,16 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code) pkt.u.fault.cancel_count = 0; pkt.u.fault.status = fault_code; - /* now form the NDR for the fault */ - push = ndr_push_init_ctx(call->mem_ctx); - if (!push) { + rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply); + if (!rep) { return NT_STATUS_NO_MEMORY; } - status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); + status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL); if (!NT_STATUS_IS_OK(status)) { return status; } - rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply); - if (!rep) { - return NT_STATUS_NO_MEMORY; - } - - rep->data = ndr_push_blob(push); SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length); DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *); @@ -249,7 +243,6 @@ static NTSTATUS dcesrv_fault_nt(struct dcesrv_call_state *call, NTSTATUS status) */ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason) { - struct ndr_push *push; struct dcerpc_packet pkt; struct dcesrv_call_reply *rep; NTSTATUS status; @@ -268,23 +261,16 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason) pkt.u.bind_nak.reject_reason = reason; pkt.u.bind_nak.num_versions = 0; - /* now form the NDR for the bind_nak */ - push = ndr_push_init_ctx(call->mem_ctx); - if (!push) { + rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply); + if (!rep) { return NT_STATUS_NO_MEMORY; } - status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); + status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL); if (!NT_STATUS_IS_OK(status)) { return status; } - rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply); - if (!rep) { - return NT_STATUS_NO_MEMORY; - } - - rep->data = ndr_push_blob(push); SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length); DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *); @@ -301,7 +287,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) const char *uuid, *transfer_syntax; uint32 if_version, transfer_syntax_version; struct dcerpc_packet pkt; - struct ndr_push *push; struct dcesrv_call_reply *rep; NTSTATUS status; uint32 result=0, reason=0; @@ -338,6 +323,11 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) call->dce->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag; } + /* handle any authentication that is being requested */ + if (!dcesrv_auth_bind(call)) { + return dcesrv_bind_nak(call, 0); + } + /* setup a bind_ack */ pkt.rpc_vers = 5; pkt.rpc_vers_minor = 0; @@ -370,15 +360,8 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) pkt.u.bind_ack.ctx_list[0].syntax.minor_version = 0; pkt.u.bind_ack.auth_info = data_blob(NULL, 0); - /* now form the NDR for the bind_ack */ - push = ndr_push_init_ctx(call->mem_ctx); - if (!push) { - return NT_STATUS_NO_MEMORY; - } - - status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (!dcesrv_auth_bind_ack(call, &pkt)) { + return dcesrv_bind_nak(call, 0); } rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply); @@ -386,7 +369,11 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) return NT_STATUS_NO_MEMORY; } - rep->data = ndr_push_blob(push); + status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length); DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *); @@ -486,17 +473,12 @@ 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; - push = ndr_push_init_ctx(call->mem_ctx); - if (!push) { - return NT_STATUS_NO_MEMORY; - } - - status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); + + status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL); if (!NT_STATUS_IS_OK(status)) { return status; } - - rep->data = ndr_push_blob(push); + SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length); DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *); @@ -544,29 +526,15 @@ static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset) } /* - provide some input to a dcerpc endpoint server. This passes data - from a dcerpc client into the server + process some input to a dcerpc endpoint server. */ -NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data) +NTSTATUS dcesrv_input_process(struct dcesrv_state *dce) { struct ndr_pull *ndr; TALLOC_CTX *mem_ctx; NTSTATUS status; struct dcesrv_call_state *call; - - dce->partial_input.data = talloc_realloc(dce->mem_ctx, - dce->partial_input.data, - dce->partial_input.length + data->length); - if (!dce->partial_input.data) { - return NT_STATUS_NO_MEMORY; - } - memcpy(dce->partial_input.data + dce->partial_input.length, - data->data, data->length); - dce->partial_input.length += data->length; - - if (!dce_full_packet(&dce->partial_input)) { - return NT_STATUS_OK; - } + DATA_BLOB blob; mem_ctx = talloc_init("dcesrv_input"); if (!mem_ctx) { @@ -582,7 +550,10 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data) call->dce = dce; call->replies = NULL; - ndr = ndr_pull_init_blob(&dce->partial_input, mem_ctx); + blob = dce->partial_input; + blob.length = SVAL(blob.data, DCERPC_FRAG_LEN_OFFSET); + + ndr = ndr_pull_init_blob(&blob, mem_ctx); if (!ndr) { talloc_free(dce->mem_ctx, dce->partial_input.data); talloc_destroy(mem_ctx); @@ -673,6 +644,38 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data) return status; } + +/* + provide some input to a dcerpc endpoint server. This passes data + from a dcerpc client into the server +*/ +NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data) +{ + struct ndr_pull *ndr; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + struct dcesrv_call_state *call; + + dce->partial_input.data = talloc_realloc(dce->mem_ctx, + dce->partial_input.data, + dce->partial_input.length + data->length); + if (!dce->partial_input.data) { + return NT_STATUS_NO_MEMORY; + } + memcpy(dce->partial_input.data + dce->partial_input.length, + data->data, data->length); + dce->partial_input.length += data->length; + + while (dce_full_packet(&dce->partial_input)) { + status = dcesrv_input_process(dce); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + return NT_STATUS_OK; +} + /* retrieve some output from a dcerpc server. The amount of data that is wanted is in data->length and data->data is already allocated diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index dbc24722ce..a2be1d8e06 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -70,6 +70,13 @@ struct dcesrv_handle { void *data; }; +/* hold the authentication state information */ +struct dcesrv_auth { + struct ntlmssp_state *ntlmssp_state; + struct dcerpc_auth *auth_info; +}; + + /* the state associated with a dcerpc server connection */ struct dcesrv_state { /* the top level context for this server */ @@ -105,6 +112,9 @@ struct dcesrv_state { struct dcesrv_handle *handles; DATA_BLOB partial_input; + + /* the current authentication state */ + struct dcesrv_auth auth_state; }; diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c index 8ea0605fb7..ee026b3674 100644 --- a/source4/rpc_server/dcerpc_tcp.c +++ b/source4/rpc_server/dcerpc_tcp.c @@ -107,6 +107,8 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde, return; } + blob.length = ret; + dcesrv_input(r->dce, &blob); data_blob_free(&blob); diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c new file mode 100644 index 0000000000..aea79f2927 --- /dev/null +++ b/source4/rpc_server/dcesrv_auth.c @@ -0,0 +1,42 @@ +/* + Unix SMB/CIFS implementation. + + server side dcerpc authentication code + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +/* + parse any auth information from a dcerpc bind request +*/ +BOOL dcesrv_auth_bind(struct dcesrv_call_state *call) +{ + struct dcerpc_packet *pkt = &call->pkt; + + return True; +} + +/* + add any auth information needed in a bind ack +*/ +BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt) +{ + return True; +} -- cgit