From fffd741a7a00b07c85eec254b8cc7c2fe40cef18 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 26 Nov 2003 03:36:17 +0000 Subject: added auto-determination of the DCERPC over TCP port number by asking the servers endpoint mapper (This used to be commit 4abf5376b00f580eb69196e55a792cc7eb4c9880) --- source4/librpc/rpc/dcerpc.c | 14 ++-- source4/librpc/rpc/dcerpc_util.c | 149 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 source4/librpc/rpc/dcerpc_util.c (limited to 'source4/librpc/rpc') diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 83fb0b592c..2fc940314d 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -43,6 +43,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void) p->call_id = 1; p->auth_info = NULL; p->ntlmssp_state = NULL; + p->flags = 0; return p; } @@ -222,7 +223,8 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* sign the packet */ status = ntlmssp_sign_packet(p->ntlmssp_state, - ndr->data+24, ndr->offset-24, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, &p->auth_info->credentials); if (!NT_STATUS_IS_OK(status)) { return status; @@ -237,9 +239,11 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* extract the whole packet as a blob */ *blob = ndr_push_blob(ndr); - /* fill in the fragment length and auth_length */ - SSVAL(blob->data, 8, blob->length); - SSVAL(blob->data, 10, p->auth_info->credentials.length); + /* 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, p->auth_info->credentials.length); data_blob_free(&p->auth_info->credentials); @@ -422,7 +426,7 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, /* we can write a full max_recv_frag size, minus the dcerpc request header size */ - chunk_size = p->srv_max_recv_frag - 24; + chunk_size = p->srv_max_recv_frag - DCERPC_REQUEST_LENGTH; pkt.ptype = DCERPC_PKT_REQUEST; pkt.call_id = p->call_id++; diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c new file mode 100644 index 0000000000..75799c1a0b --- /dev/null +++ b/source4/librpc/rpc/dcerpc_util.c @@ -0,0 +1,149 @@ +/* + Unix SMB/CIFS implementation. + + dcerpc utility functions + + 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" + +/* + this ndr_size_* stuff should really be auto-generated .... +*/ + +static size_t ndr_size_epm_floor(struct epm_floor *fl) +{ + size_t ret = 5; + if (fl->lhs.protocol == EPM_PROTOCOL_UUID) { + ret += 18; + } else { + ret += fl->lhs.info.lhs_data.length; + } + ret += fl->rhs.rhs_data.length; + return ret; +} + +size_t ndr_size_epm_towers(struct epm_towers *towers) +{ + size_t ret = 2; + int i; + for (i=0;inum_floors;i++) { + ret += ndr_size_epm_floor(&towers->floors[i]); + } + return ret; +} + +/* + work out what TCP port to use for a given interface on a given host +*/ +NTSTATUS dcerpc_epm_map_tcp_port(const char *server, + const char *uuid, unsigned version, + uint32 *port) +{ + struct dcerpc_pipe *p; + NTSTATUS status; + struct epm_Map r; + struct policy_handle handle; + GUID guid; + struct epm_twr_t twr, *twr_r; + + status = dcerpc_pipe_open_tcp(&p, server, 135); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* we can use the pipes memory context here as we will have a short + lived connection */ + status = dcerpc_bind_byuuid(p, p->mem_ctx, + DCERPC_EPMAPPER_UUID, + DCERPC_EPMAPPER_VERSION); + if (!NT_STATUS_IS_OK(status)) { + dcerpc_pipe_close(p); + return status; + } + + ZERO_STRUCT(handle); + ZERO_STRUCT(guid); + + twr.towers.num_floors = 5; + twr.towers.floors = talloc(p->mem_ctx, sizeof(twr.towers.floors[0]) * 5); + + /* what I'd like for christmas ... */ + + /* an RPC interface ... */ + twr.towers.floors[0].lhs.protocol = EPM_PROTOCOL_UUID; + GUID_from_string(uuid, &twr.towers.floors[0].lhs.info.uuid.uuid); + twr.towers.floors[0].lhs.info.uuid.version = version; + twr.towers.floors[0].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2); + + /* encoded with NDR ... */ + twr.towers.floors[1].lhs.protocol = EPM_PROTOCOL_UUID; + GUID_from_string(NDR_GUID, &twr.towers.floors[1].lhs.info.uuid.uuid); + twr.towers.floors[1].lhs.info.uuid.version = 2; + twr.towers.floors[1].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2); + + /* on an RPC connection ... */ + twr.towers.floors[2].lhs.protocol = EPM_PROTOCOL_RPC_C; + twr.towers.floors[2].lhs.info.lhs_data = data_blob(NULL, 0); + twr.towers.floors[2].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2); + + /* on a TCP port ... */ + twr.towers.floors[3].lhs.protocol = EPM_PROTOCOL_TCP; + twr.towers.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); + twr.towers.floors[3].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2); + + /* on an IP link ... */ + twr.towers.floors[4].lhs.protocol = EPM_PROTOCOL_IP; + twr.towers.floors[4].lhs.info.lhs_data = data_blob(NULL, 0); + twr.towers.floors[4].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 4); + + r.in.object = &guid; + r.in.map_tower = &twr; + r.in.entry_handle = &handle; + r.in.max_towers = 1; + r.out.entry_handle = &handle; + + status = dcerpc_epm_Map(p, p->mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + dcerpc_pipe_close(p); + return status; + } + if (r.out.status != 0 || r.out.num_towers != 1) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + twr_r = r.out.towers[0].twr; + if (!twr_r) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + if (twr_r->towers.num_floors != 5 || + twr_r->towers.floors[3].lhs.protocol != EPM_PROTOCOL_TCP || + twr_r->towers.floors[3].rhs.rhs_data.length != 2) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + *port = RSVAL(twr_r->towers.floors[3].rhs.rhs_data.data, 0); + + dcerpc_pipe_close(p); + + return NT_STATUS_OK; +} -- cgit