r18104: A couple of important fixes to samr domain open so that
[samba.git] / source4 / libnet / libnet_domain.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Rafal Szczesniak 2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22   a composite function for domain handling on samr and lsa pipes
23 */
24
25 #include "includes.h"
26 #include "libcli/composite/composite.h"
27 #include "libnet/libnet.h"
28 #include "librpc/gen_ndr/ndr_samr_c.h"
29 #include "librpc/gen_ndr/ndr_lsa_c.h"
30
31 static void domain_open_handler(struct rpc_request*);
32
33 enum domain_open_stage { DOMOPEN_CONNECT, DOMOPEN_LOOKUP, DOMOPEN_OPEN,
34                          DOMOPEN_CLOSE_EXISTING, DOMOPEN_RPC_CONNECT };
35
36 struct domain_open_samr_state {
37         enum domain_open_stage    stage;
38         struct libnet_context     *ctx;
39         struct dcerpc_pipe        *pipe;
40         struct rpc_request        *req;
41         struct composite_context  *rpcconn_req;
42         struct samr_Connect       connect;
43         struct samr_LookupDomain  lookup;
44         struct samr_OpenDomain    open;
45         struct samr_Close         close;
46         struct libnet_RpcConnect  rpcconn;
47         struct lsa_String         domain_name;
48         uint32_t                  access_mask;
49         struct policy_handle      connect_handle;
50         struct policy_handle      domain_handle;
51
52         /* information about the progress */
53         void (*monitor_fn)(struct monitor_msg*);
54 };
55
56
57 /**
58  * Stage 0.5 (optional): Connect to samr rpc pipe
59  */
60 static void domain_open_rpc_connect(struct composite_context *ctx)
61 {
62         struct composite_context *c;
63         struct domain_open_samr_state *s;
64
65         c = talloc_get_type(ctx->async.private_data, struct composite_context);
66         s = talloc_get_type(c->private_data, struct domain_open_samr_state);
67
68         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
69         if (!composite_is_ok(c)) return;
70
71         s->pipe = s->rpcconn.out.dcerpc_pipe;
72
73         /* preparing parameters for samr_Connect rpc call */
74         s->connect.in.system_name      = 0;
75         s->connect.in.access_mask      = s->access_mask;
76         s->connect.out.connect_handle  = &s->connect_handle;
77
78         /* send request */
79         s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
80         if (composite_nomem(s->req, c)) return;
81
82         /* callback handler */
83         s->req->async.callback = domain_open_handler;
84         s->req->async.private  = c;
85         s->stage = DOMOPEN_CONNECT;
86 }
87
88
89 /**
90  * Stage 0.5 (optional): Close existing (in libnet context) domain
91  * handle
92  */
93 static NTSTATUS domain_open_close(struct composite_context *c,
94                                   struct domain_open_samr_state *s)
95 {
96         /* receive samr_Close reply */
97         c->status = dcerpc_ndr_request_recv(s->req);
98         NT_STATUS_NOT_OK_RETURN(c->status);
99
100         /* reset domain handle and associated data in libnet_context */
101         s->ctx->samr.name        = NULL;
102         s->ctx->samr.access_mask = 0;
103         ZERO_STRUCT(s->ctx->samr.handle);
104
105         /* preparing parameters for samr_Connect rpc call */
106         s->connect.in.system_name      = 0;
107         s->connect.in.access_mask      = s->access_mask;
108         s->connect.out.connect_handle  = &s->connect_handle;
109         
110         /* send request */
111         s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
112         if (s->req == NULL) return NT_STATUS_NO_MEMORY;
113
114         /* callback handler */
115         s->req->async.callback = domain_open_handler;
116         s->req->async.private  = c;
117         s->stage = DOMOPEN_CONNECT;
118         
119         return NT_STATUS_OK;
120 }
121
122
123 /**
124  * Stage 1: Connect to SAM server.
125  */
126 static NTSTATUS domain_open_connect(struct composite_context *c,
127                                     struct domain_open_samr_state *s)
128 {
129         struct samr_LookupDomain *r = &s->lookup;
130
131         /* receive samr_Connect reply */
132         c->status = dcerpc_ndr_request_recv(s->req);
133         NT_STATUS_NOT_OK_RETURN(c->status);
134
135         /* prepare for samr_LookupDomain call */
136         r->in.connect_handle = &s->connect_handle;
137         r->in.domain_name    = &s->domain_name;
138
139         s->req = dcerpc_samr_LookupDomain_send(s->pipe, c, r);
140         if (s->req == NULL) goto failure;
141
142         s->req->async.callback = domain_open_handler;
143         s->req->async.private  = c;
144         s->stage = DOMOPEN_LOOKUP;
145
146         return NT_STATUS_OK;
147
148 failure:
149         return NT_STATUS_UNSUCCESSFUL;
150 }
151
152
153 /**
154  * Stage 2: Lookup domain by name.
155  */
156 static NTSTATUS domain_open_lookup(struct composite_context *c,
157                                    struct domain_open_samr_state *s)
158 {
159         struct samr_OpenDomain *r = &s->open;
160
161         /* receive samr_LookupDomain reply */
162         c->status = dcerpc_ndr_request_recv(s->req);
163         NT_STATUS_NOT_OK_RETURN(c->status);
164
165         /* prepare for samr_OpenDomain call */
166         r->in.connect_handle = &s->connect_handle;
167         r->in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
168         r->in.sid            = s->lookup.out.sid;
169         r->out.domain_handle = &s->domain_handle;
170
171         s->req = dcerpc_samr_OpenDomain_send(s->pipe, c, r);
172         if (s->req == NULL) goto failure;
173
174         s->req->async.callback = domain_open_handler;
175         s->req->async.private  = c;
176         s->stage = DOMOPEN_OPEN;
177
178         return NT_STATUS_OK;
179
180 failure:
181         return NT_STATUS_UNSUCCESSFUL;
182 }
183
184
185 /*
186  * Stage 3: Open domain.
187  */
188 static NTSTATUS domain_open_open(struct composite_context *c,
189                                  struct domain_open_samr_state *s)
190 {
191         /* receive samr_OpenDomain reply */
192         c->status = dcerpc_ndr_request_recv(s->req);
193         NT_STATUS_NOT_OK_RETURN(c->status);
194
195         c->state = COMPOSITE_STATE_DONE;
196         
197         return NT_STATUS_OK;
198 }
199
200
201 /**
202  * Event handler for asynchronous request. Handles transition through
203  * intermediate stages of the call.
204  *
205  * @param req rpc call context
206  */
207 static void domain_open_handler(struct rpc_request *req)
208 {
209         struct composite_context *c = req->async.private;
210         struct domain_open_samr_state *s = talloc_get_type(c->private_data,
211                                                            struct domain_open_samr_state);
212
213         /* Stages of the call */
214         switch (s->stage) {
215         case DOMOPEN_CONNECT:
216                 c->status = domain_open_connect(c, s);
217                 break;
218         case DOMOPEN_LOOKUP:
219                 c->status = domain_open_lookup(c, s);
220                 break;
221         case DOMOPEN_OPEN:
222                 c->status = domain_open_open(c, s);
223                 break;
224         case DOMOPEN_CLOSE_EXISTING:
225                 c->status = domain_open_close(c, s);
226                 break;
227         case DOMOPEN_RPC_CONNECT:
228                 /* this state shouldn't be handled here */
229                 c->status = NT_STATUS_UNSUCCESSFUL;
230                 break;
231         }
232
233         if (!NT_STATUS_IS_OK(c->status)) {
234                 c->state = COMPOSITE_STATE_ERROR;
235         }
236
237         if (c->state == COMPOSITE_STATE_DONE) {
238                 composite_done(c);
239         }
240 }
241
242
243 /**
244  * Sends asynchronous DomainOpenSamr request
245  *
246  * @param ctx initialised libnet context
247  * @param io arguments and results of the call
248  * @param monitor pointer to monitor function that is passed monitor message
249  */
250
251 struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
252                                                      struct libnet_DomainOpen *io,
253                                                      void (*monitor)(struct monitor_msg*))
254 {
255         struct composite_context *c;
256         struct domain_open_samr_state *s;
257
258         c = composite_create(ctx, ctx->event_ctx);
259         if (c == NULL) return NULL;
260
261         s = talloc_zero(c, struct domain_open_samr_state);
262         if (composite_nomem(s, c)) return c;
263
264         c->private_data = s;
265         s->monitor_fn   = monitor;
266
267         s->ctx                 = ctx;
268         s->pipe                = ctx->samr.pipe;
269         s->access_mask         = io->in.access_mask;
270         s->domain_name.string  = talloc_strdup(c, io->in.domain_name);
271
272         /* check, if there's samr pipe opened already, before opening a domain */
273         if (ctx->samr.pipe == NULL) {
274
275                 /* attempting to connect a domain controller */
276                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
277                 s->rpcconn.in.name         = io->in.domain_name;
278                 s->rpcconn.in.dcerpc_iface = &dcerpc_table_samr;
279                 
280                 /* send rpc pipe connect request */
281                 s->rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn);
282                 if (composite_nomem(s->rpcconn_req, c)) return c;
283
284                 s->rpcconn_req->async.fn = domain_open_rpc_connect;
285                 s->rpcconn_req->async.private_data  = c;
286                 s->stage = DOMOPEN_RPC_CONNECT;
287
288                 return c;
289         }
290
291         /* libnet context's domain handle is not empty, so check out what
292            was opened first, before doing anything */
293         if (!policy_handle_empty(&ctx->samr.handle)) {
294                 if (strequal(ctx->samr.name, io->in.domain_name) &&
295                     ctx->samr.access_mask == io->in.access_mask) {
296
297                         /* this domain is already opened */
298                         composite_done(c);
299                         return c;
300
301                 } else {
302                         /* another domain or access rights have been
303                            requested - close the existing handle first */
304                         s->close.in.handle = &ctx->samr.handle;
305
306                         /* send request to close domain handle */
307                         s->req = dcerpc_samr_Close_send(s->pipe, c, &s->close);
308                         if (composite_nomem(s->req, c)) return c;
309
310                         /* callback handler */
311                         s->req->async.callback = domain_open_handler;
312                         s->req->async.private  = c;
313                         s->stage = DOMOPEN_CLOSE_EXISTING;
314
315                         return c;
316                 }
317         }
318
319         /* preparing parameters for samr_Connect rpc call */
320         s->connect.in.system_name      = 0;
321         s->connect.in.access_mask      = s->access_mask;
322         s->connect.out.connect_handle  = &s->connect_handle;
323         
324         /* send request */
325         s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
326         if (composite_nomem(s->req, c)) return c;
327
328         /* callback handler */
329         s->req->async.callback = domain_open_handler;
330         s->req->async.private  = c;
331         s->stage = DOMOPEN_CONNECT;
332
333         return c;
334 }
335
336
337 /**
338  * Waits for and receives result of asynchronous DomainOpenSamr call
339  * 
340  * @param c composite context returned by asynchronous DomainOpen call
341  * @param ctx initialised libnet context
342  * @param mem_ctx memory context of the call
343  * @param io pointer to results (and arguments) of the call
344  * @return nt status code of execution
345  */
346
347 NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
348                                     TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
349 {
350         NTSTATUS status;
351         struct domain_open_samr_state *s;
352
353         /* wait for results of sending request */
354         status = composite_wait(c);
355         
356         if (NT_STATUS_IS_OK(status) && io) {
357                 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
358                 io->out.domain_handle = s->domain_handle;
359
360                 /* store the resulting handle and related data for use by other
361                    libnet functions */
362                 ctx->samr.handle      = s->domain_handle;
363                 ctx->samr.name        = talloc_steal(ctx, s->domain_name.string);
364                 ctx->samr.access_mask = s->access_mask;
365         }
366
367         talloc_free(c);
368         return status;
369 }
370
371
372 struct domain_open_lsa_state {
373         const char *name;
374         uint32_t access_mask;
375         struct libnet_context *ctx;
376         struct libnet_RpcConnect rpcconn;
377         struct lsa_OpenPolicy2   openpol;
378         struct policy_handle handle;
379         struct dcerpc_pipe *pipe;
380
381         /* information about the progress */
382         void (*monitor_fn)(struct monitor_msg*);
383 };
384
385
386 static void continue_rpc_connect_lsa(struct composite_context *ctx);
387 static void continue_lsa_policy_open(struct rpc_request *req);
388
389
390 /**
391  * Sends asynchronous DomainOpenLsa request
392  *
393  * @param ctx initialised libnet context
394  * @param io arguments and results of the call
395  * @param monitor pointer to monitor function that is passed monitor message
396  */
397
398 struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
399                                                     struct libnet_DomainOpen *io,
400                                                     void (*monitor)(struct monitor_msg*))
401 {
402         struct composite_context *c;
403         struct domain_open_lsa_state *s;
404         struct composite_context *rpcconn_req;
405         struct rpc_request *openpol_req;
406         struct lsa_QosInfo *qos;
407
408         /* create composite context and state */
409         c = composite_create(ctx, ctx->event_ctx);
410         if (c == NULL) return c;
411
412         s = talloc_zero(c, struct domain_open_lsa_state);
413         if (composite_nomem(s, c)) return c;
414
415         c->private_data = s;
416
417         /* store arguments in the state structure */
418         s->name         = talloc_strdup(c, io->in.domain_name);
419         s->access_mask  = io->in.access_mask;
420         s->ctx          = ctx;
421
422         /* check, if there's lsa pipe opened already, before opening a handle */
423         if (ctx->lsa.pipe == NULL) {
424
425                 /* attempting to connect a domain controller */
426                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
427                 s->rpcconn.in.name         = talloc_strdup(c, io->in.domain_name);
428                 s->rpcconn.in.dcerpc_iface = &dcerpc_table_lsarpc;
429                 
430                 /* send rpc pipe connect request */
431                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn);
432                 if (composite_nomem(rpcconn_req, c)) return c;
433
434                 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
435                 return c;
436         }
437
438         s->pipe = ctx->lsa.pipe;
439
440         /* preparing parameters for lsa_OpenPolicy2 rpc call */
441         s->openpol.in.system_name = s->name;
442         s->openpol.in.access_mask = s->access_mask;
443         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
444
445         qos = talloc_zero(c, struct lsa_QosInfo);
446         qos->len                 = 0;
447         qos->impersonation_level = 2;
448         qos->context_mode        = 1;
449         qos->effective_only      = 0;
450
451         s->openpol.in.attr->sec_qos = qos;
452         s->openpol.out.handle       = &s->handle;
453         
454         /* send rpc request */
455         openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
456         if (composite_nomem(openpol_req, c)) return c;
457
458         composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
459         return c;
460 }
461
462
463 /*
464   Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
465  */
466 static void continue_rpc_connect_lsa(struct composite_context *ctx)
467 {
468         struct composite_context *c;
469         struct domain_open_lsa_state *s;
470         struct lsa_QosInfo *qos;
471         struct rpc_request *openpol_req;
472
473         c = talloc_get_type(ctx->async.private_data, struct composite_context);
474         s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
475
476         /* receive rpc connection */
477         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
478         if (!composite_is_ok(c)) return;
479
480         /* RpcConnect function leaves the pipe in libnet context,
481            so get it from there */
482         s->pipe = s->ctx->lsa.pipe;
483
484         /* prepare lsa_OpenPolicy2 call */
485         s->openpol.in.system_name = s->name;
486         s->openpol.in.access_mask = s->access_mask;
487         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
488
489         qos = talloc_zero(c, struct lsa_QosInfo);
490         qos->len                 = 0;
491         qos->impersonation_level = 2;
492         qos->context_mode        = 1;
493         qos->effective_only      = 0;
494
495         s->openpol.in.attr->sec_qos = qos;
496         s->openpol.out.handle       = &s->handle;
497
498         /* send rpc request */
499         openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
500         if (composite_nomem(openpol_req, c)) return;
501
502         composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
503 }
504
505
506 /*
507   Stage 1: Lsa policy opened - we're done, if successfully
508  */
509 static void continue_lsa_policy_open(struct rpc_request *req)
510 {
511         struct composite_context *c;
512         struct domain_open_lsa_state *s;
513
514         c = talloc_get_type(req->async.private, struct composite_context);
515         s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
516
517         c->status = dcerpc_ndr_request_recv(req);
518         if (!composite_is_ok(c)) return;
519
520         composite_done(c);
521 }
522
523
524 /**
525  * Receives result of asynchronous DomainOpenLsa call
526  *
527  * @param c composite context returned by asynchronous DomainOpenLsa call
528  * @param ctx initialised libnet context
529  * @param mem_ctx memory context of the call
530  * @param io pointer to results (and arguments) of the call
531  * @return nt status code of execution
532  */
533
534 NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
535                                    TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
536 {
537         NTSTATUS status;
538         struct domain_open_lsa_state *s;
539
540         status = composite_wait(c);
541
542         if (NT_STATUS_IS_OK(status) && io) {
543                 /* everything went fine - get the results and
544                    return the error string */
545                 s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
546                 io->out.domain_handle = s->handle;
547
548                 ctx->lsa.handle      = s->handle;
549                 ctx->lsa.name        = talloc_steal(ctx, s->name);
550                 ctx->lsa.access_mask = s->access_mask;
551                 
552                 io->out.error_string = talloc_strdup(mem_ctx, "Success");
553
554         } else if (!NT_STATUS_IS_OK(status)) {
555                 /* there was an error, so provide nt status code description */
556                 io->out.error_string = talloc_asprintf(mem_ctx,
557                                                        "Failed to open domain: %s",
558                                                        nt_errstr(status));
559         }
560
561         talloc_free(c);
562         return status;
563 }
564
565
566 /**
567  * Sends a request to open a domain in desired service
568  *
569  * @param ctx initalised libnet context
570  * @param io arguments and results of the call
571  * @param monitor pointer to monitor function that is passed monitor message
572  */
573
574 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
575                                                  struct libnet_DomainOpen *io,
576                                                  void (*monitor)(struct monitor_msg*))
577 {
578         struct composite_context *c;
579
580         switch (io->in.type) {
581         case DOMAIN_LSA:
582                 /* reques to open a policy handle on \pipe\lsarpc */
583                 c = libnet_DomainOpenLsa_send(ctx, io, monitor);
584                 break;
585
586         case DOMAIN_SAMR:
587         default:
588                 /* request to open a domain policy handle on \pipe\samr */
589                 c = libnet_DomainOpenSamr_send(ctx, io, monitor);
590                 break;
591         }
592
593         return c;
594 }
595
596
597 /**
598  * Receive result of domain open request
599  *
600  * @param c composite context returned by DomainOpen_send function
601  * @param ctx initialised libnet context
602  * @param mem_ctx memory context of the call
603  * @param io results and arguments of the call
604  */
605
606 NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
607                                 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
608 {
609         NTSTATUS status;
610
611         switch (io->in.type) {
612         case DOMAIN_LSA:
613                 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
614                 break;
615
616         case DOMAIN_SAMR:
617         default:
618                 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
619                 break;
620         }
621         
622         return status;
623 }
624
625
626 /**
627  * Synchronous version of DomainOpen call
628  *
629  * @param ctx initialised libnet context
630  * @param mem_ctx memory context for the call
631  * @param io arguments and results of the call
632  * @return nt status code of execution
633  */
634
635 NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
636                            TALLOC_CTX *mem_ctx,
637                            struct libnet_DomainOpen *io)
638 {
639         struct composite_context *c = libnet_DomainOpen_send(ctx, io, NULL);
640         return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
641 }
642
643
644 struct domain_close_lsa_state {
645         struct dcerpc_pipe *pipe;
646         struct lsa_Close close;
647         struct policy_handle handle;
648
649         void (*monitor_fn)(struct monitor_msg*);
650 };
651
652
653 static void continue_lsa_close(struct rpc_request *req);
654
655
656 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
657                                                      struct libnet_DomainClose *io,
658                                                      void (*monitor)(struct monitor_msg*))
659 {
660         struct composite_context *c;
661         struct domain_close_lsa_state *s;
662         struct rpc_request *close_req;
663
664         /* composite context and state structure allocation */
665         c = composite_create(ctx, ctx->event_ctx);
666         if (c == NULL) return c;
667
668         s = talloc_zero(c, struct domain_close_lsa_state);
669         if (composite_nomem(s, c)) return c;
670
671         c->private_data = s;
672         s->monitor_fn   = monitor;
673
674         /* TODO: check if lsa pipe pointer is non-null */
675
676         if (!strequal(ctx->lsa.name, io->in.domain_name)) {
677                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
678                 return c;
679         }
680
681         /* get opened lsarpc pipe pointer */
682         s->pipe = ctx->lsa.pipe;
683         
684         /* prepare close handle call arguments */
685         s->close.in.handle  = &ctx->lsa.handle;
686         s->close.out.handle = &s->handle;
687
688         /* send the request */
689         close_req = dcerpc_lsa_Close_send(s->pipe, c, &s->close);
690         if (composite_nomem(close_req, c)) return c;
691
692         composite_continue_rpc(c, close_req, continue_lsa_close, c);
693         return c;
694 }
695
696
697 /*
698   Stage 1: Receive result of lsa close call
699 */
700 static void continue_lsa_close(struct rpc_request *req)
701 {
702         struct composite_context *c;
703         struct domain_close_lsa_state *s;
704         
705         c = talloc_get_type(req->async.private, struct composite_context);
706         s = talloc_get_type(c->private_data, struct domain_close_lsa_state);
707
708         c->status = dcerpc_ndr_request_recv(req);
709         if (!composite_is_ok(c)) return;
710
711         composite_done(c);
712 }
713
714
715 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
716                                     TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
717 {
718         NTSTATUS status;
719
720         status = composite_wait(c);
721
722         if (NT_STATUS_IS_OK(status) && io) {
723                 /* policy handle closed successfully */
724
725                 ctx->lsa.name = NULL;
726                 ZERO_STRUCT(ctx->lsa.handle);
727
728                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
729
730         } else if (!NT_STATUS_IS_OK(status)) {
731                 /* there was an error, so return description of the status code */
732                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
733         }
734
735         talloc_free(c);
736         return status;
737 }
738
739
740 struct domain_close_samr_state {
741         struct samr_Close close;
742         struct policy_handle handle;
743         
744         void (*monitor_fn)(struct monitor_msg*);
745 };
746
747
748 static void continue_samr_close(struct rpc_request *req);
749
750
751 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
752                                                       struct libnet_DomainClose *io,
753                                                       void (*monitor)(struct monitor_msg*))
754 {
755         struct composite_context *c;
756         struct domain_close_samr_state *s;
757         struct rpc_request *close_req;
758
759         /* composite context and state structure allocation */
760         c = composite_create(ctx, ctx->event_ctx);
761         if (c == NULL) return c;
762
763         s = talloc_zero(c, struct domain_close_samr_state);
764         if (composite_nomem(s, c)) return c;
765
766         c->private_data = s;
767         s->monitor_fn   = monitor;
768
769         /* TODO: check if samr pipe pointer is non-null */
770
771         if (!strequal(ctx->samr.name, io->in.domain_name)) {
772                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
773                 return c;
774         }
775
776         /* prepare close domain handle call arguments */
777         ZERO_STRUCT(s->close);
778         s->close.in.handle  = &ctx->samr.handle;
779         s->close.out.handle = &s->handle;
780
781         /* send the request */
782         close_req = dcerpc_samr_Close_send(ctx->samr.pipe, ctx, &s->close);
783         if (composite_nomem(close_req, c)) return c;
784
785         composite_continue_rpc(c, close_req, continue_samr_close, c);
786         return c;
787 }
788
789
790 /*
791   Stage 1: Receive result of samr close call
792 */
793 static void continue_samr_close(struct rpc_request *req)
794 {
795         struct composite_context *c;
796         struct domain_close_samr_state *s;
797
798         c = talloc_get_type(req->async.private, struct composite_context);
799         s = talloc_get_type(c->private_data, struct domain_close_samr_state);
800         
801         c->status = dcerpc_ndr_request_recv(req);
802         if (!composite_is_ok(c)) return;
803         
804         composite_done(c);
805 }
806
807
808 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
809                                      TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
810 {
811         NTSTATUS status;
812
813         status = composite_wait(c);
814
815         if (NT_STATUS_IS_OK(status) && io) {
816                 /* domain policy handle closed successfully */
817
818                 ZERO_STRUCT(ctx->samr.handle);
819                 ctx->samr.name = NULL;
820
821                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
822
823         } else if (!NT_STATUS_IS_OK(status)) {
824                 /* there was an error, so return description of the status code */
825                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
826         }
827
828         talloc_free(c);
829         return status;
830 }
831
832
833 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
834                                                   struct libnet_DomainClose *io,
835                                                   void (*monitor)(struct monitor_msg*))
836 {
837         struct composite_context *c;
838
839         switch (io->in.type) {
840         case DOMAIN_LSA:
841                 /* request to close policy handle on \pipe\lsarpc */
842                 c = libnet_DomainCloseLsa_send(ctx, io, monitor);
843                 break;
844
845         case DOMAIN_SAMR:
846         default:
847                 /* request to close domain policy handle on \pipe\samr */
848                 c = libnet_DomainCloseSamr_send(ctx, io, monitor);
849                 break;
850         }
851         
852         return c;
853 }
854
855
856 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
857                                  TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
858 {
859         NTSTATUS status;
860
861         switch (io->in.type) {
862         case DOMAIN_LSA:
863                 /* receive result of closing lsa policy handle */
864                 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
865                 break;
866
867         case DOMAIN_SAMR:
868         default:
869                 /* receive result of closing samr domain policy handle */
870                 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
871                 break;
872         }
873         
874         return status;
875 }
876
877
878 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
879                             struct libnet_DomainClose *io)
880 {
881         struct composite_context *c;
882         
883         c = libnet_DomainClose_send(ctx, io, NULL);
884         return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
885 }