From a8d4d3c9f6e9a6726c9df5794646b2528eab703e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 21 Oct 2004 19:54:38 +0000 Subject: r3123: Add dcerpc_binding_build_tower() Add local test for testing the functions dcerpc_parse_binding(), dcerpc_binding_string() and dcerpc_binding_build_tower() (This used to be commit 7a07c2c769b8e51178789eed4a31577f5d39f63a) --- source4/librpc/idl/epmapper.idl | 2 +- source4/librpc/rpc/dcerpc_util.c | 194 +++++++++++++++++++++++++++++++-- source4/torture/config.mk | 3 +- source4/torture/local/binding_string.c | 81 ++++++++++++++ source4/torture/torture.c | 1 + 5 files changed, 269 insertions(+), 12 deletions(-) create mode 100644 source4/torture/local/binding_string.c (limited to 'source4') diff --git a/source4/librpc/idl/epmapper.idl b/source4/librpc/idl/epmapper.idl index 81f9b0976c..e1e980b0fd 100644 --- a/source4/librpc/idl/epmapper.idl +++ b/source4/librpc/idl/epmapper.idl @@ -151,7 +151,7 @@ interface epmapper } epm_rhs_null; typedef struct { - astring identifier; + uint16 minor_version; } epm_rhs_ncalrpc; typedef struct { diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index bded74c407..3b4f7a7efb 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -247,8 +247,8 @@ static const struct { { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_IP, EPM_PROTOCOL_TCP } }, { "ncadg_ip_udp", NCACN_IP_UDP, 3, { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_IP, EPM_PROTOCOL_UDP } }, - { "ncalrpc", NCALRPC, 1, - { EPM_PROTOCOL_NCALRPC } }, + { "ncalrpc", NCALRPC, 2, + { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE } }, { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2, { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } }, { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2, @@ -276,6 +276,8 @@ static const struct { {"bigendian", DCERPC_PUSH_BIGENDIAN} }; + + /* form a binding string from a binding structure */ @@ -298,26 +300,31 @@ const char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_bindi s = talloc_asprintf(mem_ctx, "%s@", GUID_string(mem_ctx, b->object)); } - s = talloc_asprintf_append(s, "%s:%s[", t_name, b->host); + s = talloc_asprintf_append(s, "%s:%s", t_name, b->host); if (!s) return NULL; + if ((!b->options || !b->options[0]) && !b->flags) { + return s; + } + + s = talloc_asprintf_append(s, "["); + /* this is a *really* inefficent way of dealing with strings, but this is rarely called and the strings are always short, so I don't care */ for (i=0;b->options && b->options[i];i++) { - s = talloc_asprintf(mem_ctx, "%s%s,", s, b->options[i]); + s = talloc_asprintf_append(s, "%s,", b->options[i]); if (!s) return NULL; } for (i=0;iflags & ncacn_options[i].flag) { - s = talloc_asprintf(mem_ctx, "%s%s,", s, ncacn_options[i].name); + s = talloc_asprintf_append(s, "%s,", ncacn_options[i].name); if (!s) return NULL; } } - if (s[strlen(s)-1] == ',') { - s[strlen(s)-1] = 0; - } - s = talloc_asprintf(mem_ctx, "%s]", s); + + s[strlen(s)-1] = 0; + s = talloc_asprintf_append(s, "]"); return s; } @@ -431,6 +438,173 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ return NT_STATUS_OK; } +static NTSTATUS floor_set_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor, const char *data) +{ + switch (floor->lhs.protocol) { + case EPM_PROTOCOL_TCP: + floor->rhs.tcp.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_UDP: + floor->rhs.udp.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_HTTP: + floor->rhs.http.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_IP: + floor->rhs.ip.address = 0; + + /* Only try to put in a IPv4 address. Windows 2003 just returns + * 0.0.0.0 for IPv6 addresses */ + if (strlen(data) > 0) { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(struct addrinfo)); + + hints.ai_family = AF_INET; + + if (getaddrinfo(data, NULL, &hints, &res) < 0) { + return NT_STATUS_BAD_NETWORK_NAME; + } + + floor->rhs.ip.address = ntohl(((struct in_addr *)res->ai_addr)->s_addr); + + freeaddrinfo(res); + } + return NT_STATUS_OK; + + case EPM_PROTOCOL_NCACN: + floor->rhs.ncacn.minor_version = 0; + return NT_STATUS_OK; + + case EPM_PROTOCOL_NCADG: + floor->rhs.ncadg.minor_version = 0; + return NT_STATUS_OK; + + case EPM_PROTOCOL_SMB: + floor->rhs.smb.unc = talloc_strdup(mem_ctx, data); + if (!floor->rhs.smb.unc) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; + + case EPM_PROTOCOL_PIPE: + floor->rhs.pipe.path = talloc_strdup(mem_ctx, data); + if (!floor->rhs.pipe.path) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; + + case EPM_PROTOCOL_NETBIOS: + floor->rhs.netbios.name = talloc_strdup(mem_ctx, data); + if (!floor->rhs.netbios.name) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; + + case EPM_PROTOCOL_NCALRPC: + return NT_STATUS_OK; + + case EPM_PROTOCOL_VINES_SPP: + floor->rhs.vines_spp.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_VINES_IPC: + floor->rhs.vines_ipc.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_STREETTALK: + floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data); + if (!floor->rhs.streettalk.streettalk) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; + + case EPM_PROTOCOL_UNIX_DS: + floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data); + if (!floor->rhs.unix_ds.path) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; + + case EPM_PROTOCOL_NULL: + return NT_STATUS_OK; + } + + return NT_STATUS_NOT_SUPPORTED; +} + + +NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower **tower) +{ + const enum epm_protocols *protseq; + int num_protocols = -1, i; + NTSTATUS status; + + *tower = talloc_p(mem_ctx, struct epm_tower); + + if (!(*tower)) { + return NT_STATUS_NO_MEMORY; + } + + /* Find transport */ + for (i=0;itransport) { + protseq = transports[i].protseq; + num_protocols = transports[i].num_protocols; + break; + } + } + + if (num_protocols == -1) { + DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport)); + return NT_STATUS_UNSUCCESSFUL; + } + + (*tower)->num_floors = 2 + num_protocols; + (*tower)->floors = talloc_array_p(mem_ctx, struct epm_floor, (*tower)->num_floors); + + /* Floor 0 */ + (*tower)->floors[0].lhs.protocol = EPM_PROTOCOL_UUID; + if (binding->object) { + (*tower)->floors[0].lhs.info.uuid.uuid = *binding->object; + } + (*tower)->floors[0].lhs.info.uuid.version = 0; + + /* Floor 1 */ + (*tower)->floors[1].lhs.protocol = EPM_PROTOCOL_UUID; + (*tower)->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION; + status = GUID_from_string(NDR_GUID, &(*tower)->floors[1].lhs.info.uuid.uuid); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + /* Floor 2 to num_protocols */ + for (i = 0; i < num_protocols; i++) { + (*tower)->floors[2 + i].lhs.protocol = protseq[i]; + } + + /* The top floor contains the endpoint */ + if (num_protocols >= 1 && binding->options && binding->options[0]) { + status = floor_set_rhs_data(mem_ctx, &(*tower)->floors[2 + num_protocols - 1], binding->options[0]); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + } + + /* The second-to-top floor contains the network address */ + if (num_protocols >= 2 && binding->host) { + status = floor_set_rhs_data(mem_ctx, &(*tower)->floors[2 + num_protocols - 2], binding->host); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + } + + return NT_STATUS_OK; +} + /* open a rpc connection to a rpc pipe on SMB using the binding structure to determine the endpoint and options */ @@ -722,7 +896,7 @@ NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key) { /* this took quite a few CPU cycles to find ... */ - session_key->data = discard_const_p(char, "SystemLibraryDTC"); + session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC"); session_key->length = 16; return NT_STATUS_OK; } diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 9967696c24..e64d041889 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -103,7 +103,8 @@ REQUIRED_SUBSYSTEMS = \ ADD_OBJ_FILES = \ torture/local/iconv.o \ torture/local/talloc.o \ - torture/local/messaging.o + torture/local/messaging.o \ + torture/local/binding_string.o REQUIRED_SUBSYSTEMS = \ LIBSMB \ MESSAGING diff --git a/source4/torture/local/binding_string.c b/source4/torture/local/binding_string.c new file mode 100644 index 0000000000..26fe67dd5c --- /dev/null +++ b/source4/torture/local/binding_string.c @@ -0,0 +1,81 @@ +/* + Unix SMB/CIFS implementation. + + local testing of RPC binding string parsing + + Copyright (C) Jelmer Vernooij 2004 + + 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" + +static BOOL test_BindingString(const char *binding) +{ + TALLOC_CTX *mem_ctx = talloc_init("test_BindingString"); + struct dcerpc_binding b; + const char *s; + struct epm_tower *tower; + NTSTATUS status; + + /* Parse */ + status = dcerpc_parse_binding(mem_ctx, binding, &b); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("Error parsing binding string '%s': %s\n", binding, nt_errstr(status))); + return False; + } + + s = dcerpc_binding_string(mem_ctx, &b); + if (!s) { + DEBUG(0, ("Error converting binding back to string for '%s'\n", binding)); + return False; + } + + if (strcasecmp(binding, s) != 0) { + DEBUG(0, ("Mismatch while comparing original and regenerated binding strings: '%s' <> '%s'\n", binding, s)); + return False; + } + + /* Generate protocol towers */ + status = dcerpc_binding_build_tower(mem_ctx, &b, &tower); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("Error generating protocol tower from '%s': %s\n", binding, nt_errstr(status))); + return False; + } + + /* FIXME: Convert back to binding and then back to string and compare */ + + return True; +} + +BOOL torture_local_binding_string(int dummy) +{ + BOOL ret = True; + + ret &= test_BindingString("ncacn_np:"); + ret &= test_BindingString("ncalrpc:"); + ret &= test_BindingString("ncalrpc:"); + ret &= test_BindingString("ncacn_np:[rpcecho]"); + ret &= test_BindingString("ncacn_np:127.0.0.1[rpcecho]"); + ret &= test_BindingString("ncacn_np:localhost[rpcecho]"); + ret &= test_BindingString("ncacn_np:[/pipe/rpcecho]"); + ret &= test_BindingString("ncacn_np:localhost[/pipe/rpcecho,sign,seal]"); + ret &= test_BindingString("ncacn_np:[,sign]"); + ret &= test_BindingString("ncadg_ip_udp:"); + ret &= test_BindingString("308FB580-1EB2-11CA-923B-08002B1075A7@ncacn_np:localhost"); + ret &= test_BindingString("308FB580-1EB2-11CA-923B-08002B1075A7@ncacn_ip_tcp:localhost"); + + return ret; +} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index 5992bfc633..cb639da653 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -3471,6 +3471,7 @@ static struct { {"LOCAL-ICONV", torture_local_iconv, 0}, {"LOCAL-TALLOC", torture_local_talloc, 0}, {"LOCAL-MESSAGING", torture_local_messaging, 0}, + {"LOCAL-BINDINGSTRING", torture_local_binding_string, 0}, /* ldap testers */ {"LDAP-BASIC", torture_ldap_basic, 0}, -- cgit