Merge branch 'master' of ssh://git.samba.org/data/git/samba
[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_ndr_request_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_ndr_request_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_ndr_request_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_ndr_request_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                 /* attempting to connect a domain controller */
431                 s->rpcconn.level           = LIBNET_RPC_CONNECT_DC;
432                 s->rpcconn.in.name         = talloc_strdup(c, io->in.domain_name);
433                 s->rpcconn.in.dcerpc_iface = &ndr_table_lsarpc;
434                 
435                 /* send rpc pipe connect request */
436                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
437                 if (composite_nomem(rpcconn_req, c)) return c;
438
439                 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
440                 return c;
441         }
442
443         s->pipe = ctx->lsa.pipe;
444
445         /* preparing parameters for lsa_OpenPolicy2 rpc call */
446         s->openpol.in.system_name = s->name;
447         s->openpol.in.access_mask = s->access_mask;
448         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
449
450         qos = talloc_zero(c, struct lsa_QosInfo);
451         qos->len                 = 0;
452         qos->impersonation_level = 2;
453         qos->context_mode        = 1;
454         qos->effective_only      = 0;
455
456         s->openpol.in.attr->sec_qos = qos;
457         s->openpol.out.handle       = &s->handle;
458         
459         /* send rpc request */
460         openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
461         if (composite_nomem(openpol_req, c)) return c;
462
463         composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
464         return c;
465 }
466
467
468 /*
469   Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
470  */
471 static void continue_rpc_connect_lsa(struct composite_context *ctx)
472 {
473         struct composite_context *c;
474         struct domain_open_lsa_state *s;
475         struct lsa_QosInfo *qos;
476         struct rpc_request *openpol_req;
477
478         c = talloc_get_type(ctx->async.private_data, struct composite_context);
479         s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
480
481         /* receive rpc connection */
482         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
483         if (!composite_is_ok(c)) return;
484
485         /* RpcConnect function leaves the pipe in libnet context,
486            so get it from there */
487         s->pipe = s->ctx->lsa.pipe;
488
489         /* prepare lsa_OpenPolicy2 call */
490         s->openpol.in.system_name = s->name;
491         s->openpol.in.access_mask = s->access_mask;
492         s->openpol.in.attr        = talloc_zero(c, struct lsa_ObjectAttribute);
493
494         qos = talloc_zero(c, struct lsa_QosInfo);
495         qos->len                 = 0;
496         qos->impersonation_level = 2;
497         qos->context_mode        = 1;
498         qos->effective_only      = 0;
499
500         s->openpol.in.attr->sec_qos = qos;
501         s->openpol.out.handle       = &s->handle;
502
503         /* send rpc request */
504         openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
505         if (composite_nomem(openpol_req, c)) return;
506
507         composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
508 }
509
510
511 /*
512   Stage 1: Lsa policy opened - we're done, if successfully
513  */
514 static void continue_lsa_policy_open(struct rpc_request *req)
515 {
516         struct composite_context *c;
517         struct domain_open_lsa_state *s;
518
519         c = talloc_get_type(req->async.private_data, struct composite_context);
520         s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
521
522         c->status = dcerpc_ndr_request_recv(req);
523         if (!composite_is_ok(c)) return;
524
525         if (s->monitor_fn) {
526                 struct monitor_msg msg;
527                 
528                 msg.type      = mon_LsaOpenPolicy;
529                 msg.data      = NULL;
530                 msg.data_size = 0;
531                 s->monitor_fn(&msg);
532         }
533
534         composite_done(c);
535 }
536
537
538 /**
539  * Receives result of asynchronous DomainOpenLsa call
540  *
541  * @param c composite context returned by asynchronous DomainOpenLsa call
542  * @param ctx initialised libnet context
543  * @param mem_ctx memory context of the call
544  * @param io pointer to results (and arguments) of the call
545  * @return nt status code of execution
546  */
547
548 NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
549                                    TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
550 {
551         NTSTATUS status;
552         struct domain_open_lsa_state *s;
553
554         status = composite_wait(c);
555
556         if (NT_STATUS_IS_OK(status) && io) {
557                 /* everything went fine - get the results and
558                    return the error string */
559                 s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
560                 io->out.domain_handle = s->handle;
561
562                 ctx->lsa.handle      = s->handle;
563                 ctx->lsa.name        = talloc_steal(ctx, s->name);
564                 ctx->lsa.access_mask = s->access_mask;
565                 
566                 io->out.error_string = talloc_strdup(mem_ctx, "Success");
567
568         } else if (!NT_STATUS_IS_OK(status)) {
569                 /* there was an error, so provide nt status code description */
570                 io->out.error_string = talloc_asprintf(mem_ctx,
571                                                        "Failed to open domain: %s",
572                                                        nt_errstr(status));
573         }
574
575         talloc_free(c);
576         return status;
577 }
578
579
580 /**
581  * Sends a request to open a domain in desired service
582  *
583  * @param ctx initalised libnet context
584  * @param io arguments and results of the call
585  * @param monitor pointer to monitor function that is passed monitor message
586  */
587
588 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
589                                                  struct libnet_DomainOpen *io,
590                                                  void (*monitor)(struct monitor_msg*))
591 {
592         struct composite_context *c;
593
594         switch (io->in.type) {
595         case DOMAIN_LSA:
596                 /* reques to open a policy handle on \pipe\lsarpc */
597                 c = libnet_DomainOpenLsa_send(ctx, io, monitor);
598                 break;
599
600         case DOMAIN_SAMR:
601         default:
602                 /* request to open a domain policy handle on \pipe\samr */
603                 c = libnet_DomainOpenSamr_send(ctx, io, monitor);
604                 break;
605         }
606
607         return c;
608 }
609
610
611 /**
612  * Receive result of domain open request
613  *
614  * @param c composite context returned by DomainOpen_send function
615  * @param ctx initialised libnet context
616  * @param mem_ctx memory context of the call
617  * @param io results and arguments of the call
618  */
619
620 NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
621                                 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
622 {
623         NTSTATUS status;
624
625         switch (io->in.type) {
626         case DOMAIN_LSA:
627                 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
628                 break;
629
630         case DOMAIN_SAMR:
631         default:
632                 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
633                 break;
634         }
635         
636         return status;
637 }
638
639
640 /**
641  * Synchronous version of DomainOpen call
642  *
643  * @param ctx initialised libnet context
644  * @param mem_ctx memory context for the call
645  * @param io arguments and results of the call
646  * @return nt status code of execution
647  */
648
649 NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
650                            TALLOC_CTX *mem_ctx,
651                            struct libnet_DomainOpen *io)
652 {
653         struct composite_context *c = libnet_DomainOpen_send(ctx, io, NULL);
654         return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
655 }
656
657
658 struct domain_close_lsa_state {
659         struct dcerpc_pipe *pipe;
660         struct lsa_Close close;
661         struct policy_handle handle;
662
663         void (*monitor_fn)(struct monitor_msg*);
664 };
665
666
667 static void continue_lsa_close(struct rpc_request *req);
668
669
670 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
671                                                      struct libnet_DomainClose *io,
672                                                      void (*monitor)(struct monitor_msg*))
673 {
674         struct composite_context *c;
675         struct domain_close_lsa_state *s;
676         struct rpc_request *close_req;
677
678         /* composite context and state structure allocation */
679         c = composite_create(ctx, ctx->event_ctx);
680         if (c == NULL) return c;
681
682         s = talloc_zero(c, struct domain_close_lsa_state);
683         if (composite_nomem(s, c)) return c;
684
685         c->private_data = s;
686         s->monitor_fn   = monitor;
687
688         /* TODO: check if lsa pipe pointer is non-null */
689
690         if (!strequal(ctx->lsa.name, io->in.domain_name)) {
691                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
692                 return c;
693         }
694
695         /* get opened lsarpc pipe pointer */
696         s->pipe = ctx->lsa.pipe;
697         
698         /* prepare close handle call arguments */
699         s->close.in.handle  = &ctx->lsa.handle;
700         s->close.out.handle = &s->handle;
701
702         /* send the request */
703         close_req = dcerpc_lsa_Close_send(s->pipe, c, &s->close);
704         if (composite_nomem(close_req, c)) return c;
705
706         composite_continue_rpc(c, close_req, continue_lsa_close, c);
707         return c;
708 }
709
710
711 /*
712   Stage 1: Receive result of lsa close call
713 */
714 static void continue_lsa_close(struct rpc_request *req)
715 {
716         struct composite_context *c;
717         struct domain_close_lsa_state *s;
718         
719         c = talloc_get_type(req->async.private_data, struct composite_context);
720         s = talloc_get_type(c->private_data, struct domain_close_lsa_state);
721
722         c->status = dcerpc_ndr_request_recv(req);
723         if (!composite_is_ok(c)) return;
724
725         if (s->monitor_fn) {
726                 struct monitor_msg msg;
727
728                 msg.type      = mon_LsaClose;
729                 msg.data      = NULL;
730                 msg.data_size = 0;
731                 s->monitor_fn(&msg);
732         }
733
734         composite_done(c);
735 }
736
737
738 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
739                                     TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
740 {
741         NTSTATUS status;
742
743         status = composite_wait(c);
744
745         if (NT_STATUS_IS_OK(status) && io) {
746                 /* policy handle closed successfully */
747
748                 ctx->lsa.name = NULL;
749                 ZERO_STRUCT(ctx->lsa.handle);
750
751                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
752
753         } else if (!NT_STATUS_IS_OK(status)) {
754                 /* there was an error, so return description of the status code */
755                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
756         }
757
758         talloc_free(c);
759         return status;
760 }
761
762
763 struct domain_close_samr_state {
764         struct samr_Close close;
765         struct policy_handle handle;
766         
767         void (*monitor_fn)(struct monitor_msg*);
768 };
769
770
771 static void continue_samr_close(struct rpc_request *req);
772
773
774 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
775                                                       struct libnet_DomainClose *io,
776                                                       void (*monitor)(struct monitor_msg*))
777 {
778         struct composite_context *c;
779         struct domain_close_samr_state *s;
780         struct rpc_request *close_req;
781
782         /* composite context and state structure allocation */
783         c = composite_create(ctx, ctx->event_ctx);
784         if (c == NULL) return c;
785
786         s = talloc_zero(c, struct domain_close_samr_state);
787         if (composite_nomem(s, c)) return c;
788
789         c->private_data = s;
790         s->monitor_fn   = monitor;
791
792         /* TODO: check if samr pipe pointer is non-null */
793
794         if (!strequal(ctx->samr.name, io->in.domain_name)) {
795                 composite_error(c, NT_STATUS_INVALID_PARAMETER);
796                 return c;
797         }
798
799         /* prepare close domain handle call arguments */
800         ZERO_STRUCT(s->close);
801         s->close.in.handle  = &ctx->samr.handle;
802         s->close.out.handle = &s->handle;
803
804         /* send the request */
805         close_req = dcerpc_samr_Close_send(ctx->samr.pipe, ctx, &s->close);
806         if (composite_nomem(close_req, c)) return c;
807
808         composite_continue_rpc(c, close_req, continue_samr_close, c);
809         return c;
810 }
811
812
813 /*
814   Stage 1: Receive result of samr close call
815 */
816 static void continue_samr_close(struct rpc_request *req)
817 {
818         struct composite_context *c;
819         struct domain_close_samr_state *s;
820
821         c = talloc_get_type(req->async.private_data, struct composite_context);
822         s = talloc_get_type(c->private_data, struct domain_close_samr_state);
823         
824         c->status = dcerpc_ndr_request_recv(req);
825         if (!composite_is_ok(c)) return;
826
827         if (s->monitor_fn) {
828                 struct monitor_msg msg;
829                 
830                 msg.type      = mon_SamrClose;
831                 msg.data      = NULL;
832                 msg.data_size = 0;
833                 s->monitor_fn(&msg);
834         }
835         
836         composite_done(c);
837 }
838
839
840 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
841                                      TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
842 {
843         NTSTATUS status;
844
845         status = composite_wait(c);
846
847         if (NT_STATUS_IS_OK(status) && io) {
848                 /* domain policy handle closed successfully */
849
850                 ZERO_STRUCT(ctx->samr.handle);
851                 talloc_free(discard_const_p(char, ctx->samr.name));
852                 talloc_free(ctx->samr.sid);
853                 ctx->samr.name = NULL;
854                 ctx->samr.sid = NULL;
855
856                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
857
858         } else if (!NT_STATUS_IS_OK(status)) {
859                 /* there was an error, so return description of the status code */
860                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
861         }
862
863         talloc_free(c);
864         return status;
865 }
866
867
868 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
869                                                   struct libnet_DomainClose *io,
870                                                   void (*monitor)(struct monitor_msg*))
871 {
872         struct composite_context *c;
873
874         switch (io->in.type) {
875         case DOMAIN_LSA:
876                 /* request to close policy handle on \pipe\lsarpc */
877                 c = libnet_DomainCloseLsa_send(ctx, io, monitor);
878                 break;
879
880         case DOMAIN_SAMR:
881         default:
882                 /* request to close domain policy handle on \pipe\samr */
883                 c = libnet_DomainCloseSamr_send(ctx, io, monitor);
884                 break;
885         }
886         
887         return c;
888 }
889
890
891 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
892                                  TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
893 {
894         NTSTATUS status;
895
896         switch (io->in.type) {
897         case DOMAIN_LSA:
898                 /* receive result of closing lsa policy handle */
899                 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
900                 break;
901
902         case DOMAIN_SAMR:
903         default:
904                 /* receive result of closing samr domain policy handle */
905                 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
906                 break;
907         }
908         
909         return status;
910 }
911
912
913 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
914                             struct libnet_DomainClose *io)
915 {
916         struct composite_context *c;
917         
918         c = libnet_DomainClose_send(ctx, io, NULL);
919         return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
920 }
921
922
923 struct domain_list_state {      
924         struct libnet_context *ctx;
925         struct libnet_RpcConnect rpcconn;
926         struct samr_Connect samrconn;
927         struct samr_EnumDomains enumdom;
928         struct samr_Close samrclose;
929         const char *hostname;
930         struct policy_handle connect_handle;
931         int buf_size;
932         struct domainlist *domains;
933         uint32_t resume_handle;
934         uint32_t count;
935
936         void (*monitor_fn)(struct monitor_msg*);
937 };
938
939
940 static void continue_rpc_connect(struct composite_context *c);
941 static void continue_samr_connect(struct rpc_request *c);
942 static void continue_samr_enum_domains(struct rpc_request *req);
943 static void continue_samr_close_handle(struct rpc_request *req);
944
945 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
946
947
948 /*
949   Stage 1: Receive connected rpc pipe and send connection
950   request to SAMR service
951 */
952 static void continue_rpc_connect(struct composite_context *ctx)
953 {
954         struct composite_context *c;
955         struct domain_list_state *s;
956         struct rpc_request *samrconn_req;
957
958         c = talloc_get_type(ctx->async.private_data, struct composite_context);
959         s = talloc_get_type(c->private_data, struct domain_list_state);
960         
961         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
962         if (!composite_is_ok(c)) return;
963
964         s->samrconn.in.system_name     = 0;
965         s->samrconn.in.access_mask     = SEC_GENERIC_READ;     /* should be enough */
966         s->samrconn.out.connect_handle = &s->connect_handle;
967
968         samrconn_req = dcerpc_samr_Connect_send(s->ctx->samr.pipe, c, &s->samrconn);
969         if (composite_nomem(samrconn_req, c)) return;
970
971         composite_continue_rpc(c, samrconn_req, continue_samr_connect, c);
972 }
973
974
975 /*
976   Stage 2: Receive policy handle to the connected SAMR service and issue
977   a request to enumerate domain databases available
978 */
979 static void continue_samr_connect(struct rpc_request *req)
980 {
981         struct composite_context *c;
982         struct domain_list_state *s;
983         struct rpc_request *enumdom_req;
984
985         c = talloc_get_type(req->async.private_data, struct composite_context);
986         s = talloc_get_type(c->private_data, struct domain_list_state);
987         
988         c->status = dcerpc_ndr_request_recv(req);
989         if (!composite_is_ok(c)) return;
990
991         if (s->monitor_fn) {
992                 struct monitor_msg msg;
993                 
994                 msg.type      = mon_SamrConnect;
995                 msg.data      = NULL;
996                 msg.data_size = 0;
997                 s->monitor_fn(&msg);
998         }
999
1000         s->enumdom.in.connect_handle = &s->connect_handle;
1001         s->enumdom.in.resume_handle  = &s->resume_handle;
1002         s->enumdom.in.buf_size       = s->buf_size;
1003         s->enumdom.out.resume_handle = &s->resume_handle;
1004         s->enumdom.out.num_entries   = talloc(s, uint32_t);
1005         if (composite_nomem(s->enumdom.out.num_entries, c)) return;
1006         s->enumdom.out.sam           = talloc(s, struct samr_SamArray *);
1007         if (composite_nomem(s->enumdom.out.sam, c)) return;
1008
1009         enumdom_req = dcerpc_samr_EnumDomains_send(s->ctx->samr.pipe, c, &s->enumdom);
1010         if (composite_nomem(enumdom_req, c)) return;
1011
1012         composite_continue_rpc(c, enumdom_req, continue_samr_enum_domains, c);
1013 }
1014
1015
1016 /*
1017   Stage 3: Receive domain names available and repeat the request
1018   enumeration is not complete yet. Close samr connection handle
1019   upon completion.
1020 */
1021 static void continue_samr_enum_domains(struct rpc_request *req)
1022 {
1023         struct composite_context *c;
1024         struct domain_list_state *s;
1025         struct rpc_request *enumdom_req;
1026         struct rpc_request *samrclose_req;
1027
1028         c = talloc_get_type(req->async.private_data, struct composite_context);
1029         s = talloc_get_type(c->private_data, struct domain_list_state);
1030         
1031         c->status = dcerpc_ndr_request_recv(req);
1032         if (!composite_is_ok(c)) return;
1033
1034         if (s->monitor_fn) {
1035                 struct monitor_msg msg;
1036                 
1037                 msg.type      = mon_SamrEnumDomains;
1038                 msg.data      = NULL;
1039                 msg.data_size = 0;
1040                 s->monitor_fn(&msg);
1041         }
1042
1043         if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
1044
1045                 s->domains = get_domain_list(c, s);
1046
1047         } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
1048                 
1049                 s->domains = get_domain_list(c, s);
1050                 
1051                 /* prepare next round of enumeration */
1052                 s->enumdom.in.connect_handle = &s->connect_handle;
1053                 s->enumdom.in.resume_handle  = &s->resume_handle;
1054                 s->enumdom.in.buf_size       = s->ctx->samr.buf_size;
1055                 s->enumdom.out.resume_handle = &s->resume_handle;
1056
1057                 /* send the request */
1058                 enumdom_req = dcerpc_samr_EnumDomains_send(s->ctx->samr.pipe, c, &s->enumdom);
1059                 if (composite_nomem(enumdom_req, c)) return;
1060
1061                 composite_continue_rpc(c, enumdom_req, continue_samr_enum_domains, c);
1062
1063         } else {
1064                 composite_error(c, s->enumdom.out.result);
1065                 return;
1066         }
1067
1068         /* close samr connection handle */
1069         s->samrclose.in.handle  = &s->connect_handle;
1070         s->samrclose.out.handle = &s->connect_handle;
1071         
1072         /* send the request */
1073         samrclose_req = dcerpc_samr_Close_send(s->ctx->samr.pipe, c, &s->samrclose);
1074         if (composite_nomem(samrclose_req, c)) return;
1075
1076         composite_continue_rpc(c, samrclose_req, continue_samr_close_handle, c);
1077 }
1078
1079
1080 /*
1081   Stage 4: Receive result of closing samr connection handle.
1082 */
1083 static void continue_samr_close_handle(struct rpc_request *req)
1084 {
1085         struct composite_context *c;
1086         struct domain_list_state *s;
1087
1088         c = talloc_get_type(req->async.private_data, struct composite_context);
1089         s = talloc_get_type(c->private_data, struct domain_list_state);
1090
1091         c->status = dcerpc_ndr_request_recv(req);
1092         if (!composite_is_ok(c)) return;
1093
1094         if (s->monitor_fn) {
1095                 struct monitor_msg msg;
1096                 
1097                 msg.type      = mon_SamrClose;
1098                 msg.data      = NULL;
1099                 msg.data_size = 0;
1100                 s->monitor_fn(&msg);
1101         }
1102
1103         /* did everything go fine ? */
1104         if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
1105                 composite_error(c, s->samrclose.out.result);
1106         }
1107
1108         composite_done(c);
1109 }
1110
1111
1112 /*
1113   Utility function to copy domain names from result of samr_EnumDomains call
1114 */
1115 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
1116 {
1117         int i;
1118         if (mem_ctx == NULL || s == NULL) return NULL;
1119
1120         /* prepare domains array */
1121         if (s->domains == NULL) {
1122                 s->domains = talloc_array(mem_ctx, struct domainlist,
1123                                           *s->enumdom.out.num_entries);
1124         } else {
1125                 s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
1126                                             s->count + *s->enumdom.out.num_entries);
1127         }
1128
1129         /* copy domain names returned from samr_EnumDomains call */
1130         for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
1131         {
1132                 struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
1133
1134                 /* strdup name as a child of allocated array to make it follow the array
1135                    in case of talloc_steal or talloc_free */
1136                 s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
1137                 s->domains[i].sid  = NULL;  /* this is to be filled out later */
1138         }
1139
1140         /* number of entries returned (domains enumerated) */
1141         s->count += *s->enumdom.out.num_entries;
1142         
1143         return s->domains;
1144 }
1145
1146
1147 /**
1148  * Sends a request to list domains on given host
1149  *
1150  * @param ctx initalised libnet context
1151  * @param mem_ctx memory context
1152  * @param io arguments and results of the call
1153  * @param monitor pointer to monitor function that is passed monitor messages
1154  */
1155
1156 struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
1157                                                  TALLOC_CTX *mem_ctx,
1158                                                  struct libnet_DomainList *io,
1159                                                  void (*monitor)(struct monitor_msg*))
1160 {
1161         struct composite_context *c;
1162         struct domain_list_state *s;
1163         struct composite_context *rpcconn_req;
1164         struct rpc_request *samrconn_req;
1165
1166         /* composite context and state structure allocation */
1167         c = composite_create(ctx, ctx->event_ctx);
1168         if (c == NULL) return c;
1169
1170         s = talloc_zero(c, struct domain_list_state);
1171         if (composite_nomem(s, c)) return c;
1172
1173         c->private_data = s;
1174         s->monitor_fn   = monitor;
1175
1176         s->ctx      = ctx;
1177         s->hostname = talloc_strdup(c, io->in.hostname);
1178         if (composite_nomem(s->hostname, c)) return c;
1179
1180         /* check whether samr pipe has already been opened */
1181         if (ctx->samr.pipe == NULL) {
1182                 /* prepare rpc connect call */
1183                 s->rpcconn.level           = LIBNET_RPC_CONNECT_SERVER;
1184                 s->rpcconn.in.name         = s->hostname;
1185                 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
1186
1187                 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
1188                 if (composite_nomem(rpcconn_req, c)) return c;
1189                 
1190                 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
1191
1192         } else {
1193                 /* prepare samr_Connect call */
1194                 s->samrconn.in.system_name     = 0;
1195                 s->samrconn.in.access_mask     = SEC_GENERIC_READ;
1196                 s->samrconn.out.connect_handle = &s->connect_handle;
1197                 
1198                 samrconn_req = dcerpc_samr_Connect_send(s->ctx->samr.pipe, c, &s->samrconn);
1199                 if (composite_nomem(samrconn_req, c)) return c;
1200
1201                 composite_continue_rpc(c, samrconn_req, continue_samr_connect, c);
1202         }
1203
1204         return c;
1205 }
1206
1207
1208 /**
1209  * Receive result of domain list request
1210  *
1211  * @param c composite context returned by DomainList_send function
1212  * @param ctx initialised libnet context
1213  * @param mem_ctx memory context of the call
1214  * @param io results and arguments of the call
1215  */
1216
1217 NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
1218                                 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
1219 {
1220         NTSTATUS status;
1221         struct domain_list_state *s;
1222
1223         status = composite_wait(c);
1224
1225         s = talloc_get_type(c->private_data, struct domain_list_state);
1226
1227         if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
1228                 /* fetch the results to be returned by io structure */
1229                 io->out.count        = s->count;
1230                 io->out.domains      = talloc_steal(mem_ctx, s->domains);
1231                 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
1232
1233         } else if (!NT_STATUS_IS_OK(status)) {
1234                 /* there was an error, so return description of the status code */
1235                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1236         }
1237
1238         talloc_free(c);
1239         return status;
1240 }
1241
1242
1243 /**
1244  * Synchronous version of DomainList call
1245  *
1246  * @param ctx initialised libnet context
1247  * @param mem_ctx memory context for the call
1248  * @param io arguments and results of the call
1249  * @return nt status code of execution
1250  */
1251
1252 NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1253                            struct libnet_DomainList *io)
1254 {
1255         struct composite_context *c;
1256
1257         c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
1258         return libnet_DomainList_recv(c, ctx, mem_ctx, io);
1259 }