Report binding in libnet failure message.
[samba.git] / source4 / libnet / libnet_rpc.c
index d4d187368b6a822ea5abc88b81c7c3559338a33d..50cc1145d2491290260a5766cafa02d4bb06fdf0 100644 (file)
@@ -6,7 +6,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #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;
+
+       /* information about the progress */
+       void (*monitor_fn)(struct monitor_msg*);
 };
 
 
@@ -47,38 +51,45 @@ static void continue_pipe_connect(struct composite_context *ctx);
 
 static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
                                                           TALLOC_CTX *mem_ctx,
-                                                          struct libnet_RpcConnect *r)
+                                                          struct libnet_RpcConnect *r,
+                                                          void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;    
        struct rpc_connect_srv_state *s;
+       struct dcerpc_binding *b;
        struct composite_context *pipe_connect_req;
 
        /* composite context allocation and setup */
-       c = talloc_zero(mem_ctx, struct composite_context);
-       if (c == NULL) return NULL;
+       c = composite_create(ctx, ctx->event_ctx);
+       if (c == NULL) return c;
 
        s = talloc_zero(c, struct rpc_connect_srv_state);
        if (composite_nomem(s, c)) return c;
 
-       c->state = COMPOSITE_STATE_IN_PROGRESS;
        c->private_data = s;
-       c->event_ctx = ctx->event_ctx;
+       s->monitor_fn   = monitor;
 
+       s->ctx = ctx;
        s->r = *r;
        ZERO_STRUCT(s->r.out);
 
        /* prepare binding string */
        switch (r->level) {
-       case LIBNET_RPC_CONNECT_DC:
-       case LIBNET_RPC_CONNECT_PDC:
        case LIBNET_RPC_CONNECT_SERVER:
                s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
                break;
+       case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
+               s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
+               break;
 
        case LIBNET_RPC_CONNECT_BINDING:
                s->binding = talloc_strdup(s, r->in.binding);
                break;
 
+       case LIBNET_RPC_CONNECT_DC:
+       case LIBNET_RPC_CONNECT_PDC:
+               /* this should never happen - DC and PDC level has a separate
+                  composite function */
        case LIBNET_RPC_CONNECT_DC_INFO:
                /* this should never happen - DC_INFO level has a separate
                   composite function */
@@ -86,10 +97,25 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context
                return c;
        }
 
+       /* parse binding string to the structure */
+       c->status = dcerpc_parse_binding(c, s->binding, &b);
+       if (!NT_STATUS_IS_OK(c->status)) {
+               DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
+               composite_error(c, c->status);
+               return c;
+       }
+
+       if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
+               b->target_hostname = talloc_reference(b, r->in.name);
+               if (composite_nomem(b->target_hostname, c)) {
+                       return c;
+               }
+       }
+
        /* connect to remote dcerpc pipe */
-       pipe_connect_req = dcerpc_pipe_connect_send(c, &s->r.out.dcerpc_pipe,
-                                                   s->binding, r->in.dcerpc_iface,
-                                                   ctx->cred, c->event_ctx);
+       pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
+                                                     ctx->cred, c->event_ctx,
+                                                     ctx->lp_ctx);
        if (composite_nomem(pipe_connect_req, c)) return c;
 
        composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
@@ -109,11 +135,27 @@ static void continue_pipe_connect(struct composite_context *ctx)
        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;
+       c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
+       
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               struct msg_net_rpc_connect data;
+               struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
+               
+               /* prepare monitor message and post it */
+               data.host        = binding->host;
+               data.endpoint    = binding->endpoint;
+               data.transport   = binding->transport;
+               data.domain_name = binding->target_hostname;
+               
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
 
-       s->r.out.error_string = NULL;
-       composite_done(c);
+       composite_done(c);      
 }
 
 
@@ -145,13 +187,17 @@ static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
                /* reference created pipe structure to long-term libnet_context
                   so that it can be used by other api functions even after short-term
                   mem_ctx is freed */
-               if (r->in.dcerpc_iface == &dcerpc_table_samr) {
-                       ctx->samr_pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
-               } else {
-                       ctx->pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+               if (r->in.dcerpc_iface == &ndr_table_samr) {
+                       ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+
+               } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
+                       ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
                }
+
+               r->out.error_string = talloc_strdup(mem_ctx, "Success");
+
        } else {
-               r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
+               r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
        }
 
        talloc_free(c);
@@ -165,6 +211,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 *);
 };
 
 
@@ -183,22 +232,22 @@ static void continue_rpc_connect(struct composite_context *ctx);
 
 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
                                                          TALLOC_CTX *mem_ctx,
