HACK b/source4/libnet/libnet_rpc.c if (1 || NT_STATUS_EQUAL(s->lsa_open_policy.out...
[metze/samba/wip.git] / source4 / libnet / libnet_rpc.c
index 04e91097b546fe9daaa0d517c2836d45ced9177b..9494a3d3b947d272f061e02ab4d87efce6f1ec2a 100644 (file)
 #include "libnet/libnet.h"
 #include "libcli/libcli.h"
 #include "libcli/composite/composite.h"
-#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_proto.h"
 #include "librpc/gen_ndr/ndr_lsa_c.h"
 #include "librpc/gen_ndr/ndr_samr.h"
-
+#include "auth/credentials/credentials.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*);
 };
 
 
@@ -48,7 +51,8 @@ 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;
@@ -63,6 +67,7 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context
        if (composite_nomem(s, c)) return c;
 
        c->private_data = s;
+       s->monitor_fn   = monitor;
 
        s->ctx = ctx;
        s->r = *r;
@@ -74,7 +79,8 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context
                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);
+               s->binding = talloc_asprintf(s, "ncacn_np:%s[target_hostname=%s]",
+                                            r->in.address, r->in.name);
                break;
 
        case LIBNET_RPC_CONNECT_BINDING:
@@ -100,16 +106,26 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context
                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;
-               }
+       switch (r->level) {
+       case LIBNET_RPC_CONNECT_SERVER:
+       case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
+               c->status = dcerpc_binding_set_flags(b, r->in.dcerpc_flags, 0);
+               if (!composite_is_ok(c)) return c;
+               break;
+       default:
+               /* other types have already been checked before */
+               break;
+       }
+
+       if (DEBUGLEVEL >= 10) {
+               c->status = dcerpc_binding_set_flags(b, DCERPC_DEBUG_PRINT_BOTH, 0);
+               if (!composite_is_ok(c)) return c;
        }
 
        /* connect to remote dcerpc pipe */
        pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
-                                                     ctx->cred, c->event_ctx);
+                                                     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);
@@ -130,8 +146,26 @@ static void continue_pipe_connect(struct composite_context *ctx)
 
        /* receive result of rpc pipe connection */
        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;
+               const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
+
+               /* prepare monitor message and post it */
+               data.host        = dcerpc_binding_get_string_option(b, "host");
+               data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
+               data.transport   = dcerpc_binding_get_transport(b);
+               data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
+
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
 
-       composite_done(c);
+       composite_done(c);      
 }
 
 
@@ -151,11 +185,11 @@ static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
                                          struct libnet_RpcConnect *r)
 {
        NTSTATUS status;
-       struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
-                                         struct rpc_connect_srv_state);
 
        status = composite_wait(c);
        if (NT_STATUS_IS_OK(status)) {
+               struct rpc_connect_srv_state *s;
+
                /* move the returned rpc pipe between memory contexts */
                s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
                r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
@@ -163,11 +197,13 @@ 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) {
+               if (r->in.dcerpc_iface == &ndr_table_samr) {
                        ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+                       ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
 
-               } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
+               } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
                        ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+                       ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
                }
 
                r->out.error_string = talloc_strdup(mem_ctx, "Success");
@@ -193,7 +229,7 @@ struct rpc_connect_dc_state {
 };
 
 
-static void continue_lookup_dc(struct composite_context *ctx);
+static void continue_lookup_dc(struct tevent_req *req);
 static void continue_rpc_connect(struct composite_context *ctx);
 
 
@@ -208,11 +244,12 @@ 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;
+       struct tevent_req *lookup_dc_req;
 
        /* composite context allocation and setup */
        c = composite_create(ctx, ctx->event_ctx);
@@ -222,6 +259,7 @@ static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context
        if (composite_nomem(s, c)) return c;
 
        c->private_data = s;
+       s->monitor_fn   = monitor;
 
        s->ctx = ctx;
        s->r   = *r;
@@ -248,7 +286,7 @@ static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context
        lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
        if (composite_nomem(lookup_dc_req, c)) return c;
 
-       composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
+       tevent_req_set_callback(lookup_dc_req, continue_lookup_dc, c);
        return c;
 }
 
@@ -257,34 +295,36 @@ static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context
   Step 2 of RpcConnectDC: get domain controller name and
   initiate RpcConnect to it
 */
