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 b43e7e306344f24916db02273858ef5a10dbf463 Mon Sep 17 00:00:00 2001
From: Julien Kerihuel <[email protected]>
Date: Tue, 24 Aug 2010 14:33:56 +0200
Subject: [PATCH 77/77] 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      |   39 ++++++++++++++++++++++++++++----
 source4/librpc/rpc/dcerpc_util.c      |    1 +
 source4/librpc/tests/binding_string.c |    8 ++++++-
 8 files changed, 77 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 3300b6e..4acbac3 100644
--- a/source3/librpc/rpc/dcerpc.h
+++ b/source3/librpc/rpc/dcerpc.h
@@ -39,6 +39,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;
 };
@@ -93,6 +94,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..01b2ecc 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,35 @@ 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;
+	}
+	
+	addr = talloc_zero(mem_ctx, struct socket_address);
+	/* We don't provide a full socket_address, just the bits that we'll need */
+	addr->sockaddr = result->ai_addr;
+	addr->sockaddrlen = result->ai_addrlen;
+
+	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 +512,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 +589,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 +660,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.1

Index: libmapi/IMSProvider.c
===================================================================
--- libmapi/IMSProvider.c	(revision 2132)
+++ libmapi/IMSProvider.c	(working copy)
@@ -92,15 +92,20 @@
 	if (!global_mapi_ctx) return NULL;
 
 	binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s[", server);
+
 	/* If dump-data option is enabled */
 	if (global_mapi_ctx->dumpdata == true) {
 		binding = talloc_strdup_append(binding, "print,");
 	}
 	/* If seal option is enabled in the profile */
 	if (profile->seal == true) {
-		binding = talloc_strdup_append(binding, "seal");
+		binding = talloc_strdup_append(binding, "seal,");
 	}
-
+	/* If localaddress parameter is available in the profile */
+	if (profile->localaddr) {
+		binding = talloc_asprintf_append(binding, "localaddress=%s,", profile->localaddr);
+	}
+	
 	binding = talloc_strdup_append(binding, "]");
 
 	return binding;
Index: libmapi/mapi_profile.h
===================================================================
--- libmapi/mapi_profile.h	(revision 2132)
+++ libmapi/mapi_profile.h	(working copy)
@@ -46,6 +46,7 @@
 	const char     		*domain;
 	const char     		*realm;
 	const char     		*server;
+	const char		*localaddr;
 	bool			seal;
 	uint32_t		codepage;
 	uint32_t		language;
Index: libmapi/IProfAdmin.c
===================================================================
--- libmapi/IProfAdmin.c	(revision 2132)
+++ libmapi/IProfAdmin.c	(working copy)
@@ -73,6 +73,7 @@
 	profile->domain = ldb_msg_find_attr_as_string(msg, "domain", NULL);
 	profile->mailbox = ldb_msg_find_attr_as_string(msg, "EmailAddress", NULL);
 	profile->homemdb = ldb_msg_find_attr_as_string(msg, "HomeMDB", NULL);
+	profile->localaddr = ldb_msg_find_attr_as_string(msg, "localaddress", NULL);
 	profile->server = ldb_msg_find_attr_as_string(msg, "binding", NULL);
 	profile->seal = ldb_msg_find_attr_as_bool(msg, "seal", false);
 	profile->org = ldb_msg_find_attr_as_string(msg, "Organization", NULL);

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