-                                                         struct libnet_RpcConnect *r)
+                                                         struct libnet_RpcConnect *r,
+                                                         void (*monitor)(struct monitor_msg *msg))
 {
        struct composite_context *c;
        struct rpc_connect_dc_state *s;
        struct composite_context *lookup_dc_req;
 
        /* composite context allocation and setup */
-       c = talloc_zero(mem_ctx, struct composite_context);
-       if (c == NULL) return NULL;
+       c = composite_create(ctx, ctx->event_ctx);
+       if (c == NULL) return c;
 
        s = talloc_zero(c, struct rpc_connect_dc_state);
        if (composite_nomem(s, c)) return c;
 
-       c->state = COMPOSITE_STATE_IN_PROGRESS;
        c->private_data = s;
-       c->event_ctx = ctx->event_ctx;
+       s->monitor_fn   = monitor;
 
        s->ctx = ctx;
        s->r   = *r;
@@ -216,6 +265,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;
@@ -230,7 +280,7 @@ static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context
 
 
 /*
-  Step 2 of RpcConnectDC: get domain controller name/address and
+  Step 2 of RpcConnectDC: get domain controller name and
   initiate RpcConnect to it
 */
 static void continue_lookup_dc(struct composite_context *ctx)
@@ -238,6 +288,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);
@@ -246,23 +298,33 @@ 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) {
-               s->connect_name = s->f.out.dcs[0].name;
-       } else {
-               s->connect_name = s->f.out.dcs[0].address;
+       /* decide on preferred address type depending on DC type */
+       s->connect_name = s->f.out.dcs[0].name;
+
+       /* post monitor message */
+       if (s->monitor_fn) {
+               /* prepare a monitor message and post it */
+               data.domain_name = s->f.in.domain_name;
+               data.hostname    = s->f.out.dcs[0].name;
+               data.address     = s->f.out.dcs[0].address;
+               
+               msg.type         = mon_NetLookupDc;
+               msg.data         = &data;
+               msg.data_size    = sizeof(data);
+               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            = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
 
        /* this will cause yet another name resolution, but at least
         * we pass the right name down the stack now */
-       s->r2.in.name          = talloc_strdup(c, s->connect_name);
+       s->r2.in.name          = talloc_strdup(s, s->connect_name);
+       s->r2.in.address       = talloc_steal(s, s->f.out.dcs[0].address);
        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, s->monitor_fn);
        if (composite_nomem(rpc_connect_req, c)) return;
 
        composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
@@ -280,13 +342,30 @@ static void continue_rpc_connect(struct composite_context *ctx)
        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;
        if (!composite_is_ok(c)) return;
 
        s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
+       
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               struct msg_net_rpc_connect data;
+               struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
+
+               data.host        = binding->host;
+               data.endpoint    = binding->endpoint;
+               data.transport   = binding->transport;
+               data.domain_name = binding->target_hostname;
+               
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
 
        composite_done(c);
 }
@@ -319,13 +398,17 @@ static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
                /* reference created pipe structure to long-term libnet_context
                   so that it can be used by other api functions even after short-term
                   mem_ctx is freed */
-               if (r->in.dcerpc_iface == &dcerpc_table_samr) {
-                       ctx->samr_pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
-               } else {
-                       ctx->pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+               if (r->in.dcerpc_iface == &ndr_table_samr) {
+                       ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+
+               } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
+                       ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
                }
+
        } else {
-               r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
+               r->out.error_string = talloc_asprintf(mem_ctx,
+                                                     "Failed to rpc connect: %s",
+                                                     nt_errstr(status));
        }
 
        talloc_free(c);
@@ -347,6 +430,9 @@ struct rpc_connect_dci_state {
        struct lsa_QueryInfoPolicy lsa_query_info;
        struct dcerpc_binding *final_binding;
        struct dcerpc_pipe *final_pipe;
+
+       /* information about the progress */
+       void (*monitor_fn)(struct monitor_msg*);
 };
 
 
@@ -356,6 +442,7 @@ static void continue_lsa_query_info(struct rpc_request *req);
 static void continue_lsa_query_info2(struct rpc_request *req);
 static void continue_epm_map_binding(struct composite_context *ctx);
 static void continue_secondary_conn(struct composite_context *ctx);
+static void continue_epm_map_binding_send(struct composite_context *c);
 
 
 /**
@@ -370,21 +457,21 @@ static void continue_secondary_conn(struct composite_context *ctx);
 
 static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
                                                              TALLOC_CTX *mem_ctx,
-                                                             struct libnet_RpcConnect *r)
+                                                             struct libnet_RpcConnect *r,
+                                                             void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c, *conn_req;
        struct rpc_connect_dci_state *s;
 
        /* composite context allocation and setup */
