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