added auto-determination of the DCERPC over TCP port number by asking
authorAndrew Tridgell <tridge@samba.org>
Wed, 26 Nov 2003 03:36:17 +0000 (03:36 +0000)
committerAndrew Tridgell <tridge@samba.org>
Wed, 26 Nov 2003 03:36:17 +0000 (03:36 +0000)
the servers endpoint mapper
(This used to be commit 4abf5376b00f580eb69196e55a792cc7eb4c9880)

source4/Makefile.in
source4/build/pidl/idl.gram
source4/librpc/idl/dcerpc.idl
source4/librpc/idl/epmapper.idl
source4/librpc/rpc/dcerpc.c
source4/librpc/rpc/dcerpc_util.c [new file with mode: 0644]
source4/torture/torture.c

index 4f7b20837c6fbf42c63b20845c4a520c2c108eac..c6b763137eea36d0fbf2777775b28d8ca2e6efe5 100644 (file)
@@ -200,6 +200,7 @@ LIBRAW_NDR_OBJ = librpc/ndr/ndr.o librpc/ndr/ndr_basic.o librpc/ndr/ndr_sec.o \
                librpc/gen_ndr/ndr_mgmt.o
 
 LIBRAW_RPC_OBJ = librpc/rpc/dcerpc.o librpc/rpc/dcerpc_auth.o \
+               librpc/rpc/dcerpc_util.o \
                librpc/rpc/dcerpc_smb.o librpc/rpc/dcerpc_tcp.o \
                librpc/gen_rpc/rpc_echo.o librpc/gen_rpc/rpc_lsa.o \
                librpc/gen_rpc/rpc_dfs.o librpc/gen_rpc/rpc_spoolss.o \
index 5cba06f0147c5cf79e6391a603eadc7d7fc37509..897a5ad769cb86cf505980a2c945b9d8bdde3512 100644 (file)
@@ -166,7 +166,7 @@ type :
 
 text: /[\w\s\..?-]*/
 
-text2: /[\|\w\s,\*\>"\/\..?-]*/
+text2: /[\|\w\s,\*&\>"\/\..?-]*/
 
 anytext: text2 '(' <commit> anytext ')' anytext
         {{ "$item[1]($item[4])$item[6]" }}
index 978bc5640c6e87568e9415aef60df9760ba25eee..c23553c444445783ddfa4b7c92cc559ffa878d89 100644 (file)
@@ -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 */
index 172c83149b1c3a78f56d3f60d9b9b084a70d8719..6fa9a7bd608c6d3b37723da583fb5df230b6f336 100644 (file)
@@ -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;
 
index 83fb0b592c25df6e4b4d65d776b769fc46d336ce..2fc940314d5c2dc4093e8f102097e2bb380da7b6 100644 (file)
@@ -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 (file)
index 0000000..75799c1
--- /dev/null
@@ -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;
+}
index 11b27f12ebfb227d7de37e4d0daea27c8be3ccb5..18d339d65e8087f1962403c5c32275d1c20b28f8 100644 (file)
@@ -138,11 +138,21 @@ static NTSTATUS torture_rpc_tcp(struct dcerpc_pipe **p,
 {
         NTSTATUS status;
        char *host = lp_parm_string(-1, "torture", "host");
-       const char *port = lp_parm_string(-1, "torture", "share");
+       const char *port_str = lp_parm_string(-1, "torture", "share");
+       uint32 port = atoi(port_str);
+
+       if (port == 0) {
+               status = dcerpc_epm_map_tcp_port(host, 
+                                                pipe_uuid, pipe_version,
+                                                &port);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
 
-       DEBUG(2,("Connecting to dcerpc server %s:%s\n", host, port));
+       DEBUG(2,("Connecting to dcerpc server %s:%u\n", host, port));
 
-       status = dcerpc_pipe_open_tcp(p, host, atoi(port));
+       status = dcerpc_pipe_open_tcp(p, host, port);
        if (!NT_STATUS_IS_OK(status)) {
                 printf("Open of pipe '%s' failed with error (%s)\n",
                       pipe_name, nt_errstr(status));
@@ -202,14 +212,10 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p,
         }
 
        /* bind to the pipe, using the uuid as the key */
-#if 1
        status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
                                       lp_workgroup(),
                                       lp_parm_string(-1, "torture", "username"),
                                       lp_parm_string(-1, "torture", "password"));
-#else
-       status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
-#endif
        if (!NT_STATUS_IS_OK(status)) {
                dcerpc_pipe_close(*p);
                return status;