Fix spelling mistakes
[bbaumbach/samba-autobuild/.git] / source4 / libnet / libnet_domain.c
index 57c0ce6571e4c62a611b949b431128c4fc80690a..a7499b84b35bb6a8b2c6e5d1ddb9b24d86939936 100644 (file)
@@ -5,7 +5,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
    
    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,
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    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 "librpc/gen_ndr/ndr_samr_c.h"
 #include "librpc/gen_ndr/ndr_lsa_c.h"
 
 #include "librpc/gen_ndr/ndr_samr_c.h"
 #include "librpc/gen_ndr/ndr_lsa_c.h"
 
-static void domain_open_handler(struct rpc_request*);
-
-enum domain_open_stage { DOMOPEN_CONNECT, DOMOPEN_LOOKUP, DOMOPEN_OPEN,
-                        DOMOPEN_CLOSE_EXISTING, DOMOPEN_RPC_CONNECT };
 
 struct domain_open_samr_state {
 
 struct domain_open_samr_state {
-       enum domain_open_stage    stage;
        struct libnet_context     *ctx;
        struct dcerpc_pipe        *pipe;
        struct libnet_context     *ctx;
        struct dcerpc_pipe        *pipe;
-       struct rpc_request        *req;
-       struct composite_context  *rpcconn_req;
+       struct libnet_RpcConnect  rpcconn;
        struct samr_Connect       connect;
        struct samr_LookupDomain  lookup;
        struct samr_OpenDomain    open;
        struct samr_Close         close;
        struct samr_Connect       connect;
        struct samr_LookupDomain  lookup;
        struct samr_OpenDomain    open;
        struct samr_Close         close;
-       struct libnet_RpcConnect  rpcconn;
        struct lsa_String         domain_name;
        uint32_t                  access_mask;
        struct policy_handle      connect_handle;
        struct policy_handle      domain_handle;
        struct lsa_String         domain_name;
        uint32_t                  access_mask;
        struct policy_handle      connect_handle;
        struct policy_handle      domain_handle;
+       struct dom_sid2           *domain_sid;
 
        /* information about the progress */
        void (*monitor_fn)(struct monitor_msg*);
 };
 
 
 
        /* information about the progress */
        void (*monitor_fn)(struct monitor_msg*);
 };
 
 
+static void continue_domain_open_close(struct tevent_req *subreq);
+static void continue_domain_open_connect(struct tevent_req *subreq);
+static void continue_domain_open_lookup(struct tevent_req *subreq);
+static void continue_domain_open_open(struct tevent_req *subreq);
+
+
 /**
  * Stage 0.5 (optional): Connect to samr rpc pipe
  */
 /**
  * Stage 0.5 (optional): Connect to samr rpc pipe
  */
-static void domain_open_rpc_connect(struct composite_context *ctx)
+static void continue_domain_open_rpc_connect(struct composite_context *ctx)
 {
        struct composite_context *c;
        struct domain_open_samr_state *s;
 {
        struct composite_context *c;
        struct domain_open_samr_state *s;
+       struct tevent_req *subreq;
 
 
-       c = talloc_get_type(ctx->async.private_data, struct composite_context);
-       s = talloc_get_type(c->private_data, struct domain_open_samr_state);
+       c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
 
        c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
        if (!composite_is_ok(c)) return;
 
        c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
        if (!composite_is_ok(c)) return;
@@ -76,13 +76,13 @@ static void domain_open_rpc_connect(struct composite_context *ctx)
        s->connect.out.connect_handle  = &s->connect_handle;
 
        /* send request */
        s->connect.out.connect_handle  = &s->connect_handle;
 
        /* send request */
-       s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
-       if (composite_nomem(s->req, c)) return;
+       subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
+                                           s->pipe->binding_handle,
+                                           &s->connect);
+       if (composite_nomem(subreq, c)) return;
 
        /* callback handler */
 
        /* callback handler */
-       s->req->async.callback = domain_open_handler;
-       s->req->async.private  = c;
-       s->stage = DOMOPEN_CONNECT;
+       tevent_req_set_callback(subreq, continue_domain_open_connect, c);
 }
 
 
 }
 
 
@@ -90,12 +90,27 @@ static void domain_open_rpc_connect(struct composite_context *ctx)
  * Stage 0.5 (optional): Close existing (in libnet context) domain
  * handle
  */
  * Stage 0.5 (optional): Close existing (in libnet context) domain
  * handle
  */
