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