s4-libnet: Add mem_ctx to libnet_DomainOpen calls (bug #8889)
[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));
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                                                      struct libnet_DomainClose *io,
695                                                      void (*monitor)(struct monitor_msg*))
696 {
697         struct composite_context *c;
698         struct domain_close_lsa_state *s;
699         struct tevent_req *subreq;
700
701         /* composite context and state structure allocation */
702         c = composite_create(ctx, ctx->event_ctx);
703         if (c == NULL) return c;
704
705         s = talloc_zero(c, struct domain_close_lsa_state);
706         if (composite_nomem(s, c)) return c;
707
708         c->private_data = s;
709         s->monitor_fn   = monitor;
710
711         /* TODO: check if lsa pipe pointer is non-null */
712
713         if (!strequal(ctx->lsa.name, io->in.domain_name)) {
714                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
715                 return c;
716         }
717
718         /* get opened lsarpc pipe pointer */
719         s->pipe = ctx->lsa.pipe;
720         
721         /* prepare close handle call arguments */
722         s->close.in.handle  = &ctx->lsa.handle;
723         s->close.out.handle = &s->handle;
724
725         /* send the request */
726         subreq = dcerpc_lsa_Close_r_send(s, c->event_ctx,
727                                          s->pipe->binding_handle,
728                                          &s->close);
729         if (composite_nomem(subreq, c)) return c;
730
731         tevent_req_set_callback(subreq, continue_lsa_close, c);
732         return c;
733 }
734
735
736 /*
737   Stage 1: Receive result of lsa close call
738 */
739 static void continue_lsa_close(struct tevent_req *subreq)
740 {
741         struct composite_context *c;
742         struct domain_close_lsa_state *s;
743         
744         c = tevent_req_callback_data(subreq, struct composite_context);
745         s = talloc_get_type_abort(c->private_data, struct domain_close_lsa_state);
746
747         c->status = dcerpc_lsa_Close_r_recv(subreq, s);
748         TALLOC_FREE(subreq);
749         if (!composite_is_ok(c)) return;
750
751         if (s->monitor_fn) {
752                 struct monitor_msg msg;
753
754                 msg.type      = mon_LsaClose;
755                 msg.data      = NULL;
756                 msg.data_size = 0;
757                 s->monitor_fn(&msg);
758         }
759
760         composite_done(c);
761 }
762
763
764 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
765                                     TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
766 {
767         NTSTATUS status;
768
769         status = composite_wait(c);
770
771         if (NT_STATUS_IS_OK(status) && io) {
772                 /* policy handle closed successfully */
773
774                 ctx->lsa.name = NULL;
775                 ZERO_STRUCT(ctx->lsa.handle);
776
777                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
778
779         } else if (!NT_STATUS_IS_OK(status)) {
780                 /* there was an error, so return description of the status code */
781                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
782         }
783
784         talloc_free(c);
785         return status;
786 }
787
788
789 struct domain_close_samr_state {
790         struct samr_Close close;
791         struct policy_handle handle;
792         
793         void (*monitor_fn)(struct monitor_msg*);
794 };
795
796
797 static void continue_samr_close(struct tevent_req *subreq);
798
799
800 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
801                                                       struct libnet_DomainClose *io,
802                                                       void (*monitor)(struct monitor_msg*))
803 {
804         struct composite_context *c;
805         struct domain_close_samr_state *s;
806         struct tevent_req *subreq;
807
808         /* composite context and state structure allocation */
809         c = composite_create(ctx, ctx->event_ctx);
810         if (c == NULL) return c;
811
812         s = talloc_zero(c, struct domain_close_samr_state);
813         if (composite_nomem(s, c)) return c;
814
815         c->private_data = s;
816         s->monitor_fn   = monitor;
817
818         /* TODO: check if samr pipe pointer is non-null */
819
820         if (!strequal(ctx->samr.name, io->in.domain_name)) {
821                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
822                 return c;
823         }
824
825         /* prepare close domain handle call arguments */
826         ZERO_STRUCT(s->close);
827         s->close.in.handle  = &ctx->samr.handle;
828         s->close.out.handle = &s->handle;
829
830         /* send the request */
831         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
832                                           ctx->samr.pipe->binding_handle,
833                                           &s->close);
834         if (composite_nomem(subreq, c)) return c;
835
836         tevent_req_set_callback(subreq, continue_samr_close, c);
837         return c;
838 }
839
840
841 /*
842   Stage 1: Receive result of samr close call
843 */
844 static void continue_samr_close(struct tevent_req *subreq)
845 {
846         struct composite_context *c;
847         struct domain_close_samr_state *s;
848
849         c = tevent_req_callback_data(subreq, struct composite_context);
850         s = talloc_get_type_abort(c->private_data, struct domain_close_samr_state);
851         
852         c->status = dcerpc_samr_Close_r_recv(subreq, s);
853         TALLOC_FREE(subreq);
854         if (!composite_is_ok(c)) return;
855
856         if (s->monitor_fn) {
857                 struct monitor_msg msg;
858                 
859                 msg.type      = mon_SamrClose;
860                 msg.data      = NULL;
861                 msg.data_size = 0;
862                 s->monitor_fn(&msg);
863         }
864         
865         composite_done(c);
866 }
867
868
869 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
870                                      TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
871 {
872         NTSTATUS status;
873
874         status = composite_wait(c);
875
876         if (NT_STATUS_IS_OK(status) && io) {
877                 /* domain policy handle closed successfully */
878
879                 ZERO_STRUCT(ctx->samr.handle);
880                 talloc_free(discard_const_p(char, ctx->samr.name));
881                 talloc_free(ctx->samr.sid);
882                 ctx->samr.name = NULL;
883                 ctx->samr.sid = NULL;
884
885                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
886
887         } else if (!NT_STATUS_IS_OK(status)) {
888                 /* there was an error, so return description of the status code */
889                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
890         }
891
892         talloc_free(c);
893         return status;
894 }
895
896
897 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
898                                                   struct libnet_DomainClose *io,
899                                                   void (*monitor)(struct monitor_msg*))
900 {
901         struct composite_context *c;
902
903         switch (io->in.type) {
904         case DOMAIN_LSA:
905                 /* request to close policy handle on \pipe\lsarpc */
906                 c = libnet_DomainCloseLsa_send(ctx, io, monitor);
907                 break;
908
909         case DOMAIN_SAMR:
910         default:
911                 /* request to close domain policy handle on \pipe\samr */
912                 c = libnet_DomainCloseSamr_send(ctx, io, monitor);
913                 break;
914         }
915         
916         return c;
917 }
918
919
920 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
921                                  TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
922 {
923         NTSTATUS status;
924
925         switch (io->in.type) {
926         case DOMAIN_LSA:
927                 /* receive result of closing lsa policy handle */
928                 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
929                 break;
930
931         case DOMAIN_SAMR:
932         default:
933                 /* receive result of closing samr domain policy handle */
934                 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
935                 break;
936         }
937         
938         return status;
939 }
940
941
942 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
943                             struct libnet_DomainClose *io)
944 {
945         struct composite_context *c;
946         
947         c = libnet_DomainClose_send(ctx, io, NULL);
948         return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
949 }
950
951
952 struct domain_list_state {      
953         struct libnet_context *ctx;
954         struct libnet_RpcConnect rpcconn;
955         struct samr_Connect samrconn;
956         struct samr_EnumDomains enumdom;
957         struct samr_Close samrclose;
958         const char *hostname;
959         struct policy_handle connect_handle;
960         int buf_size;
961         struct domainlist *domains;
962         uint32_t resume_handle;
963         uint32_t count;
964
965         void (*monitor_fn)(struct monitor_msg*);
966 };
967
968
969 static void continue_rpc_connect(struct composite_context *c);
970 static void continue_samr_connect(struct tevent_req *subreq);
971 static void continue_samr_enum_domains(struct tevent_req *subreq);
972 static void continue_samr_close_handle(struct tevent_req *subreq);
973
974 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
975
976
977 /*
978   Stage 1: Receive connected rpc pipe and send connection
979   request to SAMR service
980 */
981 static void continue_rpc_connect(struct composite_context *ctx)
982 {
983         struct composite_context *c;
984         struct domain_list_state *s;
985         struct tevent_req *subreq;
986
987         c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
988         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
989         
990         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
991         if (!composite_is_ok(c)) return;
992
993         s->samrconn.in.system_name     = 0;
994         s->samrconn.in.access_mask     = SEC_GENERIC_READ;     /* should be enough */
995         s->samrconn.out.connect_handle = &s->connect_handle;
996
997         subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
998                                             s->ctx->samr.pipe->binding_handle,
999                                             &s->samrconn);
1000         if (composite_nomem(subreq, c)) return;
1001
1002         tevent_req_set_callback(subreq, continue_samr_connect, c);
1003 }
1004
1005
1006 /*
1007   Stage 2: Receive policy handle to the connected SAMR service and issue
1008   a request to enumerate domain databases available
1009 */
1010 static void continue_samr_connect(struct tevent_req *subreq)
1011 {
1012         struct composite_context *c;
1013         struct domain_list_state *s;
1014
1015         c = tevent_req_callback_data(subreq, struct composite_context);
1016         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1017         
1018         c->status = dcerpc_samr_Connect_r_recv(subreq, s);
1019         TALLOC_FREE(subreq);
1020         if (!composite_is_ok(c)) return;
1021
1022         if (s->monitor_fn) {
1023                 struct monitor_msg msg;
1024                 
1025                 msg.type      = mon_SamrConnect;
1026                 msg.data      = NULL;
1027                 msg.data_size = 0;
1028                 s->monitor_fn(&msg);
1029         }
1030
1031         s->enumdom.in.connect_handle = &s->connect_handle;
1032         s->enumdom.in.resume_handle  = &s->resume_handle;
1033         s->enumdom.in.buf_size       = s->buf_size;
1034         s->enumdom.out.resume_handle = &s->resume_handle;
1035         s->enumdom.out.num_entries   = talloc(s, uint32_t);
1036         if (composite_nomem(s->enumdom.out.num_entries, c)) return;
1037         s->enumdom.out.sam           = talloc(s, struct samr_SamArray *);
1038         if (composite_nomem(s->enumdom.out.sam, c)) return;
1039
1040         subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
1041                                                 s->ctx->samr.pipe->binding_handle,
1042                                                 &s->enumdom);
1043         if (composite_nomem(subreq, c)) return;
1044
1045         tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1046 }
1047
1048
1049 /*
1050   Stage 3: Receive domain names available and repeat the request
1051   enumeration is not complete yet. Close samr connection handle
1052   upon completion.
1053 */
1054 static void continue_samr_enum_domains(struct tevent_req *subreq)
1055 {
1056         struct composite_context *c;
1057         struct domain_list_state *s;
1058
1059         c = tevent_req_callback_data(subreq, struct composite_context);
1060         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1061         
1062         c->status = dcerpc_samr_EnumDomains_r_recv(subreq, s);
1063         TALLOC_FREE(subreq);
1064         if (!composite_is_ok(c)) return;
1065
1066         if (s->monitor_fn) {
1067                 struct monitor_msg msg;
1068                 
1069                 msg.type      = mon_SamrEnumDomains;
1070                 msg.data      = NULL;
1071                 msg.data_size = 0;
1072                 s->monitor_fn(&msg);
1073         }
1074
1075         if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
1076
1077                 s->domains = get_domain_list(c, s);
1078
1079         } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
1080                 
1081                 s->domains = get_domain_list(c, s);
1082                 
1083                 /* prepare next round of enumeration */
1084                 s->enumdom.in.connect_handle = &s->connect_handle;
1085                 s->enumdom.in.resume_handle  = &s->resume_handle;
1086                 s->enumdom.in.buf_size       = s->ctx->samr.buf_size;
1087                 s->enumdom.out.resume_handle = &s->resume_handle;
1088
1089                 /* send the request */
1090                 subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
1091                                                         s->ctx->samr.pipe->binding_handle,
1092                                                         &s->enumdom);
1093                 if (composite_nomem(subreq, c)) return;
1094
1095                 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1096
1097         } else {
1098                 composite_error(c, s->enumdom.out.result);
1099                 return;
1100         }
1101
1102         /* close samr connection handle */
1103         s->samrclose.in.handle  = &s->connect_handle;
1104         s->samrclose.out.handle = &s->connect_handle;
1105         
1106         /* send the request */
1107         subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
1108                                           s->ctx->samr.pipe->binding_handle,
1109                                           &s->samrclose);
1110         if (composite_nomem(subreq, c)) return;
1111
1112         tevent_req_set_callback(subreq, continue_samr_close_handle, c);
1113 }
1114
1115
1116 /*
1117   Stage 4: Receive result of closing samr connection handle.
1118 */
1119 static void continue_samr_close_handle(struct tevent_req *subreq)
1120 {
1121         struct composite_context *c;
1122         struct domain_list_state *s;
1123
1124         c = tevent_req_callback_data(subreq, struct composite_context);
1125         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1126
1127         c->status = dcerpc_samr_Close_r_recv(subreq, s);
1128         TALLOC_FREE(subreq);
1129         if (!composite_is_ok(c)) return;
1130
1131         if (s->monitor_fn) {
1132                 struct monitor_msg msg;
1133                 
1134                 msg.type      = mon_SamrClose;
1135                 msg.data      = NULL;
1136                 msg.data_size = 0;
1137                 s->monitor_fn(&msg);
1138         }
1139
1140         /* did everything go fine ? */
1141         if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
1142                 composite_error(c, s->samrclose.out.result);
1143                 return;
1144         }
1145
1146         composite_done(c);
1147 }
1148
1149
1150 /*
1151   Utility function to copy domain names from result of samr_EnumDomains call
1152 */
1153 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
1154 {
1155         uint32_t i;
1156         if (mem_ctx == NULL || s == NULL) return NULL;
1157
1158         /* prepare domains array */
1159         if (s->domains == NULL) {
1160                 s->domains = talloc_array(mem_ctx, struct domainlist,
1161                                           *s->enumdom.out.num_entries);
1162         } else {
1163                 s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
1164                                             s->count + *s->enumdom.out.num_entries);
1165         }
1166
1167         /* copy domain names returned from samr_EnumDomains call */
1168         for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
1169         {
1170                 struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
1171
1172                 /* strdup name as a child of allocated array to make it follow the array
1173                    in case of talloc_steal or talloc_free */
1174                 s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
1175                 s->domains[i].sid  = NULL;  /* this is to be filled out later */
1176         }
1177
1178         /* number of entries returned (domains enumerated) */
1179         s->count += *s->enumdom.out.num_entries;
1180         
1181         return s->domains;
1182 }
1183
1184
1185 /**
1186  * Sends a request to list domains on given host
1187  *
1188  * @param ctx initalised libnet context
1189  * @param mem_ctx memory context
1190  * @param io arguments and results of the call
1191  * @param monitor pointer to monitor function that is passed monitor messages
1192  */
1193
1194 struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
1195                                                  TALLOC_CTX *mem_ctx,
1196                                                  struct libnet_DomainList *io,
1197                                                  void (*monitor)(struct monitor_msg*))
1198 {
1199         struct composite_context *c;
1200         struct domain_list_state *s;
1201         struct composite_context *rpcconn_req;
1202         struct tevent_req *subreq;
1203
1204         /* composite context and state structure allocation */
1205         c = composite_create(ctx, ctx->event_ctx);
1206         if (c == NULL) return c;
1207
1208         s = talloc_zero(c, struct domain_list_state);
1209         if (composite_nomem(s, c)) return c;
1210
1211         c->private_data = s;
1212         s->monitor_fn   = monitor;
1213
1214         s->ctx      = ctx;
1215         s->hostname = talloc_strdup(c, io->in.hostname);
1216         if (composite_nomem(s->hostname, c)) return c;
1217
1218         /* check whether samr pipe has already been opened */
1219         if (ctx->samr.pipe == NULL) {
1220                 ZERO_STRUCT(s->rpcconn);
1221
1222                 /* prepare rpc connect call */
1223                 s->rpcconn.level           = LIBNET_RPC_CONNECT_SERVER;
1224                 s->rpcconn.in.name         = s->hostname;
1225                 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
1226
1227                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
1228                 if (composite_nomem(rpcconn_req, c)) return c;
1229                 
1230                 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
1231
1232         } else {
1233                 /* prepare samr_Connect call */
1234                 s->samrconn.in.system_name     = 0;
1235                 s->samrconn.in.access_mask     = SEC_GENERIC_READ;
1236                 s->samrconn.out.connect_handle = &s->connect_handle;
1237                 
1238                 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
1239                                                     s->ctx->samr.pipe->binding_handle,
1240                                                     &s->samrconn);
1241                 if (composite_nomem(subreq, c)) return c;
1242
1243                 tevent_req_set_callback(subreq, continue_samr_connect, c);
1244         }
1245
1246         return c;
1247 }
1248
1249
1250 /**
1251  * Receive result of domain list request
1252  *
1253  * @param c composite context returned by DomainList_send function
1254  * @param ctx initialised libnet context
1255  * @param mem_ctx memory context of the call
1256  * @param io results and arguments of the call
1257  */
1258
1259 NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
1260                                 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
1261 {
1262         NTSTATUS status;
1263         struct domain_list_state *s;
1264
1265         status = composite_wait(c);
1266
1267         s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1268
1269         if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
1270                 /* fetch the results to be returned by io structure */
1271                 io->out.count        = s->count;
1272                 io->out.domains      = talloc_steal(mem_ctx, s->domains);
1273                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
1274
1275         } else if (!NT_STATUS_IS_OK(status)) {
1276                 /* there was an error, so return description of the status code */
1277                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1278         }
1279
1280         talloc_free(c);
1281         return status;
1282 }
1283
1284
1285 /**
1286  * Synchronous version of DomainList call
1287  *
1288  * @param ctx initialised libnet context
1289  * @param mem_ctx memory context for the call
1290  * @param io arguments and results of the call
1291  * @return nt status code of execution
1292  */
1293
1294 NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1295                            struct libnet_DomainList *io)
1296 {
1297         struct composite_context *c;
1298
1299         c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
1300         return libnet_DomainList_recv(c, ctx, mem_ctx, io);
1301 }