-static NTSTATUS domain_open_close(struct composite_context *c,
-                                 struct domain_open_samr_state *s)
+static void continue_domain_open_close(struct tevent_req *subreq)
 {
 {
+       struct composite_context *c;
+       struct domain_open_samr_state *s;
+
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
+
        /* receive samr_Close reply */
        /* receive samr_Close reply */
-       c->status = dcerpc_ndr_request_recv(s->req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
+       c->status = dcerpc_samr_Close_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type = mon_SamrClose;
+               msg.data = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
 
        /* reset domain handle and associated data in libnet_context */
        s->ctx->samr.name        = NULL;
 
        /* reset domain handle and associated data in libnet_context */
        s->ctx->samr.name        = NULL;
@@ -108,135 +123,139 @@ static NTSTATUS domain_open_close(struct composite_context *c,
        s->connect.out.connect_handle  = &s->connect_handle;
        
        /* send request */
        s->connect.out.connect_handle  = &s->connect_handle;
        
        /* send request */
-       s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
-       if (s->req == NULL) return NT_STATUS_NO_MEMORY;
+       subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
+                                           s->pipe->binding_handle,
+                                           &s->connect);
+       if (composite_nomem(subreq, c)) return;
 
        /* callback handler */
 
        /* callback handler */
-       s->req->async.callback = domain_open_handler;
-       s->req->async.private  = c;
-       s->stage = DOMOPEN_CONNECT;
-       
-       return NT_STATUS_OK;
+       tevent_req_set_callback(subreq, continue_domain_open_connect, c);
 }
 
 
 /**
  * Stage 1: Connect to SAM server.
  */
 }
 
 
 /**
  * Stage 1: Connect to SAM server.
  */
-static NTSTATUS domain_open_connect(struct composite_context *c,
-                                   struct domain_open_samr_state *s)
+static void continue_domain_open_connect(struct tevent_req *subreq)
 {
 {
-       struct samr_LookupDomain *r = &s->lookup;
+       struct composite_context *c;
+       struct domain_open_samr_state *s;
+       struct samr_LookupDomain *r;
+       
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
 
        /* receive samr_Connect reply */
 
        /* receive samr_Connect reply */
-       c->status = dcerpc_ndr_request_recv(s->req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
+       c->status = dcerpc_samr_Connect_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+
+               msg.type = mon_SamrConnect;
+               msg.data = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
+       r = &s->lookup;
 
        /* prepare for samr_LookupDomain call */
        r->in.connect_handle = &s->connect_handle;
        r->in.domain_name    = &s->domain_name;
 
        /* prepare for samr_LookupDomain call */
        r->in.connect_handle = &s->connect_handle;
        r->in.domain_name    = &s->domain_name;
+       r->out.sid           = talloc(s, struct dom_sid2 *);
+       if (composite_nomem(r->out.sid, c)) return;
 
 
-       s->req = dcerpc_samr_LookupDomain_send(s->pipe, c, r);
-       if (s->req == NULL) goto failure;
-
-       s->req->async.callback = domain_open_handler;
-       s->req->async.private  = c;
-       s->stage = DOMOPEN_LOOKUP;
-
-       return NT_STATUS_OK;
+       subreq = dcerpc_samr_LookupDomain_r_send(s, c->event_ctx,
+                                                s->pipe->binding_handle,
+                                                r);
+       if (composite_nomem(subreq, c)) return;
 
 
-failure:
-       return NT_STATUS_UNSUCCESSFUL;
+       tevent_req_set_callback(subreq, continue_domain_open_lookup, c);
 }
 
 
 /**
  * Stage 2: Lookup domain by name.
  */
 }
 
 
 /**
  * Stage 2: Lookup domain by name.
  */
-static NTSTATUS domain_open_lookup(struct composite_context *c,
-                                  struct domain_open_samr_state *s)
+static void continue_domain_open_lookup(struct tevent_req *subreq)
 {
 {
-       struct samr_OpenDomain *r = &s->open;
+       struct composite_context *c;
+       struct domain_open_samr_state *s;
+       struct samr_OpenDomain *r;
 
 
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
+       
        /* receive samr_LookupDomain reply */
        /* receive samr_LookupDomain reply */
-       c->status = dcerpc_ndr_request_recv(s->req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
+       c->status = dcerpc_samr_LookupDomain_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               struct msg_rpc_lookup_domain data;
+
+               data.domain_name = s->domain_name.string;
+
+               msg.type = mon_SamrLookupDomain;
+               msg.data = (void*)&data;
+               msg.data_size = sizeof(data);
+               s->monitor_fn(&msg);
+       }
+
+       r = &s->open;
+
+       /* check the rpc layer status */
+       if (!composite_is_ok(c)) return;
+
+       /* check the rpc call itself status */
+       if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
+               composite_error(c, s->lookup.out.result);
+               return;
+       }
 
        /* prepare for samr_OpenDomain call */
        r->in.connect_handle = &s->connect_handle;
        r->in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
 
        /* prepare for samr_OpenDomain call */
        r->in.connect_handle = &s->connect_handle;
        r->in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
-       r->in.sid            = s->lookup.out.sid;
+       r->in.sid            = *s->lookup.out.sid;
        r->out.domain_handle = &s->domain_handle;
 
        r->out.domain_handle = &s->domain_handle;
 
-       s->req = dcerpc_samr_OpenDomain_send(s->pipe, c, r);
-       if (s->req == NULL) goto failure;
-
-       s->req->async.callback = domain_open_handler;
-       s->req->async.private  = c;
-       s->stage = DOMOPEN_OPEN;
+       subreq = dcerpc_samr_OpenDomain_r_send(s, c->event_ctx,
+                                              s->pipe->binding_handle,
+                                              r);
+       if (composite_nomem(subreq, c)) return;
 
 
-       return NT_STATUS_OK;
-
-failure:
-       return NT_STATUS_UNSUCCESSFUL;
+       tevent_req_set_callback(subreq, continue_domain_open_open, c);
 }
 
 
 /*
  * Stage 3: Open domain.
  */
 }
 
 
 /*
  * Stage 3: Open domain.
  */
-static NTSTATUS domain_open_open(struct composite_context *c,
-                                struct domain_open_samr_state *s)
+static void continue_domain_open_open(struct tevent_req *subreq)
 {
 {
-       /* receive samr_OpenDomain reply */
-       c->status = dcerpc_ndr_request_recv(s->req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
-
-       c->state = COMPOSITE_STATE_DONE;
-       
-       return NT_STATUS_OK;
-}
+       struct composite_context *c;
+       struct domain_open_samr_state *s;
 
 
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
 
 
-/**
- * Event handler for asynchronous request. Handles transition through
- * intermediate stages of the call.
- *
- * @param req rpc call context
- */
-static void domain_open_handler(struct rpc_request *req)
-{
-       struct composite_context *c = req->async.private;
-       struct domain_open_samr_state *s = talloc_get_type(c->private_data,
-                                                          struct domain_open_samr_state);
-
-       /* Stages of the call */
-       switch (s->stage) {
-       case DOMOPEN_CONNECT:
-               c->status = domain_open_connect(c, s);
-               break;
-       case DOMOPEN_LOOKUP:
-               c->status = domain_open_lookup(c, s);
-               break;
-       case DOMOPEN_OPEN:
-               c->status = domain_open_open(c, s);
-               break;
-       case DOMOPEN_CLOSE_EXISTING:
-               c->status = domain_open_close(c, s);
-               break;
-       case DOMOPEN_RPC_CONNECT:
-               /* this state shouldn't be handled here */
-               c->status = NT_STATUS_UNSUCCESSFUL;
-               break;
-       }
+       /* receive samr_OpenDomain reply */
+       c->status = dcerpc_samr_OpenDomain_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
 
 
-       if (!NT_STATUS_IS_OK(c->status)) {
-               c->state = COMPOSITE_STATE_ERROR;
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type = mon_SamrOpenDomain;
+               msg.data = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
        }
 
        }
 
-       if (c->state == COMPOSITE_STATE_DONE) {
-               composite_done(c);
-       }
+       composite_done(c);
 }
 
 
 }
 
 
@@ -249,13 +268,16 @@ static void domain_open_handler(struct rpc_request *req)
  */
 
 struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
  */
 
 struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
+                                                    TALLOC_CTX *mem_ctx,
                                                     struct libnet_DomainOpen *io,
                                                     void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_open_samr_state *s;
                                                     struct libnet_DomainOpen *io,
                                                     void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_open_samr_state *s;
+       struct composite_context *rpcconn_req;
+       struct tevent_req *subreq;
 
 
-       c = composite_create(ctx, ctx->event_ctx);
+       c = composite_create(mem_ctx, ctx->event_ctx);
        if (c == NULL) return NULL;
 
        s = talloc_zero(c, struct domain_open_samr_state);
        if (c == NULL) return NULL;
 
        s = talloc_zero(c, struct domain_open_samr_state);
@@ -275,22 +297,19 @@ struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
                /* attempting to connect a domain controller */
                s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
                s->rpcconn.in.name         = io->in.domain_name;
                /* attempting to connect a domain controller */
                s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
                s->rpcconn.in.name         = io->in.domain_name;
-               s->rpcconn.in.dcerpc_iface = &dcerpc_table_samr;
+               s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
                
                /* send rpc pipe connect request */
                
                /* send rpc pipe connect request */
-               s->rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn);
-               if (composite_nomem(s->rpcconn_req, c)) return c;
-
-               s->rpcconn_req->async.fn = domain_open_rpc_connect;
-               s->rpcconn_req->async.private_data  = c;
-               s->stage = DOMOPEN_RPC_CONNECT;
+               rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
+               if (composite_nomem(rpcconn_req, c)) return c;
 
 
+               composite_continue(c, rpcconn_req, continue_domain_open_rpc_connect, c);
                return c;
        }
 
        /* libnet context's domain handle is not empty, so check out what
           was opened first, before doing anything */
                return c;
        }
 
        /* libnet context's domain handle is not empty, so check out what
           was opened first, before doing anything */
