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);
signature.asc
Description: This is a digitally signed message part
_______________________________________________ devel mailing list [email protected] http://mailman.openchange.org/listinfo/devel