-static void continue_lookup_dc(struct composite_context *ctx)
+static void continue_lookup_dc(struct tevent_req *req)
 {
        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);
+
+       c = tevent_req_callback_data(req, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct rpc_connect_dc_state);
        
        /* receive result of domain controller lookup */
-       c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
+       c->status = libnet_LookupDCs_recv(req, c, &s->f);
        if (!composite_is_ok(c)) return;
 
        /* decide on preferred address type depending on DC type */
        s->connect_name = s->f.out.dcs[0].name;
 
-       /* 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);
+       /* 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_ADDRESS;
@@ -294,9 +334,10 @@ static void continue_lookup_dc(struct composite_context *ctx)
        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;  
+       s->r2.in.dcerpc_flags  = s->r.in.dcerpc_flags;
 
        /* send rpc connect request to the server */
-       rpc_connect_req = libnet_RpcConnectSrv_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);
@@ -310,8 +351,6 @@ 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);
@@ -323,17 +362,23 @@ static void continue_rpc_connect(struct composite_context *ctx)
        if (!composite_is_ok(c)) return;
 
        s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
-
-       /* prepare a monitor message and post it */
-       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;
-
-       msg.type       = net_pipe_connected;
-       msg.data       = (void*)&data;
-       msg.data_size  = sizeof(data);
        
-       if (s->monitor_fn) s->monitor_fn(&msg);
+       /* post monitor message */
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               struct msg_net_rpc_connect data;
+               const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
+
+               data.host        = dcerpc_binding_get_string_option(b, "host");
+               data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
+               data.transport   = dcerpc_binding_get_transport(b);
+               data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
+
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
 
        composite_done(c);
 }
@@ -360,17 +405,27 @@ static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
 
        status = composite_wait(c);
        if (NT_STATUS_IS_OK(status)) {
-               /* move connected rpc pipe between memory contexts */
-               r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
+               /* move connected rpc pipe between memory contexts 
+                  
+                  The use of talloc_reparent(talloc_parent(), ...) is
+                  bizarre, but it is needed because of the absolutely
+                  atrocious use of talloc in this code. We need to
+                  force the original parent to change, but finding
+                  the original parent is well nigh impossible at this
+                  point in the code (yes, I tried).
+                */
+               r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe), 
+                                                    mem_ctx, s->r.out.dcerpc_pipe);
 
                /* 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) {
+               if (r->in.dcerpc_iface == &ndr_table_samr) {
                        ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
-
-               } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
+                       ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
+               } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
                        ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+                       ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
                }
 
        } else {
@@ -398,13 +453,16 @@ 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*);
 };
 
 
 static void continue_dci_rpc_connect(struct composite_context *ctx);
-static void continue_lsa_policy(struct rpc_request *req);
-static void continue_lsa_query_info(struct rpc_request *req);
-static void continue_lsa_query_info2(struct rpc_request *req);
+static void continue_lsa_policy(struct tevent_req *subreq);
+static void continue_lsa_query_info(struct tevent_req *subreq);
+static void continue_lsa_query_info2(struct tevent_req *subreq);
 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);
@@ -422,7 +480,8 @@ static void continue_epm_map_binding_send(struct composite_context *c);
 
 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;
@@ -435,26 +494,31 @@ static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_cont
        if (composite_nomem(s, c)) return c;
 
        c->private_data = s;
+       s->monitor_fn   = monitor;
 
        s->ctx = ctx;
        s->r   = *r;
        ZERO_STRUCT(s->r.out);
 
+
        /* proceed to pure rpc connection if the binding string is provided,
           otherwise try to connect domain controller */
        if (r->in.binding == NULL) {
-               s->rpc_conn.in.name    = r->in.name;
-               s->rpc_conn.level      = LIBNET_RPC_CONNECT_DC;
+               /* Pass on any binding flags (such as anonymous fallback) that have been set */
+               s->rpc_conn.in.dcerpc_flags = r->in.dcerpc_flags;
+
+               s->rpc_conn.in.name         = r->in.name;
+               s->rpc_conn.level           = LIBNET_RPC_CONNECT_DC;
        } else {
-               s->rpc_conn.in.binding = r->in.binding;
-               s->rpc_conn.level      = LIBNET_RPC_CONNECT_BINDING;
+               s->rpc_conn.in.binding      = r->in.binding;
+               s->rpc_conn.level           = LIBNET_RPC_CONNECT_BINDING;
        }
 
        /* 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);
@@ -470,7 +534,8 @@ static void continue_dci_rpc_connect(struct composite_context *ctx)
 {
        struct composite_context *c;
        struct rpc_connect_dci_state *s;
-       struct rpc_request *open_pol_req;
+       struct tevent_req *subreq;
+       enum dcerpc_transport_t transport;
 
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
@@ -481,6 +546,23 @@ 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;
+               const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
+
+               data.host        = dcerpc_binding_get_string_option(b, "host");
+               data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
+               data.transport   = dcerpc_binding_get_transport(b);
+               data.domain_name = dcerpc_binding_get_string_option(b, "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->lsa.pipe;
        
@@ -491,6 +573,16 @@ static void continue_dci_rpc_connect(struct composite_context *ctx)
 
        s->attr.sec_qos = &s->qos;
 
+       transport = dcerpc_binding_get_transport(s->lsa_pipe->binding);
+       if (transport == NCACN_IP_TCP) {
+               /*
+                * Skip to creating the actual connection. We can't open a
+                * policy handle over tcpip.
+                */
+               continue_epm_map_binding_send(c);
+               return;
+       }
+
        s->lsa_open_policy.in.attr        = &s->attr;
        s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
        if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