-       if (!policy_handle_empty(&ctx->samr.handle)) {
+       if (!ndr_policy_handle_empty(&ctx->samr.handle)) {
                if (strequal(ctx->samr.name, io->in.domain_name) &&
                    ctx->samr.access_mask == io->in.access_mask) {
 
                if (strequal(ctx->samr.name, io->in.domain_name) &&
                    ctx->samr.access_mask == io->in.access_mask) {
 
@@ -304,14 +323,13 @@ struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
                        s->close.in.handle = &ctx->samr.handle;
 
                        /* send request to close domain handle */
                        s->close.in.handle = &ctx->samr.handle;
 
                        /* send request to close domain handle */
-                       s->req = dcerpc_samr_Close_send(s->pipe, c, &s->close);
-                       if (composite_nomem(s->req, c)) return c;
+                       subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
+                                                         s->pipe->binding_handle,
+                                                         &s->close);
+                       if (composite_nomem(subreq, c)) return c;
 
                        /* callback handler */
 
                        /* callback handler */
-                       s->req->async.callback = domain_open_handler;
-                       s->req->async.private  = c;
-                       s->stage = DOMOPEN_CLOSE_EXISTING;
-
+                       tevent_req_set_callback(subreq, continue_domain_open_close, c);
                        return c;
                }
        }
                        return c;
                }
        }
