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