Hi Lists,

You will find in attachment an updated version of the patch which fixes
memory leaks introduced in the initial patch within the
convert_address_string function.

Cheers,
Julien.

On Tue, 2010-08-24 at 15:13 +0200, Julien Kerihuel wrote:
> Hi Lists,
> 
> The attached patch (initially proposed by Brad Hards) adds a
> localaddress ncacn option to DCERPC binding string and allow clients to
> specify on which interface they have to bind to communicate with remote
> host.
> 
> I have reworked the patch so localaddress becomes a member of the
> ncacn_options array and have its own defined flag (1<<22). The patch
> also alters EPM connections to use the correct interface.
> 
> Typical usage:
> ncacn_ip_tcp:192.168.102.236[print,seal,localaddress=192.168.0.142]
> 
> Given that we have a local interface with IP 192.168.0.142 and another
> one using 192.168.0.140, EPM and DCERPC connections will go through
> 192.168.0.142.
> 
> Also attached the openchange patch (for openchange developers) to test
> it prior to any trunk merge. To test the openchange patch, apply it to
> trunk, edit the OpenChange profile database and add the localaddress
> attribute followed by a local interface IP address, similarly to:
> 
> localaddress: 192.168.0.142
> 
> If no localaddress parameter is defined, then Samba4 DCERPC stack
> fallback to the default behavior (guess the best interface).
> 
> Cheers,
> Julien.
> 

-- 
Julien Kerihuel
[email protected]
OpenChange Project Manager

GPG Fingerprint: 0B55 783D A781 6329 108A  B609 7EF6 FE11 A35F 1F79

From bc4c912d677205d7e344d2c46b27491b73927137 Mon Sep 17 00:00:00 2001
From: Julien Kerihuel <[email protected]>
Date: Fri, 27 Aug 2010 14:04:07 +0200
Subject: [PATCH] Add unique IP address binding for client connections (EPM and ncacn_ip_tcp levels)

---
 librpc/rpc/binding.c                  |   26 +++++++++++++++++--
 source3/librpc/rpc/dcerpc.h           |    4 +++
 source4/librpc/rpc/dcerpc.h           |    4 +++
 source4/librpc/rpc/dcerpc_connect.c   |    4 ++-
 source4/librpc/rpc/dcerpc_secondary.c |    1 +
 source4/librpc/rpc/dcerpc_sock.c      |   43 +++++++++++++++++++++++++++++----
 source4/librpc/rpc/dcerpc_util.c      |    1 +
 source4/librpc/tests/binding_string.c |    8 +++++-
 8 files changed, 81 insertions(+), 10 deletions(-)

diff --git a/librpc/rpc/binding.c b/librpc/rpc/binding.c
index 5e9bef8..5c150e1 100644
--- a/librpc/rpc/binding.c
+++ b/librpc/rpc/binding.c
@@ -70,6 +70,8 @@ static const struct {
 	},
 };
 
+#define	LOCALADDRESS	"localaddress"
+
 static const struct {
 	const char *name;
 	uint32_t flag;
@@ -86,7 +88,8 @@ static const struct {
 	{"bigendian", DCERPC_PUSH_BIGENDIAN},
 	{"smb2", DCERPC_SMB2},
 	{"hdrsign", DCERPC_HEADER_SIGNING},
-	{"ndr64", DCERPC_NDR64}
+	{"ndr64", DCERPC_NDR64},
+	{LOCALADDRESS, DCERPC_LOCALADDRESS}
 };
 
 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
@@ -220,7 +223,12 @@ _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_bi
 
 	for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
 		if (b->flags & ncacn_options[i].flag) {
-			s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
+			if (!strcmp(ncacn_options[i].name, LOCALADDRESS) && b->localaddress) {
+				s = talloc_asprintf_append_buffer(s, ",%s=%s", ncacn_options[i].name,
+								  b->localaddress);
+			} else {
+				s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
+			}
 			if (!s) return NULL;
 		}
 	}
@@ -313,6 +321,7 @@ _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struc
 	b->flags = 0;
 	b->assoc_group_id = 0;
 	b->endpoint = NULL;
