mirror of
https://github.com/samba-team/samba.git
synced 2025-11-07 12:23:51 +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:
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
42
source/rpc_server/dcesrv_auth.c
Normal file
42
source/rpc_server/dcesrv_auth.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user