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