-       c = talloc_zero(mem_ctx, struct composite_context);
-       if (c == NULL) return NULL;
+       c = composite_create(ctx, ctx->event_ctx);
+       if (c == NULL) return c;
 
        s = talloc_zero(c, struct rpc_connect_dci_state);
        if (composite_nomem(s, c)) return c;
 
-       c->state = COMPOSITE_STATE_IN_PROGRESS;
        c->private_data = s;
-       c->event_ctx = ctx->event_ctx;
+       s->monitor_fn   = monitor;
 
        s->ctx = ctx;
        s->r   = *r;
@@ -401,10 +488,10 @@ static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_cont
        }
 
        /* we need to query information on lsarpc interface first */
-       s->rpc_conn.in.dcerpc_iface    = &dcerpc_table_lsarpc;
+       s->rpc_conn.in.dcerpc_iface    = &ndr_table_lsarpc;
        
        /* request connection to the lsa pipe on the pdc */
-       conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn);
+       conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
        if (composite_nomem(c, conn_req)) return c;
 
        composite_continue(c, conn_req, continue_dci_rpc_connect, c);
@@ -431,8 +518,25 @@ static void continue_dci_rpc_connect(struct composite_context *ctx)
                return;
        }
 
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               struct msg_net_rpc_connect data;
+               struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
+
+               data.host        = binding->host;
+               data.endpoint    = binding->endpoint;
+               data.transport   = binding->transport;
+               data.domain_name = binding->target_hostname;
+
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
+
        /* prepare to open a policy handle on lsa pipe */
-       s->lsa_pipe = s->ctx->pipe;
+       s->lsa_pipe = s->ctx->lsa.pipe;
        
        s->qos.len                 = 0;
        s->qos.impersonation_level = 2;
@@ -465,7 +569,7 @@ static void continue_lsa_policy(struct rpc_request *req)
        struct rpc_connect_dci_state *s;
        struct rpc_request *query_info_req;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
+       c = talloc_get_type(req->async.private_data, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
        c->status = dcerpc_ndr_request_recv(req);
@@ -474,6 +578,31 @@ static void continue_lsa_policy(struct rpc_request *req)
                return;
        }
 
+       if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+               s->r.out.realm = NULL;
+               s->r.out.guid  = NULL;
+               s->r.out.domain_name = NULL;
+               s->r.out.domain_sid  = NULL;
+
+               /* Skip to the creating the actual connection, no info available on this transport */
+               continue_epm_map_binding_send(c);
+               return;
+
+       } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
+               composite_error(c, s->lsa_open_policy.out.result);
+               return;
+       }
+
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+
+               msg.type      = mon_LsaOpenPolicy;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
        /* query lsa info for dns domain name and guid */
        s->lsa_query_info2.in.handle = &s->lsa_handle;
        s->lsa_query_info2.in.level  = LSA_POLICY_INFO_DNS;
@@ -495,7 +624,7 @@ static void continue_lsa_query_info2(struct rpc_request *req)
        struct rpc_connect_dci_state *s;
        struct rpc_request *query_info_req;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
+       c = talloc_get_type(req->async.private_data, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
        c->status = dcerpc_ndr_request_recv(req);
@@ -517,6 +646,14 @@ static void continue_lsa_query_info2(struct rpc_request *req)
                        return;
                }
 
+               if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
+                       s->r.out.error_string = talloc_asprintf(c,
+                                                               "lsa_QueryInfoPolicy2 failed: %s",
+                                                               nt_errstr(s->lsa_query_info2.out.result));
+                       composite_error(c, s->lsa_query_info2.out.result);
+                       return;
+               }
+
                /* Copy the dns domain name and guid from the query result */
 
                /* this should actually be a conversion from lsa_StringLarge */
@@ -529,6 +666,16 @@ static void continue_lsa_query_info2(struct rpc_request *req)
                *s->r.out.guid = s->lsa_query_info2.out.info->dns.domain_guid;
        }
 
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_LsaQueryPolicy;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
        /* query lsa info for domain name and sid */
        s->lsa_query_info.in.handle = &s->lsa_handle;
        s->lsa_query_info.in.level  = LSA_POLICY_INFO_DOMAIN;