@@ -498,10 +590,12 @@ static void continue_dci_rpc_connect(struct composite_context *ctx)
        s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        s->lsa_open_policy.out.handle     = &s->lsa_handle;
 
-       open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
-       if (composite_nomem(open_pol_req, c)) return;
+       subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
+                                              s->lsa_pipe->binding_handle,
+                                              &s->lsa_open_policy);
+       if (composite_nomem(subreq, c)) return;
 
-       composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
+       tevent_req_set_callback(subreq, continue_lsa_policy, c);
 }
 
 
@@ -509,42 +603,58 @@ static void continue_dci_rpc_connect(struct composite_context *ctx)
   Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
   for kerberos realm (dns name) and guid. The query may fail.
 */
-static void continue_lsa_policy(struct rpc_request *req)
+static void continue_lsa_policy(struct tevent_req *subreq)
 {
        struct composite_context *c;
        struct rpc_connect_dci_state *s;
-       struct rpc_request *query_info_req;
 
-       c = talloc_get_type(req->async.private_data, struct composite_context);
+       c = tevent_req_callback_data(subreq, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(c->status)) {
                composite_error(c, c->status);
                return;
        }
 
-       if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+       if (1 || 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;
+       s->lsa_query_info2.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
+       if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
 
-       query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
-       if (composite_nomem(query_info_req, c)) return;
+       subreq = dcerpc_lsa_QueryInfoPolicy2_r_send(s, c->event_ctx,
+                                                   s->lsa_pipe->binding_handle,
+                                                   &s->lsa_query_info2);
+       if (composite_nomem(subreq, c)) return;
 
-       composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
+       tevent_req_set_callback(subreq, continue_lsa_query_info2, c);
 }
 
 
@@ -552,22 +662,22 @@ static void continue_lsa_policy(struct rpc_request *req)
   Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
   may result in failure) and query lsa info for domain name and sid.
 */