@@ -322,14 +340,13 @@ struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
        s->connect.out.connect_handle  = &s->connect_handle;
        
        /* send request */
        s->connect.out.connect_handle  = &s->connect_handle;
        
        /* send request */
-       s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
-       if (composite_nomem(s->req, c)) return c;
+       subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
+                                           s->pipe->binding_handle,
+                                           &s->connect);
+       if (composite_nomem(subreq, c)) return c;
 
        /* callback handler */
 
        /* callback handler */
-       s->req->async.callback = domain_open_handler;
-       s->req->async.private  = c;
-       s->stage = DOMOPEN_CONNECT;
-
+       tevent_req_set_callback(subreq, continue_domain_open_connect, c);
        return c;
 }
 
        return c;
 }
 
@@ -354,12 +371,14 @@ NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_c
        status = composite_wait(c);
        
        if (NT_STATUS_IS_OK(status) && io) {
        status = composite_wait(c);
        
        if (NT_STATUS_IS_OK(status) && io) {
-               s = talloc_get_type(c->private_data, struct domain_open_samr_state);
+               s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
                io->out.domain_handle = s->domain_handle;
 
                /* store the resulting handle and related data for use by other
                   libnet functions */
                io->out.domain_handle = s->domain_handle;
 
                /* store the resulting handle and related data for use by other
                   libnet functions */
+               ctx->samr.connect_handle = s->connect_handle;
                ctx->samr.handle      = s->domain_handle;
                ctx->samr.handle      = s->domain_handle;
+               ctx->samr.sid         = talloc_steal(ctx, *s->lookup.out.sid);
                ctx->samr.name        = talloc_steal(ctx, s->domain_name.string);
                ctx->samr.access_mask = s->access_mask;
        }
                ctx->samr.name        = talloc_steal(ctx, s->domain_name.string);
                ctx->samr.access_mask = s->access_mask;
        }
@@ -384,7 +403,7 @@ struct domain_open_lsa_state {
 
 
 static void continue_rpc_connect_lsa(struct composite_context *ctx);
 
 
 static void continue_rpc_connect_lsa(struct composite_context *ctx);
-static void continue_lsa_policy_open(struct rpc_request *req);
+static void continue_lsa_policy_open(struct tevent_req *subreq);
 
 
 /**
 
 
 /**
@@ -396,17 +415,18 @@ static void continue_lsa_policy_open(struct rpc_request *req);
  */
 
 struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
  */
 
 struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
+                                                   TALLOC_CTX *mem_ctx,
                                                    struct libnet_DomainOpen *io,
                                                    void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_open_lsa_state *s;
        struct composite_context *rpcconn_req;
                                                    struct libnet_DomainOpen *io,
                                                    void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_open_lsa_state *s;
        struct composite_context *rpcconn_req;
-       struct rpc_request *openpol_req;
+       struct tevent_req *subreq;
        struct lsa_QosInfo *qos;
 
        /* create composite context and state */
        struct lsa_QosInfo *qos;
 
        /* create composite context and state */
-       c = composite_create(ctx, ctx->event_ctx);
+       c = composite_create(mem_ctx, ctx->event_ctx);
        if (c == NULL) return c;
 
        s = talloc_zero(c, struct domain_open_lsa_state);
        if (c == NULL) return c;
 
        s = talloc_zero(c, struct domain_open_lsa_state);
@@ -422,13 +442,15 @@ struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
        /* check, if there's lsa pipe opened already, before opening a handle */
        if (ctx->lsa.pipe == NULL) {
 
        /* check, if there's lsa pipe opened already, before opening a handle */
        if (ctx->lsa.pipe == NULL) {
 
+               ZERO_STRUCT(s->rpcconn);
+
                /* attempting to connect a domain controller */
                s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
                s->rpcconn.in.name         = talloc_strdup(c, io->in.domain_name);
                /* attempting to connect a domain controller */
                s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
                s->rpcconn.in.name         = talloc_strdup(c, io->in.domain_name);
-               s->rpcconn.in.dcerpc_iface = &dcerpc_table_lsarpc;
+               s->rpcconn.in.dcerpc_iface = &ndr_table_lsarpc;
                
                /* send rpc pipe connect request */
                
                /* send rpc pipe connect request */
-               rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn);
+               rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
                if (composite_nomem(rpcconn_req, c)) return c;
 
                composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
                if (composite_nomem(rpcconn_req, c)) return c;
 
                composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
@@ -452,10 +474,12 @@ struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
        s->openpol.out.handle       = &s->handle;
        
        /* send rpc request */
        s->openpol.out.handle       = &s->handle;
        
        /* send rpc request */
-       openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
-       if (composite_nomem(openpol_req, c)) return c;
+       subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
+                                              s->pipe->binding_handle,
+                                              &s->openpol);
+       if (composite_nomem(subreq, c)) return c;
 
 
-       composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
+       tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
        return c;
 }
 
        return c;
 }
 
@@ -468,10 +492,10 @@ static void continue_rpc_connect_lsa(struct composite_context *ctx)
        struct composite_context *c;
        struct domain_open_lsa_state *s;
        struct lsa_QosInfo *qos;
        struct composite_context *c;
        struct domain_open_lsa_state *s;
        struct lsa_QosInfo *qos;
