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
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
;
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
);
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
;
79 subreq
= dcerpc_samr_Connect_r_send(s
, c
->event_ctx
,
80 s
->pipe
->binding_handle
,
82 if (composite_nomem(subreq
, c
)) return;
84 /* callback handler */
85 tevent_req_set_callback(subreq
, continue_domain_open_connect
, c
);
90 * Stage 0.5 (optional): Close existing (in libnet context) domain
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
);
104 if (!composite_is_ok(c
)) return;
107 struct monitor_msg msg
;
109 msg
.type
= mon_SamrClose
;
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
;
126 subreq
= dcerpc_samr_Connect_r_send(s
, c
->event_ctx
,
127 s
->pipe
->binding_handle
,
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
);
151 if (!composite_is_ok(c
)) return;
154 struct monitor_msg msg
;
156 msg
.type
= mon_SamrConnect
;
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
);
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
);
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
);
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
);
247 if (!composite_is_ok(c
)) return;
250 struct monitor_msg msg
;
252 msg
.type
= mon_SamrOpenDomain
;
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
,
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
;
287 s
->monitor_fn
= monitor
;
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
);
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 */
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
,
329 if (composite_nomem(subreq
, c
)) return c
;
331 /* callback handler */
332 tevent_req_set_callback(subreq
, continue_domain_open_close
, 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
;
343 subreq
= dcerpc_samr_Connect_r_send(s
, c
->event_ctx
,
344 s
->pipe
->binding_handle
,
346 if (composite_nomem(subreq
, c
)) return c
;
348 /* callback handler */
349 tevent_req_set_callback(subreq
, continue_domain_open_connect
, 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
)
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
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
;
391 struct domain_open_lsa_state
{
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
,
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
;
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
;
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
);
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
);
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
,
480 if (composite_nomem(subreq
, c
)) return c
;
482 tevent_req_set_callback(subreq
, continue_lsa_policy_open
, 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
);
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
,
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
);
545 if (!composite_is_ok(c
)) return;
548 struct monitor_msg msg
;
550 msg
.type
= mon_LsaOpenPolicy
;
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
)
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",
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
,
612 struct libnet_DomainOpen
*io
,
613 void (*monitor
)(struct monitor_msg
*))
615 struct composite_context
*c
;
617 switch (io
->in
.type
) {
619 /* reques to open a policy handle on \pipe\lsarpc */
620 c
= libnet_DomainOpenLsa_send(ctx
, mem_ctx
, io
, monitor
);
625 /* request to open a domain policy handle on \pipe\samr */
626 c
= libnet_DomainOpenSamr_send(ctx
, mem_ctx
, io
, monitor
);
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
)
648 switch (io
->in
.type
) {
650 status
= libnet_DomainOpenLsa_recv(c
, ctx
, mem_ctx
, io
);
655 status
= libnet_DomainOpenSamr_recv(c
, ctx
, mem_ctx
, io
);
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
,
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
,
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
;
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
);
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
,
730 if (composite_nomem(subreq
, c
)) return c
;
732 tevent_req_set_callback(subreq
, continue_lsa_close
, 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
);
750 if (!composite_is_ok(c
)) return;
753 struct monitor_msg msg
;
755 msg
.type
= mon_LsaClose
;
765 NTSTATUS
libnet_DomainCloseLsa_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
766 TALLOC_CTX
*mem_ctx
, struct libnet_DomainClose
*io
)
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
));
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
,
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
;
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
);
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
,
836 if (composite_nomem(subreq
, c
)) return c
;
838 tevent_req_set_callback(subreq
, continue_samr_close
, 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
);
856 if (!composite_is_ok(c
)) return;
859 struct monitor_msg msg
;
861 msg
.type
= mon_SamrClose
;
871 NTSTATUS
libnet_DomainCloseSamr_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
872 TALLOC_CTX
*mem_ctx
, struct libnet_DomainClose
*io
)
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
));
899 struct composite_context
* libnet_DomainClose_send(struct libnet_context
*ctx
,
901 struct libnet_DomainClose
*io
,
902 void (*monitor
)(struct monitor_msg
*))
904 struct composite_context
*c
;
906 switch (io
->in
.type
) {
908 /* request to close policy handle on \pipe\lsarpc */
909 c
= libnet_DomainCloseLsa_send(ctx
, mem_ctx
, io
, monitor
);
914 /* request to close domain policy handle on \pipe\samr */
915 c
= libnet_DomainCloseSamr_send(ctx
, mem_ctx
, io
, monitor
);
923 NTSTATUS
libnet_DomainClose_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
924 TALLOC_CTX
*mem_ctx
, struct libnet_DomainClose
*io
)
928 switch (io
->in
.type
) {
930 /* receive result of closing lsa policy handle */
931 status
= libnet_DomainCloseLsa_recv(c
, ctx
, mem_ctx
, io
);
936 /* receive result of closing samr domain policy handle */
937 status
= libnet_DomainCloseSamr_recv(c
, ctx
, mem_ctx
, io
);
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
;
964 struct domainlist
*domains
;
965 uint32_t resume_handle
;
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
,
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
;
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
,
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
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
;
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
,
1096 if (composite_nomem(subreq
, c
)) return;
1098 tevent_req_set_callback(subreq
, continue_samr_enum_domains
, c
);
1101 composite_error(c
, s
->enumdom
.out
.result
);
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
,
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
;
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
);
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
)
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
);
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
;
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
;
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
);
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
,
1244 if (composite_nomem(subreq
, c
)) return c
;
1246 tevent_req_set_callback(subreq
, continue_samr_connect
, 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
)
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
));
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
);