summaryrefslogtreecommitdiff
path: root/source4/librpc
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-11-26 03:36:17 +0000
committerAndrew Tridgell <tridge@samba.org>2003-11-26 03:36:17 +0000
commitfffd741a7a00b07c85eec254b8cc7c2fe40cef18 (patch)
tree15653de92c489d6ae9ba5ce490965b7ea9a285b8 /source4/librpc
parentc123c8454142d17d2884ae9dd951b7f2a0b1a343 (diff)
downloadsamba-fffd741a7a00b07c85eec254b8cc7c2fe40cef18.tar.gz
samba-fffd741a7a00b07c85eec254b8cc7c2fe40cef18.tar.bz2
samba-fffd741a7a00b07c85eec254b8cc7c2fe40cef18.zip
added auto-determination of the DCERPC over TCP port number by asking
the servers endpoint mapper (This used to be commit 4abf5376b00f580eb69196e55a792cc7eb4c9880)
Diffstat (limited to 'source4/librpc')
-rw-r--r--source4/librpc/idl/dcerpc.idl9
-rw-r--r--source4/librpc/idl/epmapper.idl10
-rw-r--r--source4/librpc/rpc/dcerpc.c14
-rw-r--r--source4/librpc/rpc/dcerpc_util.c149
4 files changed, 176 insertions, 6 deletions
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl
index 978bc5640c..c23553c444 100644
--- a/source4/librpc/idl/dcerpc.idl
+++ b/source4/librpc/idl/dcerpc.idl
@@ -31,6 +31,9 @@ interface dcerpc
[flag(NDR_REMAINING)] DATA_BLOB auth_info;
} dcerpc_bind;
+
+ const uint8 DCERPC_REQUEST_LENGTH = 24;
+
typedef struct {
uint32 alloc_hint;
uint16 context_id;
@@ -62,6 +65,8 @@ interface dcerpc
uint32 versions[num_versions];
} dcerpc_bind_nak;
+ const uint8 DCERPC_RESPONSE_LENGTH = 24;
+
typedef struct {
uint32 alloc_hint;
uint16 context_id;
@@ -140,6 +145,10 @@ interface dcerpc
const uint8 DCERPC_PFC_FLAG_LAST = 0x02;
const uint8 DCERPC_PFC_FLAG_NOCALL = 0x20;
+ /* these offsets are needed by the signing code */
+ const uint8 DCERPC_FRAG_LEN_OFFSET = 8;
+ const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
+
typedef [public] struct {
uint8 rpc_vers; /* RPC version */
uint8 rpc_vers_minor; /* Minor version */
diff --git a/source4/librpc/idl/epmapper.idl b/source4/librpc/idl/epmapper.idl
index 172c83149b..6fa9a7bd60 100644
--- a/source4/librpc/idl/epmapper.idl
+++ b/source4/librpc/idl/epmapper.idl
@@ -22,12 +22,20 @@ interface epmapper
/* this guid indicates NDR encoding in a protocol tower */
const string NDR_GUID = "8a885d04-1ceb-11c9-9fe8-08002b104860";
+ const string NDR_GUID_VERSION = 1;
typedef struct {
GUID uuid;
uint16 version;
} epm_prot_uuid;
+ typedef enum {
+ EPM_PROTOCOL_TCP = 0x07,
+ EPM_PROTOCOL_IP = 0x09,
+ EPM_PROTOCOL_RPC_C = 0x0b,
+ EPM_PROTOCOL_UUID = 0x0d
+ } epm_protocols;
+
typedef [nodiscriminant] union {
[case(13)] epm_prot_uuid uuid;
[default] [flag(NDR_REMAINING)] DATA_BLOB lhs_data;
@@ -58,7 +66,7 @@ interface epmapper
} epm_towers;
typedef struct {
- uint32 tower_length;
+ [value(ndr_size_epm_towers(&r->towers))] uint32 tower_length;
[subcontext(4)] epm_towers towers;
} epm_twr_t;
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;i<towers->num_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;
+}