+	b->localaddress = NULL;
 
 	if (!options) {
 		*b_out = b;
@@ -339,8 +348,19 @@ _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struc
 	/* some options are pre-parsed for convenience */
 	for (i=0;b->options[i];i++) {
 		for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
-			if (strcasecmp(ncacn_options[j].name, b->options[i]) == 0) {
+			if (strncasecmp(ncacn_options[j].name, b->options[i], 
+					strlen(ncacn_options[j].name)) == 0) {
 				int k;
+
+				if (!strcmp(ncacn_options[j].name, LOCALADDRESS)) {
+					p = strchr(b->options[i], '=');
+					if (!p) {
+						return NT_STATUS_INVALID_PARAMETER;
+					}
+					p++; /* skip over = sign */
+					b->localaddress = talloc_strdup(b, p);
+				}
+
 				b->flags |= ncacn_options[j].flag;
 				for (k=i;b->options[k];k++) {
 					b->options[k] = b->options[k+1];
diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h
index d064f3d..558189c 100644
--- a/source3/librpc/rpc/dcerpc.h
+++ b/source3/librpc/rpc/dcerpc.h
@@ -41,6 +41,7 @@ struct dcerpc_binding {
 	const char *target_hostname;
 	const char *endpoint;
 	const char **options;
+	const char *localaddress;
 	uint32_t flags;
 	uint32_t assoc_group_id;
 };
@@ -95,6 +96,9 @@ struct dcerpc_binding {
 /* use NDR64 transport */
 #define DCERPC_NDR64                   (1<<21)
 
+/* specify binding interface */
+#define	DCERPC_LOCALADDRESS            (1<<22)
+
 /* The following definitions come from librpc/rpc/binding.c  */
 
 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor);
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 9ff2c1b..706648c 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -181,6 +181,9 @@ struct dcerpc_pipe {
 /* use NDR64 transport */
 #define DCERPC_NDR64                   (1<<21)
 
+/* specify binding interface */
+#define	DCERPC_LOCALADDRESS            (1<<22)
+
 /* this describes a binding to a particular transport/pipe */
 struct dcerpc_binding {
 	enum dcerpc_transport_t transport;
@@ -189,6 +192,7 @@ struct dcerpc_binding {
 	const char *target_hostname;
 	const char *endpoint;
 	const char **options;
+	const char *localaddress;
 	uint32_t flags;
 	uint32_t assoc_group_id;
 };
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index 7779d31..23c990c 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -276,6 +276,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb2_recv(struct composite_context
 
 struct pipe_ip_tcp_state {
 	struct dcerpc_pipe_connect io;
+	const char *localaddr;
 	const char *host;
 	const char *target_hostname;
 	uint32_t port;
@@ -319,13 +320,14 @@ static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CT
 
 	/* store input parameters in state structure */
 	s->io               = *io;
+	s->localaddr        = talloc_reference(c, io->binding->localaddress);
 	s->host             = talloc_reference(c, io->binding->host);
 	s->target_hostname  = talloc_reference(c, io->binding->target_hostname);
                              /* port number is a binding endpoint here */
 	s->port             = atoi(io->binding->endpoint);   
 
 	/* send pipe open request on tcp/ip */
-	pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->host, s->target_hostname, 
+	pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->localaddr, s->host, s->target_hostname, 
 					     s->port, io->resolve_ctx);
 	composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
 	return c;
diff --git a/source4/librpc/rpc/dcerpc_secondary.c b/source4/librpc/rpc/dcerpc_secondary.c
index 5f355a5..65466e4 100644
--- a/source4/librpc/rpc/dcerpc_secondary.c
+++ b/source4/librpc/rpc/dcerpc_secondary.c
@@ -102,6 +102,7 @@ _PUBLIC_ struct composite_context* dcerpc_secondary_connection_send(struct dcerp
 		}
 
 		pipe_tcp_req = dcerpc_pipe_open_tcp_send(s->pipe2->conn,
+							 s->binding->localaddress,
 							 s->peer_addr->addr,
 							 s->binding->target_hostname,
 							 atoi(s->binding->endpoint),
diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c
index d8bd6d2..b39ace2 100644
--- a/source4/librpc/rpc/dcerpc_sock.c
+++ b/source4/librpc/rpc/dcerpc_sock.c
@@ -228,6 +228,7 @@ struct pipe_open_socket_state {
 	struct dcerpc_connection *conn;
 	struct socket_context *socket_ctx;
 	struct sock_private *sock;
+	struct socket_address *localaddr;
 	struct socket_address *server;
 	const char *target_hostname;
 	enum dcerpc_transport_t transport;
@@ -305,6 +306,7 @@ static void continue_socket_connect(struct composite_context *ctx)
 
 static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ctx,
 						       struct dcerpc_connection *cn,
+						       struct socket_address *localaddr,
 						       struct socket_address *server,
 						       const char *target_hostname,
 						       const char *full_path,
@@ -323,6 +325,8 @@ static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ct
 
 	s->conn      = cn;
 	s->transport = transport;
+	s->localaddr = talloc_reference(c, localaddr);
+	if (composite_nomem(s->localaddr, c)) return c;
 	s->server    = talloc_reference(c, server);
 	if (composite_nomem(s->server, c)) return c;
 	s->target_hostname = talloc_reference(s, target_hostname);
@@ -337,7 +341,7 @@ static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ct
 
 	s->sock->path = talloc_reference(s->sock, full_path);
 
-	conn_req = socket_connect_send(s->socket_ctx, NULL, s->server, 0, 
+	conn_req = socket_connect_send(s->socket_ctx, s->localaddr, s->server, 0, 
 				       c->event_ctx);
 	composite_continue(c, conn_req, continue_socket_connect, c);
 	return c;
@@ -357,6 +361,7 @@ struct pipe_tcp_state {
 	const char *target_hostname;
 	const char *address;
 	uint32_t port;
+	struct socket_address *localaddr;
 	struct socket_address *srvaddr;
 	struct resolve_context *resolve_ctx;
 	struct dcerpc_connection *conn;
@@ -385,7 +390,7 @@ static void continue_ip_resolve_name(struct composite_context *ctx)
 	if (composite_nomem(s->srvaddr, c)) return;
 
 	/* resolve_nbt_name gives only ipv4 ... - send socket open request */
-	sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn,
+	sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, s->localaddr,
 						     s->srvaddr, s->target_hostname,
 						     NULL,
 						     NCACN_IP_TCP);
@@ -419,7 +424,7 @@ static void continue_ipv6_open_socket(struct composite_context *ctx)
 	if (composite_nomem(s->srvaddr, c)) return;
 
 	/* try IPv4 if IPv6 fails */
-	sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, 
+	sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, s->localaddr,
 						     s->srvaddr, s->target_hostname, 
 						     NCACN_IP_TCP);
 	composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
@@ -452,12 +457,39 @@ static void continue_ipv4_open_socket(struct composite_context *ctx)
 	composite_done(c);
 }
 
+static struct socket_address *convert_address_string(TALLOC_CTX *mem_ctx, 
+						     const char *localaddr)
+{
+	struct socket_address	*addr;
+	struct addrinfo		*result = NULL;
+	int			ret;
+
+	if (!localaddr) {
+		localaddr = "0.0.0.0";
+	}
+	ret = getaddrinfo(localaddr, "0", NULL, &result);
+	if (ret != 0) {
+		return NULL;
+	}
+	
+	/* We don't provide a full socket_address, just the bits that we'll need */
+	addr = talloc_zero(mem_ctx, struct socket_address);
+	addr->sockaddr = talloc_zero(addr, struct sockaddr);
+	addr->sockaddr->sa_family = result->ai_addr->sa_family;
+	memcpy(addr->sockaddr->sa_data, result->ai_addr->sa_data, sizeof (addr->sockaddr->sa_data));
+	addr->sockaddrlen = result->ai_addrlen;
+
+	freeaddrinfo(result);
+
+	return addr;
+}
 
 /*
   Send rpc pipe open request to given host:port using
   tcp/ip transport
 */
 struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *conn,
+						    const char *localaddr,
 						    const char *server,
 						    const char *target_hostname,
 						    uint32_t port,
@@ -484,6 +516,7 @@ struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *co
 		if (composite_nomem(s->target_hostname, c)) return c;
 	}
 	s->port            = port;
+	s->localaddr       = convert_address_string(c, localaddr);
 	s->conn            = conn;
 	s->resolve_ctx     = resolve_ctx;
 
@@ -560,7 +593,7 @@ struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcerpc_connec
 	if (composite_nomem(s->srvaddr, c)) return c;
 
 	/* send socket open request */
-	sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, 
+	sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, NULL,
 						     s->srvaddr, NULL,
 						     s->path,
 						     NCALRPC);
@@ -631,7 +664,7 @@ struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *c
 	if (composite_nomem(s->srvaddr, c)) return c;
 
 	/* send socket open request */
-	sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NULL, s->path, NCALRPC);
+	sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, NULL, s->srvaddr, NULL, s->path, NCALRPC);
 	composite_continue(c, sock_np_req, continue_np_open_socket, c);
 	return c;
 }
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index ffe8506..d27b0f3 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -285,6 +285,7 @@ struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
 	epmapper_binding->host			= talloc_reference(epmapper_binding, binding->host);
 	epmapper_binding->target_hostname       = epmapper_binding->host;
 	epmapper_binding->options		= NULL;
+	epmapper_binding->localaddress          = talloc_reference(epmapper_binding, binding->localaddress);
 	epmapper_binding->flags			= 0;
 	epmapper_binding->assoc_group_id	= 0;
 	epmapper_binding->endpoint		= NULL;
diff --git a/source4/librpc/tests/binding_string.c b/source4/librpc/tests/binding_string.c
index 6de94eb..cff4f2a 100644
--- a/source4/librpc/tests/binding_string.c
+++ b/source4/librpc/tests/binding_string.c
@@ -128,7 +128,13 @@ static bool test_parse_check_results(struct torture_context *tctx)
 	torture_assert_int_equal(tctx, b->object.if_version, 0, "object version");
 	torture_assert_ntstatus_ok(tctx, dcerpc_parse_binding(tctx, 
 		"308fb580-1eb2-11ca-923b-08002b107...@ncacn_ip_tcp:$SERVER", &b), "parse");
-
+	torture_assert_ntstatus_ok(tctx, dcerpc_parse_binding(tctx, "ncacn_ip_tcp:$SERVER[,sign,localaddress=192.168.1.1]", &b), "parse");
+	torture_assert(tctx, b->transport == NCACN_IP_TCP, "ncacn_ip_tcp expected");
+	torture_assert(tctx, b->flags == DCERPC_SIGN, "sign flag");
+	torture_assert_str_equal(tctx, b->localaddress, "192.168.1.1", "localaddress");
+	torture_assert_str_equal(tctx, "ncacn_ip_tcp:$SERVER[,sign,localaddress=192.168.1.1]",
+				 dcerpc_binding_string(tctx, b), "back to string");
+	
 	return true;
 }
 
-- 
1.7.2.2

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
devel mailing list
[email protected]
http://mailman.openchange.org/listinfo/devel

Reply via email to