Fix an empty if statement.
[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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21   a composite function for domain handling on samr and lsa pipes
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libnet/libnet.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
28 #include "librpc/gen_ndr/ndr_lsa_c.h"
29
30
31 struct domain_open_samr_state {
32         struct libnet_context     *ctx;
33         struct dcerpc_pipe        *pipe;
34         struct libnet_RpcConnect  rpcconn;
35         struct samr_Connect       connect;
36         struct samr_LookupDomain  lookup;
37         struct samr_OpenDomain    open;
38         struct samr_Close         close;
39         struct lsa_String         domain_name;
40         uint32_t                  access_mask;
41         struct policy_handle      connect_handle;
42         struct policy_handle      domain_handle;
43         struct dom_sid2           *domain_sid;
44
45         /* information about the progress */
46         void (*monitor_fn)(struct monitor_msg*);
47 };
48
49
50 static void continue_domain_open_close(struct tevent_req *subreq);
51 static void continue_domain_open_connect(struct tevent_req *subreq);
52 static void continue_domain_open_lookup(struct tevent_req *subreq);
53 static void continue_domain_open_open(struct tevent_req *subreq);
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 tevent_req *subreq;
64
65         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
66         s = talloc_get_type_abort(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         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
80                                             s->pipe->binding_handle,
81                                             &s->connect);
82         if (composite_nomem(subreq, c)) return;
83
84         /* callback handler */
85         tevent_req_set_callback(subreq, continue_domain_open_connect, c);
86 }
87
88
89 /**
90  * Stage 0.5 (optional): Close existing (in libnet context) domain
91  * handle
92  */
93 static void continue_domain_open_close(struct tevent_req *subreq)
94 {
95         struct composite_context *c;
96         struct domain_open_samr_state *s;
97
98         c = tevent_req_callback_data(subreq, struct composite_context);
99         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
100
101         /* receive samr_Close reply */
102         c->status = dcerpc_samr_Close_r_recv(subreq, s);
103         TALLOC_FREE(subreq);
104         if (!composite_is_ok(c)) return;
105
106         if (s->monitor_fn) {
107                 struct monitor_msg msg;
108                 
109                 msg.type = mon_SamrClose;
110                 msg.data = NULL;
111                 msg.data_size = 0;
112                 s->monitor_fn(&msg);
113         }
114
115         /* reset domain handle and associated data in libnet_context */
116         s->ctx->samr.name        = NULL;
117         s->ctx->samr.access_mask = 0;
118         ZERO_STRUCT(s->ctx->samr.handle);
119
120         /* preparing parameters for samr_Connect rpc call */
121         s->connect.in.system_name      = 0;
122         s->connect.in.access_mask      = s->access_mask;
123         s->connect.out.connect_handle  = &s->connect_handle;
124         
125         /* send request */
126         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
127                                             s->pipe->binding_handle,
128                                             &s->connect);
129         if (composite_nomem(subreq, c)) return;
130
131         /* callback handler */
132         tevent_req_set_callback(subreq, continue_domain_open_connect, c);
133 }
134
135
136 /**
137  * Stage 1: Connect to SAM server.
138  */
139 static void continue_domain_open_connect(struct tevent_req *subreq)
140 {
141         struct composite_context *c;
142         struct domain_open_samr_state *s;
143         struct samr_LookupDomain *r;
144         
145         c = tevent_req_callback_data(subreq, struct composite_context);
146         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
147
148         /* receive samr_Connect reply */
149         c->status = dcerpc_samr_Connect_r_recv(subreq, s);
150         TALLOC_FREE(subreq);
151         if (!composite_is_ok(c)) return;
152
153         if (s->monitor_fn) {
154                 struct monitor_msg msg;
155
156                 msg.type = mon_SamrConnect;
157                 msg.data = NULL;
158                 msg.data_size = 0;
159                 s->monitor_fn(&msg);
160         }
161
162         r = &s->lookup;
163
164         /* prepare for samr_LookupDomain call */
165         r->in.connect_handle = &s->connect_handle;
166         r->in.domain_name    = &s->domain_name;
167         r->out.sid           = talloc(s, struct dom_sid2 *);
168         if (composite_nomem(r->out.sid, c)) return;
169
170         subreq = dcerpc_samr_LookupDomain_r_send(s, c->event_ctx,
171                                                  s->pipe->binding_handle,
172                                                  r);
173         if (composite_nomem(subreq, c)) return;
174
175         tevent_req_set_callback(subreq, continue_domain_open_lookup, c);
176 }
177
178
179 /**
180  * Stage 2: Lookup domain by name.
181  */
182 static void continue_domain_open_lookup(struct tevent_req *subreq)
183 {
184         struct composite_context *c;
185         struct domain_open_samr_state *s;
186         struct samr_OpenDomain *r;
187
188         c = tevent_req_callback_data(subreq, struct composite_context);
189         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
190         
191         /* receive samr_LookupDomain reply */
192         c->status = dcerpc_samr_LookupDomain_r_recv(subreq, s);
193         TALLOC_FREE(subreq);
194
195         if (s->monitor_fn) {
196                 struct monitor_msg msg;
197                 struct msg_rpc_lookup_domain data;
198
199                 data.domain_name = s->domain_name.string;
200
201                 msg.type = mon_SamrLookupDomain;
202                 msg.data = (void*)&data;
203                 msg.data_size = sizeof(data);
204                 s->monitor_fn(&msg);
205         }
206
207         r = &s->open;
208
209         /* check the rpc layer status */
210         if (!composite_is_ok(c)) return;
211
212         /* check the rpc call itself status */
213         if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
214                 composite_error(c, s->lookup.out.result);
215                 return;
216         }
217
218         /* prepare for samr_OpenDomain call */
219         r->in.connect_handle = &s->connect_handle;
220         r->in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
221         r->in.sid            = *s->lookup.out.sid;
222         r->out.domain_handle = &s->domain_handle;
223
224         subreq = dcerpc_samr_OpenDomain_r_send(s, c->event_ctx,
225                                                s->pipe->binding_handle,
226                                                r);
227         if (composite_nomem(subreq, c)) return;
228
229         tevent_req_set_callback(subreq, continue_domain_open_open, c);
230 }
231
232
233 /*
234  * Stage 3: Open domain.
235  */
236 static void continue_domain_open_open(struct tevent_req *subreq)
237 {
238         struct composite_context *c;
239         struct domain_open_samr_state *s;
240
241         c = tevent_req_callback_data(subreq, struct composite_context);
242         s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
243
244         /* receive samr_OpenDomain reply */
245         c->status = dcerpc_samr_OpenDomain_r_recv(subreq, s);
246         TALLOC_FREE(subreq);
247         if (!composite_is_ok(c)) return;
248
249         if (s->monitor_fn) {
250                 struct monitor_msg msg;
251                 
252                 msg.type = mon_SamrOpenDomain;
253                 msg.data = NULL;
254                 msg.data_size = 0;
255                 s->monitor_fn(&msg);
256         }
257
258         composite_done(c);
259 }
260
261
262 /**
263  * Sends asynchronous DomainOpenSamr request
264  *
265  * @param ctx initialised libnet context
266  * @param io arguments and results of the call
267  * @param monitor pointer to monitor function that is passed monitor message
268  */
269
270 struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
271                                                      TALLOC_CTX *mem_ctx,
272                                                      struct libnet_DomainOpen *io,
273                                                      void (*monitor)(struct monitor_msg*))
274 {
275         struct composite_context *c;
276         struct domain_open_samr_state *s;
277         struct composite_context *rpcconn_req;
278         struct tevent_req *subreq;
279
280         c = composite_create(mem_ctx, ctx->event_ctx);
281         if (c == NULL) return NULL;
282
283         s = talloc_zero(c, struct domain_open_samr_state);
284         if (composite_nomem(s, c)) return c;
285
286         c->private_data = s;
287         s->monitor_fn   = monitor;
288
289         s->ctx                 = ctx;
290         s->pipe                = ctx->samr.pipe;
291         s->access_mask         = io->in.access_mask;
292         s->domain_name.string  = talloc_strdup(c, io->in.domain_name);
293
294         /* check, if there's samr pipe opened already, before opening a domain */
295         if (ctx->samr.pipe == NULL) {
296
297                 /* attempting to connect a domain controller */
298                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
299                 s->rpcconn.in.name         = io->in.domain_name;
300                 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
301                 
302                 /* send rpc pipe connect request */
303                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
304                 if (composite_nomem(rpcconn_req, c)) return c;
305
306                 composite_continue(c, rpcconn_req, continue_domain_open_rpc_connect, c);
307                 return c;
308         }
309
310         /* libnet context's domain handle is not empty, so check out what
311            was opened first, before doing anything */
312         if (!ndr_policy_handle_empty(&ctx->samr.handle)) {
313                 if (strequal(ctx->samr.name, io->in.domain_name) &&
314                     ctx->samr.access_mask == io->in.access_mask) {
315
316                         /* this domain is already opened */
317                         composite_done(c);
318                         return c;
319
320                 } else {
321                         /* another domain or access rights have been
322                            requested - close the existing handle first */
323                         s->close.in.handle = &ctx->samr.handle;
324
325                         /* send request to close domain handle */
326                         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
327                                                           s->pipe->binding_handle,
328                                                           &s->close);
329                         if (composite_nomem(subreq, c)) return c;
330
331                         /* callback handler */
332                         tevent_req_set_callback(subreq, continue_domain_open_close, c);
333                         return c;
334                 }
335         }
336
337         /* preparing parameters for samr_Connect rpc call */
338         s->connect.in.system_name      = 0;
339         s->connect.in.access_mask      = s->access_mask;
340         s->connect.out.connect_handle  = &s->connect_handle;
341         
342         /* send request */
343         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
344                                             s->pipe->binding_handle,
345                                             &s->connect);
346         if (composite_nomem(subreq, c)) return c;
347
348         /* callback handler */
349         tevent_req_set_callback(subreq, continue_domain_open_connect, c);
350         return c;
351 }
352
353
354 /**
355  * Waits for and receives result of asynchronous DomainOpenSamr call
356  * 
357  * @param c composite context returned by asynchronous DomainOpen call
358  * @param ctx initialised libnet context
359  * @param mem_ctx memory context of the call
360  * @param io pointer to results (and arguments) of the call
361  * @return nt status code of execution
362  */
363
364 NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
365                                     TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
366 {
367         NTSTATUS status;
368         struct domain_open_samr_state *s;
369
370         /* wait for results of sending request */
371         status = composite_wait(c);
372         
373         if (NT_STATUS_IS_OK(status) && io) {
374                 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
375                 io->out.domain_handle = s->domain_handle;
376
377                 /* store the resulting handle and related data for use by other
378                    libnet functions */
379                 ctx->samr.connect_handle = s->connect_handle;
380                 ctx->samr.handle      = s->domain_handle;
381                 ctx->samr.sid         = talloc_steal(ctx, *s->lookup.out.sid);
382                 ctx->samr.name        = talloc_steal(ctx, s->domain_name.string);
383                 ctx->samr.access_mask = s->access_mask;
384         }
385
386         talloc_free(c);
387         return status;
388 }
389
390
391 struct domain_open_lsa_state {
392         const char *name;
393         uint32_t access_mask;
394         struct libnet_context *ctx;
395         struct libnet_RpcConnect rpcconn;
396         struct lsa_OpenPolicy2   openpol;
397         struct policy_handle handle;
398         struct dcerpc_pipe *pipe;
399
400         /* information about the progress */
401         void (*monitor_fn)(struct monitor_msg*);
402 };
403
404
405 static void continue_rpc_connect_lsa(struct composite_context *ctx);
406 static void continue_lsa_policy_open(struct tevent_req *subreq);
407
408
409 /**
410  * Sends asynchronous DomainOpenLsa request
411  *
412  * @param ctx initialised libnet context
413  * @param io arguments and results of the call
414  * @param monitor pointer to monitor function that is passed monitor message
415  */
416
417 struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
418                                                     TALLOC_CTX *mem_ctx,
419                                                     struct libnet_DomainOpen *io,
420                                                     void (*monitor)(struct monitor_msg*))
421 {
422         struct composite_context *c;
423         struct domain_open_lsa_state *s;
424         struct composite_context *rpcconn_req;
425         struct tevent_req *subreq;
426         struct lsa_QosInfo *qos;
427
428         /* create composite context and state */
429         c = composite_create(mem_ctx, ctx->event_ctx);
430         if (c == NULL) return c;
431
432         s = talloc_zero(c, struct domain_open_lsa_state);
433         if (composite_nomem(s, c)) return c;
434
435         c->private_data = s;
436
437         /* store arguments in the state structure */
438         s->name         = talloc_strdup(c, io->in.domain_name);
439         s->access_mask  = io->in.access_mask;
440         s->ctx          = ctx;
441
442         /* check, if there's lsa pipe opened already, before opening a handle */
443         if (ctx->lsa.pipe == NULL) {
444
445                 ZERO_STRUCT(s->rpcconn);
446
447                 /* attempting to connect a domain controller */
448                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
449                 s->rpcconn.in.name         = talloc_strdup(c, io->in.domain_name);
450                 s->rpcconn.in.dcerpc_iface = &ndr_table_lsarpc;
451                 
452                 /* send rpc pipe connect request */
453                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
454                 if (composite_nomem(rpcconn_req, c)) return c;
455
456                 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
457                 return c;
458         }
459
460         s->pipe = ctx->lsa.pipe;
461
462         /* preparing parameters for lsa_OpenPolicy2 rpc call */
463         s->openpol.in.system_name = s->name;
464         s->openpol.in.access_mask = s->access_mask;
465         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
466
467         qos = talloc_zero(c, struct lsa_QosInfo);
468         qos->len                 = 0;
469         qos->impersonation_level = 2;
470         qos->context_mode        = 1;
471         qos->effective_only      = 0;
472
473         s->openpol.in.attr->sec_qos = qos;
474         s->openpol.out.handle       = &s->handle;
475         
476         /* send rpc request */
477         subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
478                                                s->pipe->binding_handle,
479                                                &s->openpol);
480         if (composite_nomem(subreq, c)) return c;
481
482         tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
483         return c;
484 }
485
486
487 /*
488   Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
489  */
490 static void continue_rpc_connect_lsa(struct composite_context *ctx)
491 {
492         struct composite_context *c;
493         struct domain_open_lsa_state *s;
494         struct lsa_QosInfo *qos;
495         struct tevent_req *subreq;
496
497         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
498         s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
499
500         /* receive rpc connection */
501         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
502         if (!composite_is_ok(c)) return;
503
504         /* RpcConnect function leaves the pipe in libnet context,
505            so get it from there */
506         s->pipe = s->ctx->lsa.pipe;
507
508         /* prepare lsa_OpenPolicy2 call */
509         s->openpol.in.system_name = s->name;
510         s->openpol.in.access_mask = s->access_mask;
511         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
512
513         qos = talloc_zero(c, struct lsa_QosInfo);
514         qos->len                 = 0;
515         qos->impersonation_level = 2;
516         qos->context_mode        = 1;
517         qos->effective_only      = 0;
518
519         s->openpol.in.attr->sec_qos = qos;
520         s->openpol.out.handle       = &s->handle;
521
522         /* send rpc request */
523         subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
524                                                s->pipe->binding_handle,
525                                                &s->openpol);
526         if (composite_nomem(subreq, c)) return;
527
528         tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
529 }
530
531
532 /*
533   Stage 1: Lsa policy opened - we're done, if successfully
534  */
535 static void continue_lsa_policy_open(struct tevent_req *subreq)
536 {
537         struct composite_context *c;
538         struct domain_open_lsa_state *s;
539
540         c = tevent_req_callback_data(subreq, struct composite_context);
541         s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
542
543         c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
544         TALLOC_FREE(subreq);
545         if (!composite_is_ok(c)) return;
546
547         if (s->monitor_fn) {
548                 struct monitor_msg msg;
549                 
550                 msg.type      = mon_LsaOpenPolicy;
551                 msg.data      = NULL;
552                 msg.data_size = 0;
553                 s->monitor_fn(&msg);
554         }
555
556         composite_done(c);
557 }
558
559
560 /**
561  * Receives result of asynchronous DomainOpenLsa call
562  *
563  * @param c composite context returned by asynchronous DomainOpenLsa call
564  * @param ctx initialised libnet context
565  * @param mem_ctx memory context of the call
566  * @param io pointer to results (and arguments) of the call
567  * @return nt status code of execution
568  */
569
570 NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
571                                    TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
572 {
573         NTSTATUS status;
574         struct domain_open_lsa_state *s;
575
576         status = composite_wait(c);
577
578         if (NT_STATUS_IS_OK(status) && io) {
579                 /* everything went fine - get the results and
580                    return the error string */
581                 s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
582                 io->out.domain_handle = s->handle;
583
584                 ctx->lsa.handle      = s->handle;
585                 ctx->lsa.name        = talloc_steal(ctx, s->name);
586                 ctx->lsa.access_mask = s->access_mask;
587                 
588                 io->out.error_string = talloc_strdup(mem_ctx, "Success");
589
590         } else if (!NT_STATUS_IS_OK(status)) {
591                 /* there was an error, so provide nt status code description */
592                 io->out.error_string = talloc_asprintf(mem_ctx,
593                                                        "Failed to open domain: %s",
594                                                        nt_errstr(status));
595         }
596
597         talloc_free(c);
598         return status;
599 }
600
601
602 /**
603  * Sends a request to open a domain in desired service
604  *
605  * @param ctx initalised libnet context
606  * @param io arguments and results of the call
607  * @param monitor pointer to monitor function that is passed monitor message
608  */
609
610 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
611                                                  TALLOC_CTX *mem_ctx,
612                                                  struct libnet_DomainOpen *io,
613                                                  void (*monitor)(struct monitor_msg*))
614 {
615         struct composite_context *c;
616
617         switch (io->in.type) {
618         case DOMAIN_LSA:
619                 /* reques to open a policy handle on \pipe\lsarpc */
620                 c = libnet_DomainOpenLsa_send(ctx, mem_ctx, io, monitor);
621                 break;
622
623         case DOMAIN_SAMR:
624         default:
625                 /* request to open a domain policy handle on \pipe\samr */
626                 c = libnet_DomainOpenSamr_send(ctx, mem_ctx, io, monitor);
627                 break;
628         }
629
630         return c;
631 }
632
633
634 /**
635  * Receive result of domain open request
636  *
637  * @param c composite context returned by DomainOpen_send function
638  * @param ctx initialised libnet context
639  * @param mem_ctx memory context of the call
640  * @param io results and arguments of the call
641  */
642
643 NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
644                                 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
645 {
646         NTSTATUS status;
647
648         switch (io->in.type) {
649         case DOMAIN_LSA:
650                 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
651                 break;
652
653         case DOMAIN_SAMR:
654         default:
655                 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
656                 break;
657         }
658         
659         return status;
660 }
661
662
663 /**
664  * Synchronous version of DomainOpen call
665  *
666  * @param ctx initialised libnet context
667  * @param mem_ctx memory context for the call
668  * @param io arguments and results of the call
669  * @return nt status code of execution
670  */
671
672 NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
673                            TALLOC_CTX *mem_ctx,
674                            struct libnet_DomainOpen *io)
675 {
676         struct composite_context *c = libnet_DomainOpen_send(ctx, mem_ctx, io, NULL);
677         return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
678 }
679
680
681 struct domain_close_lsa_state {
682         struct dcerpc_pipe *pipe;
683         struct lsa_Close close;
684         struct policy_handle handle;
685
686         void (*monitor_fn)(struct monitor_msg*);
687 };
688
689
690 static void continue_lsa_close(struct tevent_req *subreq);
691
692
693 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
694                                                      TALLOC_CTX *mem_ctx,
695                                                      struct libnet_DomainClose *io,
696                                                      void (*monitor)(struct monitor_msg*))
697 {
698         struct composite_context *c;
699         struct domain_close_lsa_state *s;
700         struct tevent_req *subreq;
701
702         /* composite context and state structure allocation */
703         c = composite_create(mem_ctx, ctx->event_ctx);
704         if (c == NULL) return c;
705
706         s = talloc_zero(c, struct domain_close_lsa_state);
707         if (composite_nomem(s, c)) return c;
708
709         c->private_data = s;
710         s->monitor_fn   = monitor;
711
712         /* TODO: check if lsa pipe pointer is non-null */
713
714         if (!strequal(ctx->lsa.name, io->in.domain_name)) {
715                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
716                 return c;
717         }
718
719         /* get opened lsarpc pipe pointer */
720         s->pipe = ctx->lsa.pipe;
721         
722         /* prepare close handle call arguments */
723         s->close.in.handle  = &ctx->lsa.handle;
724         s->close.out.handle = &s->handle;
725
726         /* send the request */
727         subreq = dcerpc_lsa_Close_r_send(s, c->event_ctx,
728                                          s->pipe->binding_handle,
729                                          &s->close);
730         if (composite_nomem(subreq, c)) return c;
731
732         tevent_req_set_callback(subreq, continue_lsa_close, c);
733         return c;
734 }
735
736
737 /*
738   Stage 1: Receive result of lsa close call
739 */
740 static void continue_lsa_close(struct tevent_req *subreq)
741 {
742         struct composite_context *c;
743         struct domain_close_lsa_state *s;
744         
745         c = tevent_req_callback_data(subreq, struct composite_context);
746         s = talloc_get_type_abort(c->private_data, struct domain_close_lsa_state);
747
748         c->status = dcerpc_lsa_Close_r_recv(subreq, s);
749         TALLOC_FREE(subreq);
750         if (!composite_is_ok(c)) return;
751
752         if (s->monitor_fn) {
753                 struct monitor_msg msg;
754
755                 msg.type      = mon_LsaClose;
756                 msg.data      = NULL;
757                 msg.data_size = 0;
758                 s->monitor_fn(&msg);
759         }
760
761         composite_done(c);
762 }
763
764
765 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
766                                     TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
767 {
768         NTSTATUS status;
769
770         status = composite_wait(c);
771
772         if (NT_STATUS_IS_OK(status) && io) {
773                 /* policy handle closed successfully */
774
775                 ctx->lsa.name = NULL;
776                 ZERO_STRUCT(ctx->lsa.handle);
777
778                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
779
780         } else if (!NT_STATUS_IS_OK(status)) {
781                 /* there was an error, so return description of the status code */
782                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
783         }
784
785         talloc_free(c);
786         return status;
787 }
788
789
790 struct domain_close_samr_state {
791         struct samr_Close close;
792         struct policy_handle handle;
793         
794         void (*monitor_fn)(struct monitor_msg*);
795 };
796
797
798 static void continue_samr_close(struct tevent_req *subreq);
799
800
801 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
802                                                       TALLOC_CTX *mem_ctx,
803                                                       struct libnet_DomainClose *io,
804                                                       void (*monitor)(struct monitor_msg*))
805 {
806         struct composite_context *c;
807         struct domain_close_samr_state *s;
808         struct tevent_req *subreq;
809
810         /* composite context and state structure allocation */
811         c = composite_create(mem_ctx, ctx->event_ctx);
812         if (c == NULL) return c;
813
814         s = talloc_zero(c, struct domain_close_samr_state);
815         if (composite_nomem(s, c)) return c;
816
817         c->private_data = s;
818         s->monitor_fn   = monitor;
819
820         /* TODO: check if samr pipe pointer is non-null */
821
822         if (!strequal(ctx->samr.name, io->in.domain_name)) {
823                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
824                 return c;
825         }
826
827         /* prepare close domain handle call arguments */
828         ZERO_STRUCT(s->close);
829         s->close.in.handle  = &ctx->samr.handle;
830         s->close.out.handle = &s->handle;
831
832         /* send the request */
833         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
834                                           ctx->samr.pipe->binding_handle,
835                                           &s->close);
836         if (composite_nomem(subreq, c)) return c;
837
838         tevent_req_set_callback(subreq, continue_samr_close, c);
839         return c;
840 }
841
842
843 /*
844   Stage 1: Receive result of samr close call
845 */
846 static void continue_samr_close(struct tevent_req *subreq)
847 {
848         struct composite_context *c;
849         struct domain_close_samr_state *s;
850
851         c = tevent_req_callback_data(subreq, struct composite_context);
852         s = talloc_get_type_abort(c->private_data, struct domain_close_samr_state);
853         
854         c->status = dcerpc_samr_Close_r_recv(subreq, s);
855         TALLOC_FREE(subreq);
856         if (!composite_is_ok(c)) return;
857
858         if (s->monitor_fn) {
859                 struct monitor_msg msg;
860                 
861                 msg.type      = mon_SamrClose;
862                 msg.data      = NULL;
863                 msg.data_size = 0;
864                 s->monitor_fn(&msg);
865         }
866         
867         composite_done(c);
868 }
869
870
871 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
872                                      TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
873 {
874         NTSTATUS status;
875
876         status = composite_wait(c);
877
878         if (NT_STATUS_IS_OK(status) && io) {
879                 /* domain policy handle closed successfully */
880
881                 ZERO_STRUCT(ctx->samr.handle);
882                 talloc_free(discard_const_p(char, ctx->samr.name));
883                 talloc_free(ctx->samr.sid);
884                 ctx->samr.name = NULL;
885                 ctx->samr.sid = NULL;
886
887                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
888
889         } else if (!NT_STATUS_IS_OK(status)) {
890                 /* there was an error, so return description of the status code */
891                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
892         }
893
894         talloc_free(c);
895         return status;
896 }
897
898
899 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
900                                                   TALLOC_CTX *mem_ctx,
901                                                   struct libnet_DomainClose *io,
902                                                   void (*monitor)(struct monitor_msg*))
903 {
904         struct composite_context *c;
905
906         switch (io->in.type) {
907         case DOMAIN_LSA:
908                 /* request to close policy handle on \pipe\lsarpc */
909                 c = libnet_DomainCloseLsa_send(ctx, mem_ctx, io, monitor);
910                 break;
911
912         case DOMAIN_SAMR:
913         default:
914                 /* request to close domain policy handle on \pipe\samr */
915                 c = libnet_DomainCloseSamr_send(ctx, mem_ctx, io, monitor);
916                 break;
917         }
918         
919         return c;
920 }
921
922
923 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
924                                  TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
925 {
926         NTSTATUS status;
927
928         switch (io->in.type) {
929         case DOMAIN_LSA:
930                 /* receive result of closing lsa policy handle */
931                 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
932                 break;
933
934         case DOMAIN_SAMR:
935         default:
936                 /* receive result of closing samr domain policy handle */
937                 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
938                 break;
939         }
940         
941         return status;
942 }
943
944
945 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
946                             struct libnet_DomainClose *io)
947 {
948         struct composite_context *c;
949         
950         c = libnet_DomainClose_send(ctx, mem_ctx, io, NULL);
951         return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
952 }
953
954
955 struct domain_list_state {      
956         struct libnet_context *ctx;
957         struct libnet_RpcConnect rpcconn;
958         struct samr_Connect samrconn;
959         struct samr_EnumDomains enumdom;
960         struct samr_Close samrclose;
961         const char *hostname;
962         struct policy_handle connect_handle;
963         int buf_size;
964         struct domainlist *domains;
965         uint32_t resume_handle;
966         uint32_t count;
967
968         void (*monitor_fn)(struct monitor_msg*);
969 };
970
971
972 static void continue_rpc_connect(struct composite_context *c);
973 static void continue_samr_connect(struct tevent_req *subreq);
974 static void continue_samr_enum_domains(struct tevent_req *subreq);
975 static void continue_samr_close_handle(struct tevent_req *subreq);
976
977 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
978
979
980 /*
981   Stage 1: Receive connected rpc pipe and send connection
982   request to SAMR service
983 */
984 static void continue_rpc_connect(struct composite_context *ctx)
985 {
986         struct composite_context *c;
987         struct domain_list_state *s;
988         struct tevent_req *subreq;
989
990         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
991         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
992         
993         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
994         if (!composite_is_ok(c)) return;
995
996         s->samrconn.in.system_name     = 0;
997         s->samrconn.in.access_mask     = SEC_GENERIC_READ;     /* should be enough */
998         s->samrconn.out.connect_handle = &s->connect_handle;
999
1000         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
1001                                             s->ctx->samr.pipe->binding_handle,
1002                                             &s->samrconn);
1003         if (composite_nomem(subreq, c)) return;
1004
1005         tevent_req_set_callback(subreq, continue_samr_connect, c);
1006 }
1007
1008
1009 /*
1010   Stage 2: Receive policy handle to the connected SAMR service and issue
1011   a request to enumerate domain databases available
1012 */
1013 static void continue_samr_connect(struct tevent_req *subreq)
1014 {
1015         struct composite_context *c;
1016         struct domain_list_state *s;
1017
1018         c = tevent_req_callback_data(subreq, struct composite_context);
1019         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1020         
1021         c->status = dcerpc_samr_Connect_r_recv(subreq, s);
1022         TALLOC_FREE(subreq);
1023         if (!composite_is_ok(c)) return;
1024
1025         if (s->monitor_fn) {
1026                 struct monitor_msg msg;
1027                 
1028                 msg.type      = mon_SamrConnect;
1029                 msg.data      = NULL;
1030                 msg.data_size = 0;
1031                 s->monitor_fn(&msg);
1032         }
1033
1034         s->enumdom.in.connect_handle = &s->connect_handle;
1035         s->enumdom.in.resume_handle  = &s->resume_handle;
1036         s->enumdom.in.buf_size       = s->buf_size;
1037         s->enumdom.out.resume_handle = &s->resume_handle;
1038         s->enumdom.out.num_entries   = talloc(s, uint32_t);
1039         if (composite_nomem(s->enumdom.out.num_entries, c)) return;
1040         s->enumdom.out.sam           = talloc(s, struct samr_SamArray *);
1041         if (composite_nomem(s->enumdom.out.sam, c)) return;
1042
1043         subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
1044                                                 s->ctx->samr.pipe->binding_handle,
1045                                                 &s->enumdom);
1046         if (composite_nomem(subreq, c)) return;
1047
1048         tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1049 }
1050
1051
1052 /*
1053   Stage 3: Receive domain names available and repeat the request
1054   enumeration is not complete yet. Close samr connection handle
1055   upon completion.
1056 */
1057 static void continue_samr_enum_domains(struct tevent_req *subreq)
1058 {
1059         struct composite_context *c;
1060         struct domain_list_state *s;
1061
1062         c = tevent_req_callback_data(subreq, struct composite_context);
1063         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1064         
1065         c->status = dcerpc_samr_EnumDomains_r_recv(subreq, s);
1066         TALLOC_FREE(subreq);
1067         if (!composite_is_ok(c)) return;
1068
1069         if (s->monitor_fn) {
1070                 struct monitor_msg msg;
1071                 
1072                 msg.type      = mon_SamrEnumDomains;
1073                 msg.data      = NULL;
1074                 msg.data_size = 0;
1075                 s->monitor_fn(&msg);
1076         }
1077
1078         if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
1079
1080                 s->domains = get_domain_list(c, s);
1081
1082         } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
1083                 
1084                 s->domains = get_domain_list(c, s);
1085                 
1086                 /* prepare next round of enumeration */
1087                 s->enumdom.in.connect_handle = &s->connect_handle;
1088                 s->enumdom.in.resume_handle  = &s->resume_handle;
1089                 s->enumdom.in.buf_size       = s->ctx->samr.buf_size;
1090                 s->enumdom.out.resume_handle = &s->resume_handle;
1091
1092                 /* send the request */
1093                 subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
1094                                                         s->ctx->samr.pipe->binding_handle,
1095                                                         &s->enumdom);
1096                 if (composite_nomem(subreq, c)) return;
1097
1098                 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1099
1100         } else {
1101                 composite_error(c, s->enumdom.out.result);
1102                 return;
1103         }
1104
1105         /* close samr connection handle */
1106         s->samrclose.in.handle  = &s->connect_handle;
1107         s->samrclose.out.handle = &s->connect_handle;
1108         
1109         /* send the request */
1110         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
1111                                           s->ctx->samr.pipe->binding_handle,
1112                                           &s->samrclose);
1113         if (composite_nomem(subreq, c)) return;
1114
1115         tevent_req_set_callback(subreq, continue_samr_close_handle, c);
1116 }
1117
1118
1119 /*
1120   Stage 4: Receive result of closing samr connection handle.
1121 */
1122 static void continue_samr_close_handle(struct tevent_req *subreq)
1123 {
1124         struct composite_context *c;
1125         struct domain_list_state *s;
1126
1127         c = tevent_req_callback_data(subreq, struct composite_context);
1128         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1129
1130         c->status = dcerpc_samr_Close_r_recv(subreq, s);
1131         TALLOC_FREE(subreq);
1132         if (!composite_is_ok(c)) return;
1133
1134         if (s->monitor_fn) {
1135                 struct monitor_msg msg;
1136                 
1137                 msg.type      = mon_SamrClose;
1138                 msg.data      = NULL;
1139                 msg.data_size = 0;
1140                 s->monitor_fn(&msg);
1141         }
1142
1143         /* did everything go fine ? */
1144         if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
1145                 composite_error(c, s->samrclose.out.result);
1146                 return;
1147         }
1148
1149         composite_done(c);
1150 }
1151
1152
1153 /*
1154   Utility function to copy domain names from result of samr_EnumDomains call
1155 */
1156 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
1157 {
1158         uint32_t i;
1159         if (mem_ctx == NULL || s == NULL) return NULL;
1160
1161         /* prepare domains array */
1162         if (s->domains == NULL) {
1163                 s->domains = talloc_array(mem_ctx, struct domainlist,
1164                                           *s->enumdom.out.num_entries);
1165         } else {
1166                 s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
1167                                             s->count + *s->enumdom.out.num_entries);
1168         }
1169
1170         /* copy domain names returned from samr_EnumDomains call */
1171         for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
1172         {
1173                 struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
1174
1175                 /* strdup name as a child of allocated array to make it follow the array
1176                    in case of talloc_steal or talloc_free */
1177                 s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
1178                 s->domains[i].sid  = NULL;  /* this is to be filled out later */
1179         }
1180
1181         /* number of entries returned (domains enumerated) */
1182         s->count += *s->enumdom.out.num_entries;
1183         
1184         return s->domains;
1185 }
1186
1187
1188 /**
1189  * Sends a request to list domains on given host
1190  *
1191  * @param ctx initalised libnet context
1192  * @param mem_ctx memory context
1193  * @param io arguments and results of the call
1194  * @param monitor pointer to monitor function that is passed monitor messages
1195  */
1196
1197 struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
1198                                                  TALLOC_CTX *mem_ctx,
1199                                                  struct libnet_DomainList *io,
1200                                                  void (*monitor)(struct monitor_msg*))
1201 {
1202         struct composite_context *c;
1203         struct domain_list_state *s;
1204         struct composite_context *rpcconn_req;
1205         struct tevent_req *subreq;
1206
1207         /* composite context and state structure allocation */
1208         c = composite_create(ctx, ctx->event_ctx);
1209         if (c == NULL) return c;
1210
1211         s = talloc_zero(c, struct domain_list_state);
1212         if (composite_nomem(s, c)) return c;
1213
1214         c->private_data = s;
1215         s->monitor_fn   = monitor;
1216
1217         s->ctx      = ctx;
1218         s->hostname = talloc_strdup(c, io->in.hostname);
1219         if (composite_nomem(s->hostname, c)) return c;
1220
1221         /* check whether samr pipe has already been opened */
1222         if (ctx->samr.pipe == NULL) {
1223                 ZERO_STRUCT(s->rpcconn);
1224
1225                 /* prepare rpc connect call */
1226                 s->rpcconn.level           = LIBNET_RPC_CONNECT_SERVER;
1227                 s->rpcconn.in.name         = s->hostname;
1228                 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
1229
1230                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
1231                 if (composite_nomem(rpcconn_req, c)) return c;
1232                 
1233                 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
1234
1235         } else {
1236                 /* prepare samr_Connect call */
1237                 s->samrconn.in.system_name     = 0;
1238                 s->samrconn.in.access_mask     = SEC_GENERIC_READ;
1239                 s->samrconn.out.connect_handle = &s->connect_handle;
1240                 
1241                 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
1242                                                     s->ctx->samr.pipe->binding_handle,
1243                                                     &s->samrconn);
1244                 if (composite_nomem(subreq, c)) return c;
1245
1246                 tevent_req_set_callback(subreq, continue_samr_connect, c);
1247         }
1248
1249         return c;
1250 }
1251
1252
1253 /**
1254  * Receive result of domain list request
1255  *
1256  * @param c composite context returned by DomainList_send function
1257  * @param ctx initialised libnet context
1258  * @param mem_ctx memory context of the call
1259  * @param io results and arguments of the call
1260  */
1261
1262 NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
1263                                 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
1264 {
1265         NTSTATUS status;
1266         struct domain_list_state *s;
1267
1268         status = composite_wait(c);
1269
1270         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1271
1272         if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
1273                 /* fetch the results to be returned by io structure */
1274                 io->out.count        = s->count;
1275                 io->out.domains      = talloc_steal(mem_ctx, s->domains);
1276                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
1277
1278         } else if (!NT_STATUS_IS_OK(status)) {
1279                 /* there was an error, so return description of the status code */
1280                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1281         }
1282
1283         talloc_free(c);
1284         return status;
1285 }
1286
1287
1288 /**
1289  * Synchronous version of DomainList call
1290  *
1291  * @param ctx initialised libnet context
1292  * @param mem_ctx memory context for the call
1293  * @param io arguments and results of the call
1294  * @return nt status code of execution
1295  */
1296
1297 NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1298                            struct libnet_DomainList *io)
1299 {
1300         struct composite_context *c;
1301
1302         c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
1303         return libnet_DomainList_recv(c, ctx, mem_ctx, io);
1304 }