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