@@ -541,15 +688,14 @@ static void continue_lsa_query_info2(struct rpc_request *req)
 
 
 /*
-  Step 5 of RpcConnectDCInfo: Get domain name and sid and request endpoint
-  map binding
+  Step 5 of RpcConnectDCInfo: Get domain name and sid
 */
 static void continue_lsa_query_info(struct rpc_request *req)
 {
-       struct composite_context *c, *epm_map_req;
+       struct composite_context *c;
        struct rpc_connect_dci_state *s;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
+       c = talloc_get_type(req->async.private_data, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
        c->status = dcerpc_ndr_request_recv(req);
@@ -561,10 +707,34 @@ static void continue_lsa_query_info(struct rpc_request *req)
                return;
        }
 
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_LsaQueryPolicy;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
        /* Copy the domain name and sid from the query result */
        s->r.out.domain_sid  = s->lsa_query_info.out.info->domain.sid;
        s->r.out.domain_name = s->lsa_query_info.out.info->domain.name.string;
 
+       continue_epm_map_binding_send(c);
+}
+
+/* 
+   Step 5 (continued) of RpcConnectDCInfo: request endpoint
+   map binding.
+
+   We may short-cut to this step if we don't support LSA OpenPolicy on this transport
+*/
+static void continue_epm_map_binding_send(struct composite_context *c)
+{
+       struct rpc_connect_dci_state *s;
+       struct composite_context *epm_map_req;
+       s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
        /* prepare to get endpoint mapping for the requested interface */
        s->final_binding = talloc(s, struct dcerpc_binding);
@@ -572,16 +742,15 @@ static void continue_lsa_query_info(struct rpc_request *req)
        
        *s->final_binding = *s->lsa_pipe->binding;
        /* Ensure we keep hold of the member elements */
-       talloc_reference(s->final_binding, s->lsa_pipe->binding);
+       if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
 
        epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
-                                                 s->lsa_pipe->conn->event_ctx);
+                                                 s->lsa_pipe->conn->event_ctx, s->ctx->lp_ctx);
        if (composite_nomem(epm_map_req, c)) return;
 
        composite_continue(c, epm_map_req, continue_epm_map_binding, c);
 }
 
-
 /*
   Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
   rpc connection derived from already used pipe but connected to the requested
@@ -613,7 +782,7 @@ static void continue_epm_map_binding(struct composite_context *ctx)
 
 
 /*
-  Step 7 of RpcConnectDCInfo: Get actual lsa pipe to be returned
+  Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
   and complete this composite call
 */
 static void continue_secondary_conn(struct composite_context *ctx)
@@ -635,6 +804,25 @@ static void continue_secondary_conn(struct composite_context *ctx)
        }
 
        s->r.out.dcerpc_pipe = s->final_pipe;
+
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               struct msg_net_rpc_connect data;
+               struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
+               
+               /* prepare monitor message and post it */
+               data.host        = binding->host;
+               data.endpoint    = binding->endpoint;
+               data.transport   = binding->transport;
+               data.domain_name = binding->target_hostname;
+               
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
+
        composite_done(c);
 }
 
@@ -669,13 +857,22 @@ static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct
                /* reference created pipe structure to long-term libnet_context
                   so that it can be used by other api functions even after short-term
                   mem_ctx is freed */
-               if (r->in.dcerpc_iface == &dcerpc_table_samr) {
-                       ctx->samr_pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
-               } else {
-                       ctx->pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+               if (r->in.dcerpc_iface == &ndr_table_samr) {
+                       ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+
+               } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
+                       ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
                }
+
        } else {
-               r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
+               if (s->r.out.error_string) {
+                       r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
+               } else if (r->in.binding == NULL) {
+                       r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
+               } else {
+                       r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s", 
+                                                             r->in.binding, nt_errstr(status));
+               }
        }
 
        talloc_free(c);
@@ -695,23 +892,25 @@ static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct
 
 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
                                                 TALLOC_CTX *mem_ctx,
-                                                struct libnet_RpcConnect *r)
+                                                struct libnet_RpcConnect *r,
+                                                void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
 
        switch (r->level) {
        case LIBNET_RPC_CONNECT_SERVER:
+       case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
        case LIBNET_RPC_CONNECT_BINDING:
-               c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r);
+               c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
                break;
 
        case LIBNET_RPC_CONNECT_PDC:
        case LIBNET_RPC_CONNECT_DC:
-               c = libnet_RpcConnectDC_send(ctx, mem_ctx, r);
+               c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
                break;
 
        case LIBNET_RPC_CONNECT_DC_INFO:
-               c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r);
+               c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
                break;
 
        default:
@@ -769,6 +968,6 @@ NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
 {
        struct composite_context *c;
        
-       c = libnet_RpcConnect_send(ctx, mem_ctx, r);
+       c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
        return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
 }