tdb: Add a comment explaining the "check"
[Samba/vl.git] / source4 / libnet / libnet_domain.c
blob70ed31d02be1aefd41fbebbe35d6cadfecc4501c
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Rafal Szczesniak 2005
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.
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.
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/>.
21 a composite function for domain handling on samr and lsa pipes
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"
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;
45 /* information about the progress */
46 void (*monitor_fn)(struct monitor_msg*);
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);
56 /**
57 * Stage 0.5 (optional): Connect to samr rpc pipe
59 static void continue_domain_open_rpc_connect(struct composite_context *ctx)
61 struct composite_context *c;
62 struct domain_open_samr_state *s;
63 struct tevent_req *subreq;
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);
68 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
69 if (!composite_is_ok(c)) return;
71 s->pipe = s->rpcconn.out.dcerpc_pipe;
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;
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;
84 /* callback handler */
85 tevent_req_set_callback(subreq, continue_domain_open_connect, c);
89 /**
90 * Stage 0.5 (optional): Close existing (in libnet context) domain
91 * handle
93 static void continue_domain_open_close(struct tevent_req *subreq)
95 struct composite_context *c;
96 struct domain_open_samr_state *s;
98 c = tevent_req_callback_data(subreq, struct composite_context);
99 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
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;
106 if (s->monitor_fn) {
107 struct monitor_msg msg;
109 msg.type = mon_SamrClose;
110 msg.data = NULL;
111 msg.data_size = 0;
112 s->monitor_fn(&msg);
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);
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;
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;
131 /* callback handler */
132 tevent_req_set_callback(subreq, continue_domain_open_connect, c);
137 * Stage 1: Connect to SAM server.
139 static void continue_domain_open_connect(struct tevent_req *subreq)
141 struct composite_context *c;
142 struct domain_open_samr_state *s;
143 struct samr_LookupDomain *r;
145 c = tevent_req_callback_data(subreq, struct composite_context);
146 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
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;
153 if (s->monitor_fn) {
154 struct monitor_msg msg;
156 msg.type = mon_SamrConnect;
157 msg.data = NULL;
158 msg.data_size = 0;
159 s->monitor_fn(&msg);
162 r = &s->lookup;
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;
170 subreq = dcerpc_samr_LookupDomain_r_send(s, c->event_ctx,
171 s->pipe->binding_handle,
173 if (composite_nomem(subreq, c)) return;
175 tevent_req_set_callback(subreq, continue_domain_open_lookup, c);
180 * Stage 2: Lookup domain by name.
182 static void continue_domain_open_lookup(struct tevent_req *subreq)
184 struct composite_context *c;
185 struct domain_open_samr_state *s;
186 struct samr_OpenDomain *r;
188 c = tevent_req_callback_data(subreq, struct composite_context);
189 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
191 /* receive samr_LookupDomain reply */
192 c->status = dcerpc_samr_LookupDomain_r_recv(subreq, s);
193 TALLOC_FREE(subreq);
195 if (s->monitor_fn) {
196 struct monitor_msg msg;
197 struct msg_rpc_lookup_domain data;
199 data.domain_name = s->domain_name.string;
201 msg.type = mon_SamrLookupDomain;
202 msg.data = (void*)&data;
203 msg.data_size = sizeof(data);
204 s->monitor_fn(&msg);
207 r = &s->open;
209 /* check the rpc layer status */
210 if (!composite_is_ok(c));
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;
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;
224 subreq = dcerpc_samr_OpenDomain_r_send(s, c->event_ctx,
225 s->pipe->binding_handle,
227 if (composite_nomem(subreq, c)) return;
229 tevent_req_set_callback(subreq, continue_domain_open_open, c);
234 * Stage 3: Open domain.
236 static void continue_domain_open_open(struct tevent_req *subreq)
238 struct composite_context *c;
239 struct domain_open_samr_state *s;
241 c = tevent_req_callback_data(subreq, struct composite_context);
242 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
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;
249 if (s->monitor_fn) {
250 struct monitor_msg msg;
252 msg.type = mon_SamrOpenDomain;
253 msg.data = NULL;
254 msg.data_size = 0;
255 s->monitor_fn(&msg);
258 composite_done(c);
263 * Sends asynchronous DomainOpenSamr request
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
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*))
275 struct composite_context *c;
276 struct domain_open_samr_state *s;
277 struct composite_context *rpcconn_req;
278 struct tevent_req *subreq;
280 c = composite_create(mem_ctx, ctx->event_ctx);
281 if (c == NULL) return NULL;
283 s = talloc_zero(c, struct domain_open_samr_state);
284 if (composite_nomem(s, c)) return c;
286 c->private_data = s;
287 s->monitor_fn = monitor;
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);
294 /* check, if there's samr pipe opened already, before opening a domain */
295 if (ctx->samr.pipe == NULL) {
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;
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;
306 composite_continue(c, rpcconn_req, continue_domain_open_rpc_connect, c);
307 return c;
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) {
316 /* this domain is already opened */
317 composite_done(c);
318 return c;
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;
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;
331 /* callback handler */
332 tevent_req_set_callback(subreq, continue_domain_open_close, c);
333 return c;
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;
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;
348 /* callback handler */
349 tevent_req_set_callback(subreq, continue_domain_open_connect, c);
350 return c;
355 * Waits for and receives result of asynchronous DomainOpenSamr call
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
364 NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
365 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
367 NTSTATUS status;
368 struct domain_open_samr_state *s;
370 /* wait for results of sending request */
371 status = composite_wait(c);
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;
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;
386 talloc_free(c);
387 return status;
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;
400 /* information about the progress */
401 void (*monitor_fn)(struct monitor_msg*);
405 static void continue_rpc_connect_lsa(struct composite_context *ctx);
406 static void continue_lsa_policy_open(struct tevent_req *subreq);
410 * Sends asynchronous DomainOpenLsa request
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
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*))
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;
428 /* create composite context and state */
429 c = composite_create(mem_ctx, ctx->event_ctx);
430 if (c == NULL) return c;
432 s = talloc_zero(c, struct domain_open_lsa_state);
433 if (composite_nomem(s, c)) return c;
435 c->private_data = s;
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;
442 /* check, if there's lsa pipe opened already, before opening a handle */
443 if (ctx->lsa.pipe == NULL) {
445 ZERO_STRUCT(s->rpcconn);
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;
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;
456 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
457 return c;
460 s->pipe = ctx->lsa.pipe;
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);
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;
473 s->openpol.in.attr->sec_qos = qos;
474 s->openpol.out.handle = &s->handle;
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;
482 tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
483 return c;
488 Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
490 static void continue_rpc_connect_lsa(struct composite_context *ctx)
492 struct composite_context *c;
493 struct domain_open_lsa_state *s;
494 struct lsa_QosInfo *qos;
495 struct tevent_req *subreq;
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);
500 /* receive rpc connection */
501 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
502 if (!composite_is_ok(c)) return;
504 /* RpcConnect function leaves the pipe in libnet context,
505 so get it from there */
506 s->pipe = s->ctx->lsa.pipe;
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);
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;
519 s->openpol.in.attr->sec_qos = qos;
520 s->openpol.out.handle = &s->handle;
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;
528 tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
533 Stage 1: Lsa policy opened - we're done, if successfully
535 static void continue_lsa_policy_open(struct tevent_req *subreq)
537 struct composite_context *c;
538 struct domain_open_lsa_state *s;
540 c = tevent_req_callback_data(subreq, struct composite_context);
541 s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
543 c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
544 TALLOC_FREE(subreq);
545 if (!composite_is_ok(c)) return;
547 if (s->monitor_fn) {
548 struct monitor_msg msg;
550 msg.type = mon_LsaOpenPolicy;
551 msg.data = NULL;
552 msg.data_size = 0;
553 s->monitor_fn(&msg);
556 composite_done(c);
561 * Receives result of asynchronous DomainOpenLsa call
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
570 NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
571 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
573 NTSTATUS status;
574 struct domain_open_lsa_state *s;
576 status = composite_wait(c);
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;
584 ctx->lsa.handle = s->handle;
585 ctx->lsa.name = talloc_steal(ctx, s->name);
586 ctx->lsa.access_mask = s->access_mask;
588 io->out.error_string = talloc_strdup(mem_ctx, "Success");
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));
597 talloc_free(c);
598 return status;
603 * Sends a request to open a domain in desired service
605 * @param ctx initalised libnet context
606 * @param io arguments and results of the call
607 * @param monitor pointer to monitor function that is passed monitor message
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*))
615 struct composite_context *c;
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;
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;
630 return c;
635 * Receive result of domain open request
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
643 NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
644 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
646 NTSTATUS status;
648 switch (io->in.type) {
649 case DOMAIN_LSA:
650 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
651 break;
653 case DOMAIN_SAMR:
654 default:
655 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
656 break;
659 return status;
664 * Synchronous version of DomainOpen call
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
672 NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
673 TALLOC_CTX *mem_ctx,
674 struct libnet_DomainOpen *io)
676 struct composite_context *c = libnet_DomainOpen_send(ctx, mem_ctx, io, NULL);
677 return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
681 struct domain_close_lsa_state {
682 struct dcerpc_pipe *pipe;
683 struct lsa_Close close;
684 struct policy_handle handle;
686 void (*monitor_fn)(struct monitor_msg*);
690 static void continue_lsa_close(struct tevent_req *subreq);
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*))
698 struct composite_context *c;
699 struct domain_close_lsa_state *s;
700 struct tevent_req *subreq;
702 /* composite context and state structure allocation */
703 c = composite_create(mem_ctx, ctx->event_ctx);
704 if (c == NULL) return c;
706 s = talloc_zero(c, struct domain_close_lsa_state);
707 if (composite_nomem(s, c)) return c;
709 c->private_data = s;
710 s->monitor_fn = monitor;
712 /* TODO: check if lsa pipe pointer is non-null */
714 if (!strequal(ctx->lsa.name, io->in.domain_name)) {
715 composite_error(c, NT_STATUS_INVALID_PARAMETER);
716 return c;
719 /* get opened lsarpc pipe pointer */
720 s->pipe = ctx->lsa.pipe;
722 /* prepare close handle call arguments */
723 s->close.in.handle = &ctx->lsa.handle;
724 s->close.out.handle = &s->handle;
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;
732 tevent_req_set_callback(subreq, continue_lsa_close, c);
733 return c;
738 Stage 1: Receive result of lsa close call
740 static void continue_lsa_close(struct tevent_req *subreq)
742 struct composite_context *c;
743 struct domain_close_lsa_state *s;
745 c = tevent_req_callback_data(subreq, struct composite_context);
746 s = talloc_get_type_abort(c->private_data, struct domain_close_lsa_state);
748 c->status = dcerpc_lsa_Close_r_recv(subreq, s);
749 TALLOC_FREE(subreq);
750 if (!composite_is_ok(c)) return;
752 if (s->monitor_fn) {
753 struct monitor_msg msg;
755 msg.type = mon_LsaClose;
756 msg.data = NULL;
757 msg.data_size = 0;
758 s->monitor_fn(&msg);
761 composite_done(c);
765 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
766 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
768 NTSTATUS status;
770 status = composite_wait(c);
772 if (NT_STATUS_IS_OK(status) && io) {
773 /* policy handle closed successfully */
775 ctx->lsa.name = NULL;
776 ZERO_STRUCT(ctx->lsa.handle);
778 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
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));
785 talloc_free(c);
786 return status;
790 struct domain_close_samr_state {
791 struct samr_Close close;
792 struct policy_handle handle;
794 void (*monitor_fn)(struct monitor_msg*);
798 static void continue_samr_close(struct tevent_req *subreq);
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*))
806 struct composite_context *c;
807 struct domain_close_samr_state *s;
808 struct tevent_req *subreq;
810 /* composite context and state structure allocation */
811 c = composite_create(mem_ctx, ctx->event_ctx);
812 if (c == NULL) return c;
814 s = talloc_zero(c, struct domain_close_samr_state);
815 if (composite_nomem(s, c)) return c;
817 c->private_data = s;
818 s->monitor_fn = monitor;
820 /* TODO: check if samr pipe pointer is non-null */
822 if (!strequal(ctx->samr.name, io->in.domain_name)) {
823 composite_error(c, NT_STATUS_INVALID_PARAMETER);
824 return c;
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;
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;
838 tevent_req_set_callback(subreq, continue_samr_close, c);
839 return c;
844 Stage 1: Receive result of samr close call
846 static void continue_samr_close(struct tevent_req *subreq)
848 struct composite_context *c;
849 struct domain_close_samr_state *s;
851 c = tevent_req_callback_data(subreq, struct composite_context);
852 s = talloc_get_type_abort(c->private_data, struct domain_close_samr_state);
854 c->status = dcerpc_samr_Close_r_recv(subreq, s);
855 TALLOC_FREE(subreq);
856 if (!composite_is_ok(c)) return;
858 if (s->monitor_fn) {
859 struct monitor_msg msg;
861 msg.type = mon_SamrClose;
862 msg.data = NULL;
863 msg.data_size = 0;
864 s->monitor_fn(&msg);
867 composite_done(c);
871 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
872 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
874 NTSTATUS status;
876 status = composite_wait(c);
878 if (NT_STATUS_IS_OK(status) && io) {
879 /* domain policy handle closed successfully */
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;
887 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
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));
894 talloc_free(c);
895 return status;
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*))
904 struct composite_context *c;
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;
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;
919 return c;
923 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
924 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
926 NTSTATUS status;
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;
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;
941 return status;
945 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
946 struct libnet_DomainClose *io)
948 struct composite_context *c;
950 c = libnet_DomainClose_send(ctx, mem_ctx, io, NULL);
951 return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
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;
968 void (*monitor_fn)(struct monitor_msg*);
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);
977 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
981 Stage 1: Receive connected rpc pipe and send connection
982 request to SAMR service
984 static void continue_rpc_connect(struct composite_context *ctx)
986 struct composite_context *c;
987 struct domain_list_state *s;
988 struct tevent_req *subreq;
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);
993 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
994 if (!composite_is_ok(c)) return;
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;
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;
1005 tevent_req_set_callback(subreq, continue_samr_connect, c);
1010 Stage 2: Receive policy handle to the connected SAMR service and issue
1011 a request to enumerate domain databases available
1013 static void continue_samr_connect(struct tevent_req *subreq)
1015 struct composite_context *c;
1016 struct domain_list_state *s;
1018 c = tevent_req_callback_data(subreq, struct composite_context);
1019 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1021 c->status = dcerpc_samr_Connect_r_recv(subreq, s);
1022 TALLOC_FREE(subreq);
1023 if (!composite_is_ok(c)) return;
1025 if (s->monitor_fn) {
1026 struct monitor_msg msg;
1028 msg.type = mon_SamrConnect;
1029 msg.data = NULL;
1030 msg.data_size = 0;
1031 s->monitor_fn(&msg);
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;
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;
1048 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1053 Stage 3: Receive domain names available and repeat the request
1054 enumeration is not complete yet. Close samr connection handle
1055 upon completion.
1057 static void continue_samr_enum_domains(struct tevent_req *subreq)
1059 struct composite_context *c;
1060 struct domain_list_state *s;
1062 c = tevent_req_callback_data(subreq, struct composite_context);
1063 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1065 c->status = dcerpc_samr_EnumDomains_r_recv(subreq, s);
1066 TALLOC_FREE(subreq);
1067 if (!composite_is_ok(c)) return;
1069 if (s->monitor_fn) {
1070 struct monitor_msg msg;
1072 msg.type = mon_SamrEnumDomains;
1073 msg.data = NULL;
1074 msg.data_size = 0;
1075 s->monitor_fn(&msg);
1078 if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
1080 s->domains = get_domain_list(c, s);
1082 } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
1084 s->domains = get_domain_list(c, s);
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;
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;
1098 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1100 } else {
1101 composite_error(c, s->enumdom.out.result);
1102 return;
1105 /* close samr connection handle */
1106 s->samrclose.in.handle = &s->connect_handle;
1107 s->samrclose.out.handle = &s->connect_handle;
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;
1115 tevent_req_set_callback(subreq, continue_samr_close_handle, c);
1120 Stage 4: Receive result of closing samr connection handle.
1122 static void continue_samr_close_handle(struct tevent_req *subreq)
1124 struct composite_context *c;
1125 struct domain_list_state *s;
1127 c = tevent_req_callback_data(subreq, struct composite_context);
1128 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1130 c->status = dcerpc_samr_Close_r_recv(subreq, s);
1131 TALLOC_FREE(subreq);
1132 if (!composite_is_ok(c)) return;
1134 if (s->monitor_fn) {
1135 struct monitor_msg msg;
1137 msg.type = mon_SamrClose;
1138 msg.data = NULL;
1139 msg.data_size = 0;
1140 s->monitor_fn(&msg);
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;
1149 composite_done(c);
1154 Utility function to copy domain names from result of samr_EnumDomains call
1156 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
1158 uint32_t i;
1159 if (mem_ctx == NULL || s == NULL) return NULL;
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);
1170 /* copy domain names returned from samr_EnumDomains call */
1171 for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
1173 struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
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 */
1181 /* number of entries returned (domains enumerated) */
1182 s->count += *s->enumdom.out.num_entries;
1184 return s->domains;
1189 * Sends a request to list domains on given host
1191 * @param ctx initalised 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
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*))
1202 struct composite_context *c;
1203 struct domain_list_state *s;
1204 struct composite_context *rpcconn_req;
1205 struct tevent_req *subreq;
1207 /* composite context and state structure allocation */
1208 c = composite_create(ctx, ctx->event_ctx);
1209 if (c == NULL) return c;
1211 s = talloc_zero(c, struct domain_list_state);
1212 if (composite_nomem(s, c)) return c;
1214 c->private_data = s;
1215 s->monitor_fn = monitor;
1217 s->ctx = ctx;
1218 s->hostname = talloc_strdup(c, io->in.hostname);
1219 if (composite_nomem(s->hostname, c)) return c;
1221 /* check whether samr pipe has already been opened */
1222 if (ctx->samr.pipe == NULL) {
1223 ZERO_STRUCT(s->rpcconn);
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;
1230 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
1231 if (composite_nomem(rpcconn_req, c)) return c;
1233 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
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;
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;
1246 tevent_req_set_callback(subreq, continue_samr_connect, c);
1249 return c;
1254 * Receive result of domain list request
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
1262 NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
1263 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
1265 NTSTATUS status;
1266 struct domain_list_state *s;
1268 status = composite_wait(c);
1270 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
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");
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));
1283 talloc_free(c);
1284 return status;
1289 * Synchronous version of DomainList call
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
1297 NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1298 struct libnet_DomainList *io)
1300 struct composite_context *c;
1302 c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
1303 return libnet_DomainList_recv(c, ctx, mem_ctx, io);