From 434087bb4baa14df503690cc05dc418b96fabe53 Mon Sep 17 00:00:00 2001 From: Rafal Szczesniak Date: Thu, 13 Jul 2006 22:13:47 +0000 Subject: r17026: Make rpc connect routine a bit smarter. Try to connect again using different transport and possibly address type, when the first attempt fails (only if it makes any sense, of course). This may be especially useful when connecting DCs and PDCs in mixed environments. Also, add monitor messages issuing. rafal (This used to be commit d69b31230dd01efadd9c0cc6ef31c794c6165881) --- source4/libnet/libnet_rpc.c | 93 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) (limited to 'source4') diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index fce7811138..31d2b4dbf4 100644 --- a/source4/libnet/libnet_rpc.c +++ b/source4/libnet/libnet_rpc.c @@ -23,13 +23,16 @@ #include "libnet/libnet.h" #include "libcli/libcli.h" #include "libcli/composite/composite.h" +#include "librpc/rpc/dcerpc.h" #include "librpc/gen_ndr/ndr_lsa_c.h" #include "librpc/gen_ndr/ndr_samr.h" struct rpc_connect_srv_state { + struct libnet_context *ctx; struct libnet_RpcConnect r; const char *binding; + enum dcerpc_transport_t trans; }; @@ -64,15 +67,21 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context c->private_data = s; c->event_ctx = ctx->event_ctx; + s->ctx = ctx; s->r = *r; ZERO_STRUCT(s->r.out); /* prepare binding string */ switch (r->level) { case LIBNET_RPC_CONNECT_DC: + s->binding = talloc_asprintf(s, "ncacn_ip_tcp:%s", r->in.name); + s->trans = NCACN_IP_TCP; + break; + case LIBNET_RPC_CONNECT_PDC: case LIBNET_RPC_CONNECT_SERVER: s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name); + s->trans = NCACN_NP; break; case LIBNET_RPC_CONNECT_BINDING: @@ -104,13 +113,45 @@ static void continue_pipe_connect(struct composite_context *ctx) { struct composite_context *c; struct rpc_connect_srv_state *s; + struct composite_context *pipe_connect_req; c = talloc_get_type(ctx->async.private_data, struct composite_context); s = talloc_get_type(c->private_data, struct rpc_connect_srv_state); /* receive result of rpc pipe connection */ c->status = dcerpc_pipe_connect_recv(ctx, c, &s->r.out.dcerpc_pipe); - if (!composite_is_ok(c)) return; + + if (NT_STATUS_EQUAL(c->status, NT_STATUS_IO_TIMEOUT)) { + switch (s->r.level) { + case LIBNET_RPC_CONNECT_DC: + if (s->trans == NCACN_IP_TCP) { + s->binding = talloc_asprintf(s, "ncacn_np:%s", s->r.in.name); + s->trans = NCACN_NP; + } + break; + + case LIBNET_RPC_CONNECT_SERVER: + if (s->trans == NCACN_NP) { + s->binding = talloc_asprintf(s, "ncacn_ip_tcp:%s", s->r.in.name); + s->trans = NCACN_IP_TCP; + } + break; + + default: + if (!composite_is_ok(c)) return; + s->r.out.error_string = NULL; + composite_done(c); + } + + /* connect to remote dcerpc pipe */ + pipe_connect_req = dcerpc_pipe_connect_send(c, &s->r.out.dcerpc_pipe, + s->binding, s->r.in.dcerpc_iface, + s->ctx->cred, c->event_ctx); + if (composite_nomem(pipe_connect_req, c)) return; + + composite_continue(c, pipe_connect_req, continue_pipe_connect, c); + return; + } s->r.out.error_string = NULL; composite_done(c); @@ -166,6 +207,9 @@ struct rpc_connect_dc_state { struct libnet_RpcConnect r2; struct libnet_LookupDCs f; const char *connect_name; + + /* information about the progress */ + void (*monitor_fn)(struct monitor_msg *); }; @@ -217,6 +261,7 @@ static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context default: break; } + s->f.in.domain_name = r->in.name; s->f.out.num_dcs = 0; s->f.out.dcs = NULL; @@ -239,6 +284,8 @@ static void continue_lookup_dc(struct composite_context *ctx) struct composite_context *c; struct rpc_connect_dc_state *s; struct composite_context *rpc_connect_req; + struct monitor_msg msg; + struct msg_net_lookup_dc data; c = talloc_get_type(ctx->async.private_data, struct composite_context); s = talloc_get_type(c->private_data, struct rpc_connect_dc_state); @@ -247,15 +294,34 @@ static void continue_lookup_dc(struct composite_context *ctx) c->status = libnet_LookupDCs_recv(ctx, c, &s->f); if (!composite_is_ok(c)) return; - /* we might not have got back a name. Fall back to the IP */ - if (s->f.out.dcs[0].name) { + /* decide on preferred address type depending on DC type */ + switch (s->r.level) { + case LIBNET_RPC_CONNECT_PDC: s->connect_name = s->f.out.dcs[0].name; - } else { + break; + + case LIBNET_RPC_CONNECT_DC: s->connect_name = s->f.out.dcs[0].address; + break; + + default: + /* we shouldn't absolutely get here */ + composite_error(c, NT_STATUS_INVALID_LEVEL); } + /* prepare a monitor message and post it */ + msg.type = net_lookup_dc; + msg.data = &data; + msg.data_size = sizeof(data); + + data.domain_name = s->f.in.domain_name; + data.hostname = s->f.out.dcs[0].name; + data.address = s->f.out.dcs[0].address; + + if (s->monitor_fn) s->monitor_fn(&msg); + /* ok, pdc has been found so do attempt to rpc connect */ - s->r2.level = LIBNET_RPC_CONNECT_SERVER; + s->r2.level = s->r.level; /* this will cause yet another name resolution, but at least * we pass the right name down the stack now */ @@ -263,7 +329,7 @@ static void continue_lookup_dc(struct composite_context *ctx) s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface; /* send rpc connect request to the server */ - rpc_connect_req = libnet_RpcConnect_send(s->ctx, c, &s->r2); + rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2); if (composite_nomem(rpc_connect_req, c)) return; composite_continue(c, rpc_connect_req, continue_rpc_connect, c); @@ -277,11 +343,13 @@ static void continue_rpc_connect(struct composite_context *ctx) { struct composite_context *c; struct rpc_connect_dc_state *s; + struct monitor_msg msg; + struct msg_net_pipe_connected data; c = talloc_get_type(ctx->async.private_data, struct composite_context); s = talloc_get_type(c->private_data, struct rpc_connect_dc_state); - c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->r2); + c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2); /* error string is to be passed anyway */ s->r.out.error_string = s->r2.out.error_string; @@ -289,6 +357,17 @@ static void continue_rpc_connect(struct composite_context *ctx) s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe; + /* prepare a monitor message and post it */ + msg.type = net_pipe_connected; + msg.data = NULL; + msg.data_size = 0; + + data.host = s->r.out.dcerpc_pipe->binding->host; + data.endpoint = s->r.out.dcerpc_pipe->binding->endpoint; + data.transport = s->r.out.dcerpc_pipe->binding->transport; + + if (s->monitor_fn) s->monitor_fn(&msg); + composite_done(c); } -- cgit