-       struct rpc_request *openpol_req;
+       struct tevent_req *subreq;
 
 
-       c = talloc_get_type(ctx->async.private_data, struct composite_context);
-       s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
+       c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
 
        /* receive rpc connection */
        c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
 
        /* receive rpc connection */
        c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
@@ -496,27 +520,39 @@ static void continue_rpc_connect_lsa(struct composite_context *ctx)
        s->openpol.out.handle       = &s->handle;
 
        /* send rpc request */
        s->openpol.out.handle       = &s->handle;
 
        /* send rpc request */
-       openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
-       if (composite_nomem(openpol_req, c)) return;
+       subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
+                                              s->pipe->binding_handle,
+                                              &s->openpol);
+       if (composite_nomem(subreq, c)) return;
 
 
-       composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
+       tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
 }
 
 
 /*
   Stage 1: Lsa policy opened - we're done, if successfully
  */
 }
 
 
 /*
   Stage 1: Lsa policy opened - we're done, if successfully
  */
-static void continue_lsa_policy_open(struct rpc_request *req)
+static void continue_lsa_policy_open(struct tevent_req *subreq)
 {
        struct composite_context *c;
        struct domain_open_lsa_state *s;
 
 {
        struct composite_context *c;
        struct domain_open_lsa_state *s;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
-       s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
 
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
        if (!composite_is_ok(c)) return;
 
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_LsaOpenPolicy;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
        composite_done(c);
 }
 
        composite_done(c);
 }
 
@@ -542,7 +578,7 @@ NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_co
        if (NT_STATUS_IS_OK(status) && io) {
                /* everything went fine - get the results and
                   return the error string */
        if (NT_STATUS_IS_OK(status) && io) {
                /* everything went fine - get the results and
                   return the error string */
-               s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
+               s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
                io->out.domain_handle = s->handle;
 
                ctx->lsa.handle      = s->handle;
                io->out.domain_handle = s->handle;
 
                ctx->lsa.handle      = s->handle;
@@ -566,12 +602,13 @@ NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_co
 /**
  * Sends a request to open a domain in desired service
  *
 /**
  * Sends a request to open a domain in desired service
  *
- * @param ctx initalised libnet context
+ * @param ctx initialised libnet context
  * @param io arguments and results of the call
  * @param monitor pointer to monitor function that is passed monitor message
  */
 
 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
  * @param io arguments and results of the call
  * @param monitor pointer to monitor function that is passed monitor message
  */
 
 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
+                                                TALLOC_CTX *mem_ctx,
                                                 struct libnet_DomainOpen *io,
                                                 void (*monitor)(struct monitor_msg*))
 {
                                                 struct libnet_DomainOpen *io,
                                                 void (*monitor)(struct monitor_msg*))
 {
@@ -580,13 +617,13 @@ struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
        switch (io->in.type) {
        case DOMAIN_LSA:
                /* reques to open a policy handle on \pipe\lsarpc */
        switch (io->in.type) {
        case DOMAIN_LSA:
                /* reques to open a policy handle on \pipe\lsarpc */
-               c = libnet_DomainOpenLsa_send(ctx, io, monitor);
+               c = libnet_DomainOpenLsa_send(ctx, mem_ctx, io, monitor);
                break;
 
        case DOMAIN_SAMR:
        default:
                /* request to open a domain policy handle on \pipe\samr */
                break;
 
        case DOMAIN_SAMR:
        default:
                /* request to open a domain policy handle on \pipe\samr */
-               c = libnet_DomainOpenSamr_send(ctx, io, monitor);
+               c = libnet_DomainOpenSamr_send(ctx, mem_ctx, io, monitor);
                break;
        }
 
                break;
        }
 
@@ -636,7 +673,7 @@ NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
                           TALLOC_CTX *mem_ctx,
                           struct libnet_DomainOpen *io)
 {
                           TALLOC_CTX *mem_ctx,
                           struct libnet_DomainOpen *io)
 {
-       struct composite_context *c = libnet_DomainOpen_send(ctx, io, NULL);
+       struct composite_context *c = libnet_DomainOpen_send(ctx, mem_ctx, io, NULL);
        return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
 }
 
        return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
 }
 
@@ -650,19 +687,20 @@ struct domain_close_lsa_state {
 };
 
 
 };
 
 
-static void continue_lsa_close(struct rpc_request *req);
+static void continue_lsa_close(struct tevent_req *subreq);
 
 
 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
 
 
 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
+                                                    TALLOC_CTX *mem_ctx,
                                                     struct libnet_DomainClose *io,
                                                     void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_close_lsa_state *s;
                                                     struct libnet_DomainClose *io,
                                                     void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_close_lsa_state *s;
-       struct rpc_request *close_req;
+       struct tevent_req *subreq;
 
        /* composite context and state structure allocation */
 
        /* composite context and state structure allocation */
-       c = composite_create(ctx, ctx->event_ctx);
+       c = composite_create(mem_ctx, ctx->event_ctx);
        if (c == NULL) return c;
 
        s = talloc_zero(c, struct domain_close_lsa_state);
        if (c == NULL) return c;
 
        s = talloc_zero(c, struct domain_close_lsa_state);
@@ -686,10 +724,12 @@ struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
        s->close.out.handle = &s->handle;
 
        /* send the request */
        s->close.out.handle = &s->handle;
 
        /* send the request */
