1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-08 16:23:49 +03:00

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 commit is contained in:
Andrew Tridgell
-
parent ebe29305af
commit 74041b6a0a
7 changed files with 164 additions and 107 deletions

View File

@@ -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 \

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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) {
return NT_STATUS_NO_MEMORY;
}
status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
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);
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 *);
@@ -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) {
return NT_STATUS_NO_MEMORY;
}
status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
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);
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 *);
@@ -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

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;
}