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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 a composite function for domain handling on samr and lsa pipes
26 #include "libcli/composite/composite.h"
27 #include "libnet/libnet.h"
28 #include "librpc/gen_ndr/ndr_samr_c.h"
29 #include "librpc/gen_ndr/ndr_lsa_c.h"
32 struct domain_open_samr_state
{
33 struct libnet_context
*ctx
;
34 struct dcerpc_pipe
*pipe
;
35 struct libnet_RpcConnect rpcconn
;
36 struct samr_Connect connect
;
37 struct samr_LookupDomain lookup
;
38 struct samr_OpenDomain open
;
39 struct samr_Close close
;
40 struct lsa_String domain_name
;
42 struct policy_handle connect_handle
;
43 struct policy_handle domain_handle
;
45 /* information about the progress */
46 void (*monitor_fn
)(struct monitor_msg
*);
50 static void continue_domain_open_close(struct rpc_request
*req
);
51 static void continue_domain_open_connect(struct rpc_request
*req
);
52 static void continue_domain_open_lookup(struct rpc_request
*req
);
53 static void continue_domain_open_open(struct rpc_request
*req
);
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 rpc_request
*conn_req
;
65 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
66 s
= talloc_get_type(c
->private_data
, struct domain_open_samr_state
);
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 conn_req
= dcerpc_samr_Connect_send(s
->pipe
, c
, &s
->connect
);
80 if (composite_nomem(conn_req
, c
)) return;
82 /* callback handler */
83 composite_continue_rpc(c
, conn_req
, continue_domain_open_connect
, c
);
88 * Stage 0.5 (optional): Close existing (in libnet context) domain
91 static void continue_domain_open_close(struct rpc_request
*req
)
93 struct composite_context
*c
;
94 struct domain_open_samr_state
*s
;
95 struct rpc_request
*conn_req
;
97 c
= talloc_get_type(req
->async
.private, struct composite_context
);
98 s
= talloc_get_type(c
->private_data
, struct domain_open_samr_state
);
100 /* receive samr_Close reply */
101 c
->status
= dcerpc_ndr_request_recv(req
);
102 if (!composite_is_ok(c
)) return;
104 /* reset domain handle and associated data in libnet_context */
105 s
->ctx
->samr
.name
= NULL
;
106 s
->ctx
->samr
.access_mask
= 0;
107 ZERO_STRUCT(s
->ctx
->samr
.handle
);
109 /* preparing parameters for samr_Connect rpc call */
110 s
->connect
.in
.system_name
= 0;
111 s
->connect
.in
.access_mask
= s
->access_mask
;
112 s
->connect
.out
.connect_handle
= &s
->connect_handle
;
115 conn_req
= dcerpc_samr_Connect_send(s
->pipe
, c
, &s
->connect
);
116 if (composite_nomem(conn_req
, c
)) return;
118 /* callback handler */
119 composite_continue_rpc(c
, conn_req
, continue_domain_open_connect
, c
);
124 * Stage 1: Connect to SAM server.
126 static void continue_domain_open_connect(struct rpc_request
*req
)
128 struct composite_context
*c
;
129 struct domain_open_samr_state
*s
;
130 struct rpc_request
*lookup_req
;
131 struct samr_LookupDomain
*r
;
133 c
= talloc_get_type(req
->async
.private, struct composite_context
);
134 s
= talloc_get_type(c
->private_data
, struct domain_open_samr_state
);
136 /* receive samr_Connect reply */
137 c
->status
= dcerpc_ndr_request_recv(req
);
138 if (!composite_is_ok(c
)) return;
142 /* prepare for samr_LookupDomain call */
143 r
->in
.connect_handle
= &s
->connect_handle
;
144 r
->in
.domain_name
= &s
->domain_name
;
146 lookup_req
= dcerpc_samr_LookupDomain_send(s
->pipe
, c
, r
);
147 if (composite_nomem(lookup_req
, c
)) return;
149 composite_continue_rpc(c
, lookup_req
, continue_domain_open_lookup
, c
);
154 * Stage 2: Lookup domain by name.
156 static void continue_domain_open_lookup(struct rpc_request
*req
)
158 struct composite_context
*c
;
159 struct domain_open_samr_state
*s
;
160 struct rpc_request
*opendom_req
;
161 struct samr_OpenDomain
*r
;
163 c
= talloc_get_type(req
->async
.private, struct composite_context
);
164 s
= talloc_get_type(c
->private_data
, struct domain_open_samr_state
);
166 /* receive samr_LookupDomain reply */
167 c
->status
= dcerpc_ndr_request_recv(req
);
171 /* check the rpc layer status */
172 if (!composite_is_ok(c
));
174 /* check the rpc call itself status */
175 if (!NT_STATUS_IS_OK(s
->lookup
.out
.result
)) {
176 composite_error(c
, s
->lookup
.out
.result
);
180 /* prepare for samr_OpenDomain call */
181 r
->in
.connect_handle
= &s
->connect_handle
;
182 r
->in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
183 r
->in
.sid
= s
->lookup
.out
.sid
;
184 r
->out
.domain_handle
= &s
->domain_handle
;
186 opendom_req
= dcerpc_samr_OpenDomain_send(s
->pipe
, c
, r
);
187 if (composite_nomem(opendom_req
, c
)) return;
189 composite_continue_rpc(c
, opendom_req
, continue_domain_open_open
, c
);
194 * Stage 3: Open domain.
196 static void continue_domain_open_open(struct rpc_request
*req
)
198 struct composite_context
*c
;
199 struct domain_open_samr_state
*s
;
201 c
= talloc_get_type(req
->async
.private, struct composite_context
);
202 s
= talloc_get_type(c
->private_data
, struct domain_open_samr_state
);
204 /* receive samr_OpenDomain reply */
205 c
->status
= dcerpc_ndr_request_recv(req
);
206 if (!composite_is_ok(c
)) return;
213 * Sends asynchronous DomainOpenSamr request
215 * @param ctx initialised libnet context
216 * @param io arguments and results of the call
217 * @param monitor pointer to monitor function that is passed monitor message
220 struct composite_context
*libnet_DomainOpenSamr_send(struct libnet_context
*ctx
,
221 struct libnet_DomainOpen
*io
,
222 void (*monitor
)(struct monitor_msg
*))
224 struct composite_context
*c
;
225 struct domain_open_samr_state
*s
;
226 struct composite_context
*rpcconn_req
;
227 struct rpc_request
*close_req
, *conn_req
;
229 c
= composite_create(ctx
, ctx
->event_ctx
);
230 if (c
== NULL
) return NULL
;
232 s
= talloc_zero(c
, struct domain_open_samr_state
);
233 if (composite_nomem(s
, c
)) return c
;
236 s
->monitor_fn
= monitor
;
239 s
->pipe
= ctx
->samr
.pipe
;
240 s
->access_mask
= io
->in
.access_mask
;
241 s
->domain_name
.string
= talloc_strdup(c
, io
->in
.domain_name
);
243 /* check, if there's samr pipe opened already, before opening a domain */
244 if (ctx
->samr
.pipe
== NULL
) {
246 /* attempting to connect a domain controller */
247 s
->rpcconn
.level
= LIBNET_RPC_CONNECT_DC
;
248 s
->rpcconn
.in
.name
= io
->in
.domain_name
;
249 s
->rpcconn
.in
.dcerpc_iface
= &dcerpc_table_samr
;
251 /* send rpc pipe connect request */
252 rpcconn_req
= libnet_RpcConnect_send(ctx
, c
, &s
->rpcconn
);
253 if (composite_nomem(rpcconn_req
, c
)) return c
;
255 composite_continue(c
, rpcconn_req
, continue_domain_open_rpc_connect
, c
);
259 /* libnet context's domain handle is not empty, so check out what
260 was opened first, before doing anything */
261 if (!policy_handle_empty(&ctx
->samr
.handle
)) {
262 if (strequal(ctx
->samr
.name
, io
->in
.domain_name
) &&
263 ctx
->samr
.access_mask
== io
->in
.access_mask
) {
265 /* this domain is already opened */
270 /* another domain or access rights have been
271 requested - close the existing handle first */
272 s
->close
.in
.handle
= &ctx
->samr
.handle
;
274 /* send request to close domain handle */
275 close_req
= dcerpc_samr_Close_send(s
->pipe
, c
, &s
->close
);
276 if (composite_nomem(close_req
, c
)) return c
;
278 /* callback handler */
279 composite_continue_rpc(c
, close_req
, continue_domain_open_close
, c
);
284 /* preparing parameters for samr_Connect rpc call */
285 s
->connect
.in
.system_name
= 0;
286 s
->connect
.in
.access_mask
= s
->access_mask
;
287 s
->connect
.out
.connect_handle
= &s
->connect_handle
;
290 conn_req
= dcerpc_samr_Connect_send(s
->pipe
, c
, &s
->connect
);
291 if (composite_nomem(conn_req
, c
)) return c
;
293 /* callback handler */
294 composite_continue_rpc(c
, conn_req
, continue_domain_open_connect
, c
);
300 * Waits for and receives result of asynchronous DomainOpenSamr call
302 * @param c composite context returned by asynchronous DomainOpen call
303 * @param ctx initialised libnet context
304 * @param mem_ctx memory context of the call
305 * @param io pointer to results (and arguments) of the call
306 * @return nt status code of execution
309 NTSTATUS
libnet_DomainOpenSamr_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
310 TALLOC_CTX
*mem_ctx
, struct libnet_DomainOpen
*io
)
313 struct domain_open_samr_state
*s
;
315 /* wait for results of sending request */
316 status
= composite_wait(c
);
318 if (NT_STATUS_IS_OK(status
) && io
) {
319 s
= talloc_get_type(c
->private_data
, struct domain_open_samr_state
);
320 io
->out
.domain_handle
= s
->domain_handle
;
322 /* store the resulting handle and related data for use by other
324 ctx
->samr
.handle
= s
->domain_handle
;
325 ctx
->samr
.name
= talloc_steal(ctx
, s
->domain_name
.string
);
326 ctx
->samr
.access_mask
= s
->access_mask
;
334 struct domain_open_lsa_state
{
336 uint32_t access_mask
;
337 struct libnet_context
*ctx
;
338 struct libnet_RpcConnect rpcconn
;
339 struct lsa_OpenPolicy2 openpol
;
340 struct policy_handle handle
;
341 struct dcerpc_pipe
*pipe
;
343 /* information about the progress */
344 void (*monitor_fn
)(struct monitor_msg
*);
348 static void continue_rpc_connect_lsa(struct composite_context
*ctx
);
349 static void continue_lsa_policy_open(struct rpc_request
*req
);
353 * Sends asynchronous DomainOpenLsa request
355 * @param ctx initialised libnet context
356 * @param io arguments and results of the call
357 * @param monitor pointer to monitor function that is passed monitor message
360 struct composite_context
* libnet_DomainOpenLsa_send(struct libnet_context
*ctx
,
361 struct libnet_DomainOpen
*io
,
362 void (*monitor
)(struct monitor_msg
*))
364 struct composite_context
*c
;
365 struct domain_open_lsa_state
*s
;
366 struct composite_context
*rpcconn_req
;
367 struct rpc_request
*openpol_req
;
368 struct lsa_QosInfo
*qos
;
370 /* create composite context and state */
371 c
= composite_create(ctx
, ctx
->event_ctx
);
372 if (c
== NULL
) return c
;
374 s
= talloc_zero(c
, struct domain_open_lsa_state
);
375 if (composite_nomem(s
, c
)) return c
;
379 /* store arguments in the state structure */
380 s
->name
= talloc_strdup(c
, io
->in
.domain_name
);
381 s
->access_mask
= io
->in
.access_mask
;
384 /* check, if there's lsa pipe opened already, before opening a handle */
385 if (ctx
->lsa
.pipe
== NULL
) {
387 /* attempting to connect a domain controller */
388 s
->rpcconn
.level
= LIBNET_RPC_CONNECT_DC
;
389 s
->rpcconn
.in
.name
= talloc_strdup(c
, io
->in
.domain_name
);
390 s
->rpcconn
.in
.dcerpc_iface
= &dcerpc_table_lsarpc
;
392 /* send rpc pipe connect request */
393 rpcconn_req
= libnet_RpcConnect_send(ctx
, c
, &s
->rpcconn
);
394 if (composite_nomem(rpcconn_req
, c
)) return c
;
396 composite_continue(c
, rpcconn_req
, continue_rpc_connect_lsa
, c
);
400 s
->pipe
= ctx
->lsa
.pipe
;
402 /* preparing parameters for lsa_OpenPolicy2 rpc call */
403 s
->openpol
.in
.system_name
= s
->name
;
404 s
->openpol
.in
.access_mask
= s
->access_mask
;
405 s
->openpol
.in
.attr
= talloc_zero(c
, struct lsa_ObjectAttribute
);
407 qos
= talloc_zero(c
, struct lsa_QosInfo
);
409 qos
->impersonation_level
= 2;
410 qos
->context_mode
= 1;
411 qos
->effective_only
= 0;
413 s
->openpol
.in
.attr
->sec_qos
= qos
;
414 s
->openpol
.out
.handle
= &s
->handle
;
416 /* send rpc request */
417 openpol_req
= dcerpc_lsa_OpenPolicy2_send(s
->pipe
, c
, &s
->openpol
);
418 if (composite_nomem(openpol_req
, c
)) return c
;
420 composite_continue_rpc(c
, openpol_req
, continue_lsa_policy_open
, c
);
426 Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
428 static void continue_rpc_connect_lsa(struct composite_context
*ctx
)
430 struct composite_context
*c
;
431 struct domain_open_lsa_state
*s
;
432 struct lsa_QosInfo
*qos
;
433 struct rpc_request
*openpol_req
;
435 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
436 s
= talloc_get_type(c
->private_data
, struct domain_open_lsa_state
);
438 /* receive rpc connection */
439 c
->status
= libnet_RpcConnect_recv(ctx
, s
->ctx
, c
, &s
->rpcconn
);
440 if (!composite_is_ok(c
)) return;
442 /* RpcConnect function leaves the pipe in libnet context,
443 so get it from there */
444 s
->pipe
= s
->ctx
->lsa
.pipe
;
446 /* prepare lsa_OpenPolicy2 call */
447 s
->openpol
.in
.system_name
= s
->name
;
448 s
->openpol
.in
.access_mask
= s
->access_mask
;
449 s
->openpol
.in
.attr
= talloc_zero(c
, struct lsa_ObjectAttribute
);
451 qos
= talloc_zero(c
, struct lsa_QosInfo
);
453 qos
->impersonation_level
= 2;
454 qos
->context_mode
= 1;
455 qos
->effective_only
= 0;
457 s
->openpol
.in
.attr
->sec_qos
= qos
;
458 s
->openpol
.out
.handle
= &s
->handle
;
460 /* send rpc request */
461 openpol_req
= dcerpc_lsa_OpenPolicy2_send(s
->pipe
, c
, &s
->openpol
);
462 if (composite_nomem(openpol_req
, c
)) return;
464 composite_continue_rpc(c
, openpol_req
, continue_lsa_policy_open
, c
);
469 Stage 1: Lsa policy opened - we're done, if successfully
471 static void continue_lsa_policy_open(struct rpc_request
*req
)
473 struct composite_context
*c
;
474 struct domain_open_lsa_state
*s
;
476 c
= talloc_get_type(req
->async
.private, struct composite_context
);
477 s
= talloc_get_type(c
->private_data
, struct domain_open_lsa_state
);
479 c
->status
= dcerpc_ndr_request_recv(req
);
480 if (!composite_is_ok(c
)) return;
487 * Receives result of asynchronous DomainOpenLsa call
489 * @param c composite context returned by asynchronous DomainOpenLsa call
490 * @param ctx initialised libnet context
491 * @param mem_ctx memory context of the call
492 * @param io pointer to results (and arguments) of the call
493 * @return nt status code of execution
496 NTSTATUS
libnet_DomainOpenLsa_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
497 TALLOC_CTX
*mem_ctx
, struct libnet_DomainOpen
*io
)
500 struct domain_open_lsa_state
*s
;
502 status
= composite_wait(c
);
504 if (NT_STATUS_IS_OK(status
) && io
) {
505 /* everything went fine - get the results and
506 return the error string */
507 s
= talloc_get_type(c
->private_data
, struct domain_open_lsa_state
);
508 io
->out
.domain_handle
= s
->handle
;
510 ctx
->lsa
.handle
= s
->handle
;
511 ctx
->lsa
.name
= talloc_steal(ctx
, s
->name
);
512 ctx
->lsa
.access_mask
= s
->access_mask
;
514 io
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
516 } else if (!NT_STATUS_IS_OK(status
)) {
517 /* there was an error, so provide nt status code description */
518 io
->out
.error_string
= talloc_asprintf(mem_ctx
,
519 "Failed to open domain: %s",
529 * Sends a request to open a domain in desired service
531 * @param ctx initalised libnet context
532 * @param io arguments and results of the call
533 * @param monitor pointer to monitor function that is passed monitor message
536 struct composite_context
* libnet_DomainOpen_send(struct libnet_context
*ctx
,
537 struct libnet_DomainOpen
*io
,
538 void (*monitor
)(struct monitor_msg
*))
540 struct composite_context
*c
;
542 switch (io
->in
.type
) {
544 /* reques to open a policy handle on \pipe\lsarpc */
545 c
= libnet_DomainOpenLsa_send(ctx
, io
, monitor
);
550 /* request to open a domain policy handle on \pipe\samr */
551 c
= libnet_DomainOpenSamr_send(ctx
, io
, monitor
);
560 * Receive result of domain open request
562 * @param c composite context returned by DomainOpen_send function
563 * @param ctx initialised libnet context
564 * @param mem_ctx memory context of the call
565 * @param io results and arguments of the call
568 NTSTATUS
libnet_DomainOpen_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
569 TALLOC_CTX
*mem_ctx
, struct libnet_DomainOpen
*io
)
573 switch (io
->in
.type
) {
575 status
= libnet_DomainOpenLsa_recv(c
, ctx
, mem_ctx
, io
);
580 status
= libnet_DomainOpenSamr_recv(c
, ctx
, mem_ctx
, io
);
589 * Synchronous version of DomainOpen call
591 * @param ctx initialised libnet context
592 * @param mem_ctx memory context for the call
593 * @param io arguments and results of the call
594 * @return nt status code of execution
597 NTSTATUS
libnet_DomainOpen(struct libnet_context
*ctx
,
599 struct libnet_DomainOpen
*io
)
601 struct composite_context
*c
= libnet_DomainOpen_send(ctx
, io
, NULL
);
602 return libnet_DomainOpen_recv(c
, ctx
, mem_ctx
, io
);
606 struct domain_close_lsa_state
{
607 struct dcerpc_pipe
*pipe
;
608 struct lsa_Close close
;
609 struct policy_handle handle
;
611 void (*monitor_fn
)(struct monitor_msg
*);
615 static void continue_lsa_close(struct rpc_request
*req
);
618 struct composite_context
* libnet_DomainCloseLsa_send(struct libnet_context
*ctx
,
619 struct libnet_DomainClose
*io
,
620 void (*monitor
)(struct monitor_msg
*))
622 struct composite_context
*c
;
623 struct domain_close_lsa_state
*s
;
624 struct rpc_request
*close_req
;
626 /* composite context and state structure allocation */
627 c
= composite_create(ctx
, ctx
->event_ctx
);
628 if (c
== NULL
) return c
;
630 s
= talloc_zero(c
, struct domain_close_lsa_state
);
631 if (composite_nomem(s
, c
)) return c
;
634 s
->monitor_fn
= monitor
;
636 /* TODO: check if lsa pipe pointer is non-null */
638 if (!strequal(ctx
->lsa
.name
, io
->in
.domain_name
)) {
639 composite_error(c
, NT_STATUS_INVALID_PARAMETER
);
643 /* get opened lsarpc pipe pointer */
644 s
->pipe
= ctx
->lsa
.pipe
;
646 /* prepare close handle call arguments */
647 s
->close
.in
.handle
= &ctx
->lsa
.handle
;
648 s
->close
.out
.handle
= &s
->handle
;
650 /* send the request */
651 close_req
= dcerpc_lsa_Close_send(s
->pipe
, c
, &s
->close
);
652 if (composite_nomem(close_req
, c
)) return c
;
654 composite_continue_rpc(c
, close_req
, continue_lsa_close
, c
);
660 Stage 1: Receive result of lsa close call
662 static void continue_lsa_close(struct rpc_request
*req
)
664 struct composite_context
*c
;
665 struct domain_close_lsa_state
*s
;
667 c
= talloc_get_type(req
->async
.private, struct composite_context
);
668 s
= talloc_get_type(c
->private_data
, struct domain_close_lsa_state
);
670 c
->status
= dcerpc_ndr_request_recv(req
);
671 if (!composite_is_ok(c
)) return;
677 NTSTATUS
libnet_DomainCloseLsa_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
678 TALLOC_CTX
*mem_ctx
, struct libnet_DomainClose
*io
)
682 status
= composite_wait(c
);
684 if (NT_STATUS_IS_OK(status
) && io
) {
685 /* policy handle closed successfully */
687 ctx
->lsa
.name
= NULL
;
688 ZERO_STRUCT(ctx
->lsa
.handle
);
690 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success");
692 } else if (!NT_STATUS_IS_OK(status
)) {
693 /* there was an error, so return description of the status code */
694 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
702 struct domain_close_samr_state
{
703 struct samr_Close close
;
704 struct policy_handle handle
;
706 void (*monitor_fn
)(struct monitor_msg
*);
710 static void continue_samr_close(struct rpc_request
*req
);
713 struct composite_context
* libnet_DomainCloseSamr_send(struct libnet_context
*ctx
,
714 struct libnet_DomainClose
*io
,
715 void (*monitor
)(struct monitor_msg
*))
717 struct composite_context
*c
;
718 struct domain_close_samr_state
*s
;
719 struct rpc_request
*close_req
;
721 /* composite context and state structure allocation */
722 c
= composite_create(ctx
, ctx
->event_ctx
);
723 if (c
== NULL
) return c
;
725 s
= talloc_zero(c
, struct domain_close_samr_state
);
726 if (composite_nomem(s
, c
)) return c
;
729 s
->monitor_fn
= monitor
;
731 /* TODO: check if samr pipe pointer is non-null */
733 if (!strequal(ctx
->samr
.name
, io
->in
.domain_name
)) {
734 composite_error(c
, NT_STATUS_INVALID_PARAMETER
);
738 /* prepare close domain handle call arguments */
739 ZERO_STRUCT(s
->close
);
740 s
->close
.in
.handle
= &ctx
->samr
.handle
;
741 s
->close
.out
.handle
= &s
->handle
;
743 /* send the request */
744 close_req
= dcerpc_samr_Close_send(ctx
->samr
.pipe
, ctx
, &s
->close
);
745 if (composite_nomem(close_req
, c
)) return c
;
747 composite_continue_rpc(c
, close_req
, continue_samr_close
, c
);
753 Stage 1: Receive result of samr close call
755 static void continue_samr_close(struct rpc_request
*req
)
757 struct composite_context
*c
;
758 struct domain_close_samr_state
*s
;
760 c
= talloc_get_type(req
->async
.private, struct composite_context
);
761 s
= talloc_get_type(c
->private_data
, struct domain_close_samr_state
);
763 c
->status
= dcerpc_ndr_request_recv(req
);
764 if (!composite_is_ok(c
)) return;
770 NTSTATUS
libnet_DomainCloseSamr_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
771 TALLOC_CTX
*mem_ctx
, struct libnet_DomainClose
*io
)
775 status
= composite_wait(c
);
777 if (NT_STATUS_IS_OK(status
) && io
) {
778 /* domain policy handle closed successfully */
780 ZERO_STRUCT(ctx
->samr
.handle
);
781 ctx
->samr
.name
= NULL
;
783 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success");
785 } else if (!NT_STATUS_IS_OK(status
)) {
786 /* there was an error, so return description of the status code */
787 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
795 struct composite_context
* libnet_DomainClose_send(struct libnet_context
*ctx
,
796 struct libnet_DomainClose
*io
,
797 void (*monitor
)(struct monitor_msg
*))
799 struct composite_context
*c
;
801 switch (io
->in
.type
) {
803 /* request to close policy handle on \pipe\lsarpc */
804 c
= libnet_DomainCloseLsa_send(ctx
, io
, monitor
);
809 /* request to close domain policy handle on \pipe\samr */
810 c
= libnet_DomainCloseSamr_send(ctx
, io
, monitor
);
818 NTSTATUS
libnet_DomainClose_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
819 TALLOC_CTX
*mem_ctx
, struct libnet_DomainClose
*io
)
823 switch (io
->in
.type
) {
825 /* receive result of closing lsa policy handle */
826 status
= libnet_DomainCloseLsa_recv(c
, ctx
, mem_ctx
, io
);
831 /* receive result of closing samr domain policy handle */
832 status
= libnet_DomainCloseSamr_recv(c
, ctx
, mem_ctx
, io
);
840 NTSTATUS
libnet_DomainClose(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
841 struct libnet_DomainClose
*io
)
843 struct composite_context
*c
;
845 c
= libnet_DomainClose_send(ctx
, io
, NULL
);
846 return libnet_DomainClose_recv(c
, ctx
, mem_ctx
, io
);
850 struct domain_list_state
{
851 struct libnet_context
*ctx
;
852 struct libnet_RpcConnect rpcconn
;
853 struct samr_Connect samrconn
;
854 struct samr_EnumDomains enumdom
;
855 struct samr_Close samrclose
;
856 const char *hostname
;
857 struct policy_handle connect_handle
;
859 struct domainlist
*domains
;
860 uint32_t resume_handle
;
863 void (*monitor_fn
)(struct monitor_msg
*);
867 static void continue_rpc_connect(struct composite_context
*c
);
868 static void continue_samr_connect(struct rpc_request
*c
);
869 static void continue_samr_enum_domains(struct rpc_request
*req
);
870 static void continue_samr_close_handle(struct rpc_request
*req
);
872 static struct domainlist
* get_domain_list(TALLOC_CTX
*mem_ctx
, struct domain_list_state
*s
);
876 Stage 1: Receive connected rpc pipe and send connection
877 request to SAMR service
879 static void continue_rpc_connect(struct composite_context
*ctx
)
881 struct composite_context
*c
;
882 struct domain_list_state
*s
;
883 struct rpc_request
*samrconn_req
;
885 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
886 s
= talloc_get_type(c
->private_data
, struct domain_list_state
);
888 c
->status
= libnet_RpcConnect_recv(ctx
, s
->ctx
, c
, &s
->rpcconn
);
889 if (!composite_is_ok(c
)) return;
891 s
->samrconn
.in
.system_name
= 0;
892 s
->samrconn
.in
.access_mask
= SEC_GENERIC_READ
; /* should be enough */
893 s
->samrconn
.out
.connect_handle
= &s
->connect_handle
;
895 samrconn_req
= dcerpc_samr_Connect_send(s
->ctx
->samr
.pipe
, c
, &s
->samrconn
);
896 if (composite_nomem(samrconn_req
, c
)) return;
898 composite_continue_rpc(c
, samrconn_req
, continue_samr_connect
, c
);
903 Stage 2: Receive policy handle to the connected SAMR service and issue
904 a request to enumerate domain databases available
906 static void continue_samr_connect(struct rpc_request
*req
)
908 struct composite_context
*c
;
909 struct domain_list_state
*s
;
910 struct rpc_request
*enumdom_req
;
912 c
= talloc_get_type(req
->async
.private, struct composite_context
);
913 s
= talloc_get_type(c
->private_data
, struct domain_list_state
);
915 c
->status
= dcerpc_ndr_request_recv(req
);
916 if (!composite_is_ok(c
)) return;
918 s
->enumdom
.in
.connect_handle
= &s
->connect_handle
;
919 s
->enumdom
.in
.resume_handle
= &s
->resume_handle
;
920 s
->enumdom
.in
.buf_size
= s
->buf_size
;
921 s
->enumdom
.out
.resume_handle
= &s
->resume_handle
;
923 enumdom_req
= dcerpc_samr_EnumDomains_send(s
->ctx
->samr
.pipe
, c
, &s
->enumdom
);
924 if (composite_nomem(enumdom_req
, c
)) return;
926 composite_continue_rpc(c
, enumdom_req
, continue_samr_enum_domains
, c
);
931 Stage 3: Receive domain names available and repeat the request
932 enumeration is not complete yet. Close samr connection handle
935 static void continue_samr_enum_domains(struct rpc_request
*req
)
937 struct composite_context
*c
;
938 struct domain_list_state
*s
;
939 struct rpc_request
*enumdom_req
;
940 struct rpc_request
*samrclose_req
;
942 c
= talloc_get_type(req
->async
.private, struct composite_context
);
943 s
= talloc_get_type(c
->private_data
, struct domain_list_state
);
945 c
->status
= dcerpc_ndr_request_recv(req
);
946 if (!composite_is_ok(c
)) return;
948 if (NT_STATUS_IS_OK(s
->enumdom
.out
.result
)) {
950 s
->domains
= get_domain_list(c
, s
);
952 } else if (NT_STATUS_EQUAL(s
->enumdom
.out
.result
, STATUS_MORE_ENTRIES
)) {
954 s
->domains
= get_domain_list(c
, s
);
956 /* prepare next round of enumeration */
957 s
->enumdom
.in
.connect_handle
= &s
->connect_handle
;
958 s
->enumdom
.in
.resume_handle
= &s
->resume_handle
;
959 s
->enumdom
.in
.buf_size
= s
->ctx
->samr
.buf_size
;
960 s
->enumdom
.out
.resume_handle
= &s
->resume_handle
;
962 /* send the request */
963 enumdom_req
= dcerpc_samr_EnumDomains_send(s
->ctx
->samr
.pipe
, c
, &s
->enumdom
);
964 if (composite_nomem(enumdom_req
, c
)) return;
966 composite_continue_rpc(c
, enumdom_req
, continue_samr_enum_domains
, c
);
969 composite_error(c
, s
->enumdom
.out
.result
);
973 /* close samr connection handle */
974 s
->samrclose
.in
.handle
= &s
->connect_handle
;
975 s
->samrclose
.out
.handle
= &s
->connect_handle
;
977 /* send the request */
978 samrclose_req
= dcerpc_samr_Close_send(s
->ctx
->samr
.pipe
, c
, &s
->samrclose
);
979 if (composite_nomem(samrclose_req
, c
)) return;
981 composite_continue_rpc(c
, samrclose_req
, continue_samr_close_handle
, c
);
986 Stage 4: Receive result of closing samr connection handle.
988 static void continue_samr_close_handle(struct rpc_request
*req
)
990 struct composite_context
*c
;
991 struct domain_list_state
*s
;
993 c
= talloc_get_type(req
->async
.private, struct composite_context
);
994 s
= talloc_get_type(c
->private_data
, struct domain_list_state
);
996 c
->status
= dcerpc_ndr_request_recv(req
);
997 if (!composite_is_ok(c
)) return;
999 /* did everything go fine ? */
1000 if (!NT_STATUS_IS_OK(s
->samrclose
.out
.result
)) {
1001 composite_error(c
, s
->samrclose
.out
.result
);
1009 Utility function to copy domain names from result of samr_EnumDomains call
1011 static struct domainlist
* get_domain_list(TALLOC_CTX
*mem_ctx
, struct domain_list_state
*s
)
1014 if (mem_ctx
== NULL
|| s
== NULL
) return NULL
;
1016 /* prepare domains array */
1017 if (s
->domains
== NULL
) {
1018 s
->domains
= talloc_array(mem_ctx
, struct domainlist
,
1019 s
->enumdom
.out
.num_entries
);
1021 s
->domains
= talloc_realloc(mem_ctx
, s
->domains
, struct domainlist
,
1022 s
->count
+ s
->enumdom
.out
.num_entries
);
1025 /* copy domain names returned from samr_EnumDomains call */
1026 for (i
= s
->count
; i
< s
->count
+ s
->enumdom
.out
.num_entries
; i
++)
1028 struct lsa_String
*domain_name
= &s
->enumdom
.out
.sam
->entries
[i
- s
->count
].name
;
1030 /* strdup name as a child of allocated array to make it follow the array
1031 in case of talloc_steal or talloc_free */
1032 s
->domains
[i
].name
= talloc_strdup(s
->domains
, domain_name
->string
);
1033 s
->domains
[i
].sid
= NULL
; /* this is to be filled out later */
1036 /* number of entries returned (domains enumerated) */
1037 s
->count
+= s
->enumdom
.out
.num_entries
;
1044 * Sends a request to list domains on given host
1046 * @param ctx initalised libnet context
1047 * @param mem_ctx memory context
1048 * @param io arguments and results of the call
1049 * @param monitor pointer to monitor function that is passed monitor messages
1052 struct composite_context
* libnet_DomainList_send(struct libnet_context
*ctx
,
1053 TALLOC_CTX
*mem_ctx
,
1054 struct libnet_DomainList
*io
,
1055 void (*monitor
)(struct monitor_msg
*))
1057 struct composite_context
*c
;
1058 struct domain_list_state
*s
;
1059 struct composite_context
*rpcconn_req
;
1060 struct rpc_request
*samrconn_req
;
1062 /* composite context and state structure allocation */
1063 c
= composite_create(ctx
, ctx
->event_ctx
);
1064 if (c
== NULL
) return c
;
1066 s
= talloc_zero(c
, struct domain_list_state
);
1067 if (composite_nomem(s
, c
)) return c
;
1069 c
->private_data
= s
;
1070 s
->monitor_fn
= monitor
;
1073 s
->hostname
= talloc_strdup(c
, io
->in
.hostname
);
1074 if (composite_nomem(s
->hostname
, c
)) return c
;
1076 /* check whether samr pipe has already been opened */
1077 if (ctx
->samr
.pipe
== NULL
) {
1078 /* prepare rpc connect call */
1079 s
->rpcconn
.level
= LIBNET_RPC_CONNECT_SERVER
;
1080 s
->rpcconn
.in
.name
= s
->hostname
;
1081 s
->rpcconn
.in
.dcerpc_iface
= &dcerpc_table_samr
;
1083 rpcconn_req
= libnet_RpcConnect_send(ctx
, c
, &s
->rpcconn
);
1084 if (composite_nomem(rpcconn_req
, c
)) return c
;
1086 composite_continue(c
, rpcconn_req
, continue_rpc_connect
, c
);
1089 /* prepare samr_Connect call */
1090 s
->samrconn
.in
.system_name
= 0;
1091 s
->samrconn
.in
.access_mask
= SEC_GENERIC_READ
;
1092 s
->samrconn
.out
.connect_handle
= &s
->connect_handle
;
1094 samrconn_req
= dcerpc_samr_Connect_send(s
->ctx
->samr
.pipe
, c
, &s
->samrconn
);
1095 if (composite_nomem(samrconn_req
, c
)) return c
;
1097 composite_continue_rpc(c
, samrconn_req
, continue_samr_connect
, c
);
1105 * Receive result of domain list request
1107 * @param c composite context returned by DomainList_send function
1108 * @param ctx initialised libnet context
1109 * @param mem_ctx memory context of the call
1110 * @param io results and arguments of the call
1113 NTSTATUS
libnet_DomainList_recv(struct composite_context
*c
, struct libnet_context
*ctx
,
1114 TALLOC_CTX
*mem_ctx
, struct libnet_DomainList
*io
)
1117 struct domain_list_state
*s
;
1119 status
= composite_wait(c
);
1121 s
= talloc_get_type(c
->private_data
, struct domain_list_state
);
1123 if (NT_STATUS_IS_OK(status
) && ctx
&& mem_ctx
&& io
) {
1124 /* fetch the results to be returned by io structure */
1125 io
->out
.count
= s
->count
;
1126 io
->out
.domains
= talloc_steal(mem_ctx
, s
->domains
);
1127 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success");
1129 } else if (!NT_STATUS_IS_OK(status
)) {
1130 /* there was an error, so return description of the status code */
1131 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
1140 * Synchronous version of DomainList call
1142 * @param ctx initialised libnet context
1143 * @param mem_ctx memory context for the call
1144 * @param io arguments and results of the call
1145 * @return nt status code of execution
1148 NTSTATUS
libnet_DomainList(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
1149 struct libnet_DomainList
*io
)
1151 struct composite_context
*c
;
1153 c
= libnet_DomainList_send(ctx
, mem_ctx
, io
, NULL
);
1154 return libnet_DomainList_recv(c
, ctx
, mem_ctx
, io
);