-       close_req = dcerpc_lsa_Close_send(s->pipe, c, &s->close);
-       if (composite_nomem(close_req, c)) return c;
+       subreq = dcerpc_lsa_Close_r_send(s, c->event_ctx,
+                                        s->pipe->binding_handle,
+                                        &s->close);
+       if (composite_nomem(subreq, c)) return c;
 
 
-       composite_continue_rpc(c, close_req, continue_lsa_close, c);
+       tevent_req_set_callback(subreq, continue_lsa_close, c);
        return c;
 }
 
        return c;
 }
 
@@ -697,17 +737,27 @@ struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
 /*
   Stage 1: Receive result of lsa close call
 */
 /*
   Stage 1: Receive result of lsa close call
 */
-static void continue_lsa_close(struct rpc_request *req)
+static void continue_lsa_close(struct tevent_req *subreq)
 {
        struct composite_context *c;
        struct domain_close_lsa_state *s;
        
 {
        struct composite_context *c;
        struct domain_close_lsa_state *s;
        
-       c = talloc_get_type(req->async.private, struct composite_context);
-       s = talloc_get_type(c->private_data, struct domain_close_lsa_state);
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_close_lsa_state);
 
 
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_lsa_Close_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
        if (!composite_is_ok(c)) return;
 
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+
+               msg.type      = mon_LsaClose;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
        composite_done(c);
 }
 
        composite_done(c);
 }
 
@@ -745,19 +795,20 @@ struct domain_close_samr_state {
 };
 
 
 };
 
 
-static void continue_samr_close(struct rpc_request *req);
+static void continue_samr_close(struct tevent_req *subreq);
 
 
 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
 
 
 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
+                                                     TALLOC_CTX *mem_ctx,
                                                      struct libnet_DomainClose *io,
                                                      void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_close_samr_state *s;
                                                      struct libnet_DomainClose *io,
                                                      void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct domain_close_samr_state *s;
-       struct rpc_request *close_req;
+       struct tevent_req *subreq;
 
        /* composite context and state structure allocation */
 
        /* composite context and state structure allocation */
-       c = composite_create(ctx, ctx->event_ctx);
+       c = composite_create(mem_ctx, ctx->event_ctx);
        if (c == NULL) return c;
 
        s = talloc_zero(c, struct domain_close_samr_state);
        if (c == NULL) return c;
 
        s = talloc_zero(c, struct domain_close_samr_state);
@@ -779,10 +830,12 @@ struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx
        s->close.out.handle = &s->handle;
 
        /* send the request */
        s->close.out.handle = &s->handle;
 
        /* send the request */
-       close_req = dcerpc_samr_Close_send(ctx->samr.pipe, ctx, &s->close);
-       if (composite_nomem(close_req, c)) return c;
+       subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
+                                         ctx->samr.pipe->binding_handle,
+                                         &s->close);
+       if (composite_nomem(subreq, c)) return c;
 
 
-       composite_continue_rpc(c, close_req, continue_samr_close, c);
+       tevent_req_set_callback(subreq, continue_samr_close, c);
        return c;
 }
 
        return c;
 }
 
@@ -790,16 +843,26 @@ struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx
 /*
   Stage 1: Receive result of samr close call
 */
 /*
   Stage 1: Receive result of samr close call
 */
-static void continue_samr_close(struct rpc_request *req)
+static void continue_samr_close(struct tevent_req *subreq)
 {
        struct composite_context *c;
        struct domain_close_samr_state *s;
 
 {
        struct composite_context *c;
        struct domain_close_samr_state *s;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
-       s = talloc_get_type(c->private_data, struct domain_close_samr_state);
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_close_samr_state);
        
        
-       c->status = dcerpc_ndr_request_recv(req);
+       c->status = dcerpc_samr_Close_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
        if (!composite_is_ok(c)) return;
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_SamrClose;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
        
        composite_done(c);
 }
        
        composite_done(c);
 }
@@ -816,7 +879,10 @@ NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_
                /* domain policy handle closed successfully */
 
                ZERO_STRUCT(ctx->samr.handle);
                /* domain policy handle closed successfully */
 
                ZERO_STRUCT(ctx->samr.handle);
+               talloc_free(discard_const_p(char, ctx->samr.name));
+               talloc_free(ctx->samr.sid);
                ctx->samr.name = NULL;
                ctx->samr.name = NULL;
+               ctx->samr.sid = NULL;
 
                io->out.error_string = talloc_asprintf(mem_ctx, "Success");
 
 
                io->out.error_string = talloc_asprintf(mem_ctx, "Success");
 
@@ -831,6 +897,7 @@ NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_
 
 
 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
 
 
 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