-static void continue_lsa_query_info2(struct rpc_request *req)
+static void continue_lsa_query_info2(struct tevent_req *subreq)
 {      
        struct composite_context *c;
        struct rpc_connect_dci_state *s;
-       struct rpc_request *query_info_req;
 
-       c = talloc_get_type(req->async.private_data, struct composite_context);
+       c = tevent_req_callback_data(subreq, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_lsa_QueryInfoPolicy2_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        
        /* In case of error just null the realm and guid and proceed
           to the next step. After all, it doesn't have to be AD domain
           controller we talking to - NT-style PDC also counts */
 
-       if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
+       if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
                s->r.out.realm = NULL;
                s->r.out.guid  = NULL;
 
@@ -591,38 +701,53 @@ static void continue_lsa_query_info2(struct rpc_request *req)
                /* Copy the dns domain name and guid from the query result */
 
                /* this should actually be a conversion from lsa_StringLarge */
-               s->r.out.realm = s->lsa_query_info2.out.info->dns.dns_domain.string;
+               s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
                s->r.out.guid  = talloc(c, struct GUID);
                if (composite_nomem(s->r.out.guid, c)) {
                        s->r.out.error_string = NULL;
                        return;
                }
-               *s->r.out.guid = s->lsa_query_info2.out.info->dns.domain_guid;
+               *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;
+       s->lsa_query_info.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
+       if (composite_nomem(s->lsa_query_info.out.info, c)) return;
 
-       query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
-       if (composite_nomem(query_info_req, c)) return;
+       subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
+                                                  s->lsa_pipe->binding_handle,
+                                                  &s->lsa_query_info);
+       if (composite_nomem(subreq, c)) return;
 
-       composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
+       tevent_req_set_callback(subreq, continue_lsa_query_info, c);
 }
 
 
 /*
   Step 5 of RpcConnectDCInfo: Get domain name and sid
 */
-static void continue_lsa_query_info(struct rpc_request *req)
+static void continue_lsa_query_info(struct tevent_req *subreq)
 {
        struct composite_context *c;
        struct rpc_connect_dci_state *s;
 
-       c = talloc_get_type(req->async.private_data, struct composite_context);
+       c = tevent_req_callback_data(subreq, struct composite_context);
        s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(c->status)) {
                s->r.out.error_string = talloc_asprintf(c,
                                                        "lsa_QueryInfoPolicy failed: %s",
@@ -631,9 +756,19 @@ 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;
+       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);
 }
@@ -642,24 +777,26 @@ static void continue_lsa_query_info(struct rpc_request *req)
    Step 5 (continued) of RpcConnectDCInfo: request endpoint
    map binding.
 
-   We may short-cut to this step if we dont' support LSA OpenPolicy on this transport
+   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;
+       struct cli_credentials *epm_creds = NULL;
+
        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);
+       s->final_binding = dcerpc_binding_dup(s, s->lsa_pipe->binding);
        if (composite_nomem(s->final_binding, c)) return;
-       
-       *s->final_binding = *s->lsa_pipe->binding;
-       /* Ensure we keep hold of the member elements */
-       if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
+
+       epm_creds = cli_credentials_init_anon(s);
+       if (composite_nomem(epm_creds, 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);
+                                                 epm_creds,
+                                                 s->ctx->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);
@@ -688,7 +825,11 @@ static void continue_epm_map_binding(struct composite_context *ctx)
        }
 
        /* create secondary connection derived from lsa pipe */
-       sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
+       sec_conn_req = dcerpc_secondary_auth_connection_send(s->lsa_pipe,
+                                                            s->final_binding,
+                                                            s->r.in.dcerpc_iface,
+                                                            s->ctx->cred,
+                                                            s->ctx->lp_ctx);
        if (composite_nomem(sec_conn_req, c)) return;
 
        composite_continue(c, sec_conn_req, continue_secondary_conn, c);
@@ -707,7 +848,8 @@ static void continue_secondary_conn(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_dci_state);
 
-       c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
+       c->status = dcerpc_secondary_auth_connection_recv(ctx, s->lsa_pipe,
+                                                         &s->final_pipe);
        if (!NT_STATUS_IS_OK(c->status)) {
                s->r.out.error_string = talloc_asprintf(c,
                                                        "secondary connection failed: %s",
@@ -718,6 +860,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;
+               const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
+
+               /* prepare monitor message and post it */
+               data.host        = dcerpc_binding_get_string_option(b, "host");
+               data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
+               data.transport   = dcerpc_binding_get_transport(b);
+               data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
+
+               msg.type      = mon_NetRpcConnect;
+               msg.data      = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
+
        composite_done(c);
 }
 
@@ -752,18 +913,23 @@ 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) {
+               if (r->in.dcerpc_iface == &ndr_table_samr) {
                        ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+                       ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
 
-               } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
+               } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
                        ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
+                       ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
                }
 
        } else {
                if (s->r.out.error_string) {
                        r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
-               } else {
+               } 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));
                }
        }
 
@@ -784,7 +950,8 @@ 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;
 
@@ -792,16 +959,16 @@ struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
        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:
@@ -859,6 +1026,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);
 }