+                                                 TALLOC_CTX *mem_ctx,
                                                  struct libnet_DomainClose *io,
                                                  void (*monitor)(struct monitor_msg*))
 {
                                                  struct libnet_DomainClose *io,
                                                  void (*monitor)(struct monitor_msg*))
 {
@@ -839,13 +906,13 @@ struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
        switch (io->in.type) {
        case DOMAIN_LSA:
                /* request to close policy handle on \pipe\lsarpc */
        switch (io->in.type) {
        case DOMAIN_LSA:
                /* request to close policy handle on \pipe\lsarpc */
-               c = libnet_DomainCloseLsa_send(ctx, io, monitor);
+               c = libnet_DomainCloseLsa_send(ctx, mem_ctx, io, monitor);
                break;
 
        case DOMAIN_SAMR:
        default:
                /* request to close domain policy handle on \pipe\samr */
                break;
 
        case DOMAIN_SAMR:
        default:
                /* request to close domain policy handle on \pipe\samr */
-               c = libnet_DomainCloseSamr_send(ctx, io, monitor);
+               c = libnet_DomainCloseSamr_send(ctx, mem_ctx, io, monitor);
                break;
        }
        
                break;
        }
        
@@ -880,6 +947,358 @@ NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
 {
        struct composite_context *c;
        
 {
        struct composite_context *c;
        
-       c = libnet_DomainClose_send(ctx, io, NULL);
+       c = libnet_DomainClose_send(ctx, mem_ctx, io, NULL);
        return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
 }
        return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
 }
+
+
+struct domain_list_state {     
+       struct libnet_context *ctx;
+       struct libnet_RpcConnect rpcconn;
+       struct samr_Connect samrconn;
+       struct samr_EnumDomains enumdom;
+       struct samr_Close samrclose;
+       const char *hostname;
+       struct policy_handle connect_handle;
+       int buf_size;
+       struct domainlist *domains;
+       uint32_t resume_handle;
+       uint32_t count;
+
+       void (*monitor_fn)(struct monitor_msg*);
+};
+
+
+static void continue_rpc_connect(struct composite_context *c);
+static void continue_samr_connect(struct tevent_req *subreq);
+static void continue_samr_enum_domains(struct tevent_req *subreq);
+static void continue_samr_close_handle(struct tevent_req *subreq);
+
+static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
+
+
+/*
+  Stage 1: Receive connected rpc pipe and send connection
+  request to SAMR service
+*/
+static void continue_rpc_connect(struct composite_context *ctx)
+{
+       struct composite_context *c;
+       struct domain_list_state *s;
+       struct tevent_req *subreq;
+
+       c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_list_state);
+       
+       c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
+       if (!composite_is_ok(c)) return;
+
+       s->samrconn.in.system_name     = 0;
+       s->samrconn.in.access_mask     = SEC_GENERIC_READ;     /* should be enough */
+       s->samrconn.out.connect_handle = &s->connect_handle;
+
+       subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
+                                           s->ctx->samr.pipe->binding_handle,
+                                           &s->samrconn);
+       if (composite_nomem(subreq, c)) return;
+
+       tevent_req_set_callback(subreq, continue_samr_connect, c);
+}
+
+
+/*
+  Stage 2: Receive policy handle to the connected SAMR service and issue
+  a request to enumerate domain databases available
+*/
+static void continue_samr_connect(struct tevent_req *subreq)
+{
+       struct composite_context *c;
+       struct domain_list_state *s;
+
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_list_state);
+       
+       c->status = dcerpc_samr_Connect_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_SamrConnect;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
+       s->enumdom.in.connect_handle = &s->connect_handle;
+       s->enumdom.in.resume_handle  = &s->resume_handle;
+       s->enumdom.in.buf_size       = s->buf_size;
+       s->enumdom.out.resume_handle = &s->resume_handle;
+       s->enumdom.out.num_entries   = talloc(s, uint32_t);
+       if (composite_nomem(s->enumdom.out.num_entries, c)) return;
+       s->enumdom.out.sam           = talloc(s, struct samr_SamArray *);
+       if (composite_nomem(s->enumdom.out.sam, c)) return;
+
+       subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
+                                               s->ctx->samr.pipe->binding_handle,
+                                               &s->enumdom);
+       if (composite_nomem(subreq, c)) return;
+
+       tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
+}
+
+
+/*
+  Stage 3: Receive domain names available and repeat the request
+  enumeration is not complete yet. Close samr connection handle
+  upon completion.
+*/
+static void continue_samr_enum_domains(struct tevent_req *subreq)
+{
+       struct composite_context *c;
+       struct domain_list_state *s;
+
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_list_state);
+       
+       c->status = dcerpc_samr_EnumDomains_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_SamrEnumDomains;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
+       if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
+
+               s->domains = get_domain_list(c, s);
+
+       } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
+               
+               s->domains = get_domain_list(c, s);
+               
+               /* prepare next round of enumeration */
+               s->enumdom.in.connect_handle = &s->connect_handle;
+               s->enumdom.in.resume_handle  = &s->resume_handle;
+               s->enumdom.in.buf_size       = s->ctx->samr.buf_size;
+               s->enumdom.out.resume_handle = &s->resume_handle;
+
+               /* send the request */
+               subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
+                                                       s->ctx->samr.pipe->binding_handle,
+                                                       &s->enumdom);
+               if (composite_nomem(subreq, c)) return;
+
+               tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
+
+       } else {
+               composite_error(c, s->enumdom.out.result);
+               return;
+       }
+
+       /* close samr connection handle */
+       s->samrclose.in.handle  = &s->connect_handle;
+       s->samrclose.out.handle = &s->connect_handle;
+       
+       /* send the request */
+       subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
+                                         s->ctx->samr.pipe->binding_handle,
+                                         &s->samrclose);
+       if (composite_nomem(subreq, c)) return;
+
+       tevent_req_set_callback(subreq, continue_samr_close_handle, c);
+}
+
+
+/*
+  Stage 4: Receive result of closing samr connection handle.
+*/
+static void continue_samr_close_handle(struct tevent_req *subreq)
+{
+       struct composite_context *c;
+       struct domain_list_state *s;
+
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type_abort(c->private_data, struct domain_list_state);
+
+       c->status = dcerpc_samr_Close_r_recv(subreq, s);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
+
+       if (s->monitor_fn) {
+               struct monitor_msg msg;
+               
+               msg.type      = mon_SamrClose;
+               msg.data      = NULL;
+               msg.data_size = 0;
+               s->monitor_fn(&msg);
+       }
+
+       /* did everything go fine ? */
+       if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
+               composite_error(c, s->samrclose.out.result);
+               return;
+       }
+
+       composite_done(c);
+}
+
+
+/*
+  Utility function to copy domain names from result of samr_EnumDomains call
+*/
+static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
+{
+       uint32_t i;
+       if (mem_ctx == NULL || s == NULL) return NULL;
+
+       /* prepare domains array */
+       if (s->domains == NULL) {
+               s->domains = talloc_array(mem_ctx, struct domainlist,
+                                         *s->enumdom.out.num_entries);
+       } else {
+               s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
+                                           s->count + *s->enumdom.out.num_entries);
+       }
+
+       /* copy domain names returned from samr_EnumDomains call */
+       for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
+       {
+               struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
+
+               /* strdup name as a child of allocated array to make it follow the array
+                  in case of talloc_steal or talloc_free */
+               s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
+               s->domains[i].sid  = NULL;  /* this is to be filled out later */
+       }
+
+       /* number of entries returned (domains enumerated) */
+       s->count += *s->enumdom.out.num_entries;
+       
+       return s->domains;
+}
+
+
+/**
+ * Sends a request to list domains on given host
+ *
+ * @param ctx initialised libnet context
+ * @param mem_ctx memory context
+ * @param io arguments and results of the call
+ * @param monitor pointer to monitor function that is passed monitor messages
+ */
+
+struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
+                                                TALLOC_CTX *mem_ctx,
+                                                struct libnet_DomainList *io,
+                                                void (*monitor)(struct monitor_msg*))
+{
+       struct composite_context *c;
+       struct domain_list_state *s;
+       struct composite_context *rpcconn_req;
+       struct tevent_req *subreq;
+
+       /* composite context and state structure allocation */
+       c = composite_create(ctx, ctx->event_ctx);
+       if (c == NULL) return c;
+
+       s = talloc_zero(c, struct domain_list_state);
+       if (composite_nomem(s, c)) return c;
+
+       c->private_data = s;
+       s->monitor_fn   = monitor;
+
+       s->ctx      = ctx;
+       s->hostname = talloc_strdup(c, io->in.hostname);
+       if (composite_nomem(s->hostname, c)) return c;
+
+       /* check whether samr pipe has already been opened */
+       if (ctx->samr.pipe == NULL) {
+               ZERO_STRUCT(s->rpcconn);
+
+               /* prepare rpc connect call */
+               s->rpcconn.level           = LIBNET_RPC_CONNECT_SERVER;
+               s->rpcconn.in.name         = s->hostname;
+               s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
+
+               rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
+               if (composite_nomem(rpcconn_req, c)) return c;
+               
+               composite_continue(c, rpcconn_req, continue_rpc_connect, c);
+
+       } else {
+               /* prepare samr_Connect call */
+               s->samrconn.in.system_name     = 0;
+               s->samrconn.in.access_mask     = SEC_GENERIC_READ;
+               s->samrconn.out.connect_handle = &s->connect_handle;
+               
+               subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
+                                                   s->ctx->samr.pipe->binding_handle,
+                                                   &s->samrconn);
+               if (composite_nomem(subreq, c)) return c;
+
+               tevent_req_set_callback(subreq, continue_samr_connect, c);
+       }
+
+       return c;
+}
+
+
+/**
+ * Receive result of domain list request
+ *
+ * @param c composite context returned by DomainList_send function
+ * @param ctx initialised libnet context
+ * @param mem_ctx memory context of the call
+ * @param io results and arguments of the call
+ */
+
+NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
+                               TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
+{
+       NTSTATUS status;
+       struct domain_list_state *s;
+
+       status = composite_wait(c);
+
+       s = talloc_get_type_abort(c->private_data, struct domain_list_state);
+
+       if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
+               /* fetch the results to be returned by io structure */
+               io->out.count        = s->count;
+               io->out.domains      = talloc_steal(mem_ctx, s->domains);
+               io->out.error_string = talloc_asprintf(mem_ctx, "Success");
+
+       } else if (!NT_STATUS_IS_OK(status)) {
+               /* there was an error, so return description of the status code */
+               io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
+       }
+
+       talloc_free(c);
+       return status;
+}
+
+
+/**
+ * Synchronous version of DomainList call
+ *
+ * @param ctx initialised libnet context
+ * @param mem_ctx memory context for the call
+ * @param io arguments and results of the call
+ * @return nt status code of execution
+ */
+
+NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
+                          struct libnet_DomainList *io)
+{
+       struct composite_context *c;
+
+       c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
+       return libnet_DomainList_recv(c, ctx, mem_ctx, io);
+}