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;
44 /* information about the progress */
45 void (*monitor_fn)(struct monitor_msg*);
49 static void continue_domain_open_close(struct rpc_request *req);
50 static void continue_domain_open_connect(struct rpc_request *req);
51 static void continue_domain_open_lookup(struct rpc_request *req);
52 static void continue_domain_open_open(struct rpc_request *req);
56 * Stage 0.5 (optional): Connect to samr rpc pipe
58 static void continue_domain_open_rpc_connect(struct composite_context *ctx)
60 struct composite_context *c;
61 struct domain_open_samr_state *s;
62 struct rpc_request *conn_req;
64 c = talloc_get_type(ctx->async.private_data, struct composite_context);
65 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
67 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
68 if (!composite_is_ok(c)) return;
70 s->pipe = s->rpcconn.out.dcerpc_pipe;
72 /* preparing parameters for samr_Connect rpc call */
73 s->connect.in.system_name = 0;
74 s->connect.in.access_mask = s->access_mask;
75 s->connect.out.connect_handle = &s->connect_handle;
78 conn_req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
79 if (composite_nomem(conn_req, c)) return;
81 /* callback handler */
82 composite_continue_rpc(c, conn_req, continue_domain_open_connect, c);
87 * Stage 0.5 (optional): Close existing (in libnet context) domain
90 static void continue_domain_open_close(struct rpc_request *req)
92 struct composite_context *c;
93 struct domain_open_samr_state *s;
94 struct rpc_request *conn_req;
96 c = talloc_get_type(req->async.private_data, struct composite_context);
97 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
99 /* receive samr_Close reply */
100 c->status = dcerpc_ndr_request_recv(req);
101 if (!composite_is_ok(c)) return;
104 struct monitor_msg msg;
106 msg.type = mon_SamrClose;
112 /* reset domain handle and associated data in libnet_context */
113 s->ctx->samr.name = NULL;
114 s->ctx->samr.access_mask = 0;
115 ZERO_STRUCT(s->ctx->samr.handle);
117 /* preparing parameters for samr_Connect rpc call */
118 s->connect.in.system_name = 0;
119 s->connect.in.access_mask = s->access_mask;
120 s->connect.out.connect_handle = &s->connect_handle;
123 conn_req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
124 if (composite_nomem(conn_req, c)) return;
126 /* callback handler */
127 composite_continue_rpc(c, conn_req, continue_domain_open_connect, c);
132 * Stage 1: Connect to SAM server.
134 static void continue_domain_open_connect(struct rpc_request *req)
136 struct composite_context *c;
137 struct domain_open_samr_state *s;
138 struct rpc_request *lookup_req;
139 struct samr_LookupDomain *r;
141 c = talloc_get_type(req->async.private_data, struct composite_context);
142 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
144 /* receive samr_Connect reply */
145 c->status = dcerpc_ndr_request_recv(req);
146 if (!composite_is_ok(c)) return;
149 struct monitor_msg msg;
151 msg.type = mon_SamrConnect;
159 /* prepare for samr_LookupDomain call */
160 r->in.connect_handle = &s->connect_handle;
161 r->in.domain_name = &s->domain_name;
163 lookup_req = dcerpc_samr_LookupDomain_send(s->pipe, c, r);
164 if (composite_nomem(lookup_req, c)) return;
166 composite_continue_rpc(c, lookup_req, continue_domain_open_lookup, c);
171 * Stage 2: Lookup domain by name.
173 static void continue_domain_open_lookup(struct rpc_request *req)
175 struct composite_context *c;
176 struct domain_open_samr_state *s;
177 struct rpc_request *opendom_req;
178 struct samr_OpenDomain *r;
180 c = talloc_get_type(req->async.private_data, struct composite_context);
181 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
183 /* receive samr_LookupDomain reply */
184 c->status = dcerpc_ndr_request_recv(req);
187 struct monitor_msg msg;
188 struct msg_rpc_lookup_domain data;
190 data.domain_name = s->domain_name.string;
192 msg.type = mon_SamrLookupDomain;
193 msg.data = (void*)&data;
194 msg.data_size = sizeof(data);
200 /* check the rpc layer status */
201 if (!composite_is_ok(c));
203 /* check the rpc call itself status */
204 if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
205 composite_error(c, s->lookup.out.result);
209 /* prepare for samr_OpenDomain call */
210 r->in.connect_handle = &s->connect_handle;
211 r->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
212 r->in.sid = s->lookup.out.sid;
213 r->out.domain_handle = &s->domain_handle;
215 opendom_req = dcerpc_samr_OpenDomain_send(s->pipe, c, r);
216 if (composite_nomem(opendom_req, c)) return;
218 composite_continue_rpc(c, opendom_req, continue_domain_open_open, c);
223 * Stage 3: Open domain.
225 static void continue_domain_open_open(struct rpc_request *req)
227 struct composite_context *c;
228 struct domain_open_samr_state *s;
230 c = talloc_get_type(req->async.private_data, struct composite_context);
231 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
233 /* receive samr_OpenDomain reply */
234 c->status = dcerpc_ndr_request_recv(req);
235 if (!composite_is_ok(c)) return;
238 struct monitor_msg msg;
240 msg.type = mon_SamrOpenDomain;
251 * Sends asynchronous DomainOpenSamr request
253 * @param ctx initialised libnet context
254 * @param io arguments and results of the call
255 * @param monitor pointer to monitor function that is passed monitor message
258 struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
259 struct libnet_DomainOpen *io,
260 void (*monitor)(struct monitor_msg*))
262 struct composite_context *c;
263 struct domain_open_samr_state *s;
264 struct composite_context *rpcconn_req;
265 struct rpc_request *close_req, *conn_req;
267 c = composite_create(ctx, ctx->event_ctx);
268 if (c == NULL) return NULL;
270 s = talloc_zero(c, struct domain_open_samr_state);
271 if (composite_nomem(s, c)) return c;
274 s->monitor_fn = monitor;
277 s->pipe = ctx->samr.pipe;
278 s->access_mask = io->in.access_mask;
279 s->domain_name.string = talloc_strdup(c, io->in.domain_name);
281 /* check, if there's samr pipe opened already, before opening a domain */
282 if (ctx->samr.pipe == NULL) {
284 /* attempting to connect a domain controller */
285 s->rpcconn.level = LIBNET_RPC_CONNECT_DC;
286 s->rpcconn.in.name = io->in.domain_name;
287 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
289 /* send rpc pipe connect request */
290 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
291 if (composite_nomem(rpcconn_req, c)) return c;
293 composite_continue(c, rpcconn_req, continue_domain_open_rpc_connect, c);
297 /* libnet context's domain handle is not empty, so check out what
298 was opened first, before doing anything */
299 if (!policy_handle_empty(&ctx->samr.handle)) {
300 if (strequal(ctx->samr.name, io->in.domain_name) &&
301 ctx->samr.access_mask == io->in.access_mask) {
303 /* this domain is already opened */
308 /* another domain or access rights have been
309 requested - close the existing handle first */
310 s->close.in.handle = &ctx->samr.handle;
312 /* send request to close domain handle */
313 close_req = dcerpc_samr_Close_send(s->pipe, c, &s->close);
314 if (composite_nomem(close_req, c)) return c;
316 /* callback handler */
317 composite_continue_rpc(c, close_req, continue_domain_open_close, c);
322 /* preparing parameters for samr_Connect rpc call */
323 s->connect.in.system_name = 0;
324 s->connect.in.access_mask = s->access_mask;
325 s->connect.out.connect_handle = &s->connect_handle;
328 conn_req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
329 if (composite_nomem(conn_req, c)) return c;
331 /* callback handler */
332 composite_continue_rpc(c, conn_req, continue_domain_open_connect, c);
338 * Waits for and receives result of asynchronous DomainOpenSamr call
340 * @param c composite context returned by asynchronous DomainOpen call
341 * @param ctx initialised libnet context
342 * @param mem_ctx memory context of the call
343 * @param io pointer to results (and arguments) of the call
344 * @return nt status code of execution
347 NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
348 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
351 struct domain_open_samr_state *s;
353 /* wait for results of sending request */
354 status = composite_wait(c);
356 if (NT_STATUS_IS_OK(status) && io) {
357 s = talloc_get_type(c->private_data, struct domain_open_samr_state);
358 io->out.domain_handle = s->domain_handle;
360 /* store the resulting handle and related data for use by other
362 ctx->samr.connect_handle = s->connect_handle;
363 ctx->samr.handle = s->domain_handle;
364 ctx->samr.sid = talloc_steal(ctx, s->lookup.out.sid);
365 ctx->samr.name = talloc_steal(ctx, s->domain_name.string);
366 ctx->samr.access_mask = s->access_mask;
374 struct domain_open_lsa_state {
376 uint32_t access_mask;
377 struct libnet_context *ctx;
378 struct libnet_RpcConnect rpcconn;
379 struct lsa_OpenPolicy2 openpol;
380 struct policy_handle handle;
381 struct dcerpc_pipe *pipe;
383 /* information about the progress */
384 void (*monitor_fn)(struct monitor_msg*);
388 static void continue_rpc_connect_lsa(struct composite_context *ctx);
389 static void continue_lsa_policy_open(struct rpc_request *req);
393 * Sends asynchronous DomainOpenLsa request
395 * @param ctx initialised libnet context
396 * @param io arguments and results of the call
397 * @param monitor pointer to monitor function that is passed monitor message
400 struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
401 struct libnet_DomainOpen *io,
402 void (*monitor)(struct monitor_msg*))
404 struct composite_context *c;
405 struct domain_open_lsa_state *s;
406 struct composite_context *rpcconn_req;
407 struct rpc_request *openpol_req;
408 struct lsa_QosInfo *qos;
410 /* create composite context and state */
411 c = composite_create(ctx, ctx->event_ctx);
412 if (c == NULL) return c;
414 s = talloc_zero(c, struct domain_open_lsa_state);
415 if (composite_nomem(s, c)) return c;
419 /* store arguments in the state structure */
420 s->name = talloc_strdup(c, io->in.domain_name);
421 s->access_mask = io->in.access_mask;
424 /* check, if there's lsa pipe opened already, before opening a handle */
425 if (ctx->lsa.pipe == NULL) {
427 /* attempting to connect a domain controller */
428 s->rpcconn.level = LIBNET_RPC_CONNECT_DC;
429 s->rpcconn.in.name = talloc_strdup(c, io->in.domain_name);
430 s->rpcconn.in.dcerpc_iface = &ndr_table_lsarpc;
432 /* send rpc pipe connect request */
433 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
434 if (composite_nomem(rpcconn_req, c)) return c;
436 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
440 s->pipe = ctx->lsa.pipe;
442 /* preparing parameters for lsa_OpenPolicy2 rpc call */
443 s->openpol.in.system_name = s->name;
444 s->openpol.in.access_mask = s->access_mask;
445 s->openpol.in.attr = talloc_zero(c, struct lsa_ObjectAttribute);
447 qos = talloc_zero(c, struct lsa_QosInfo);
449 qos->impersonation_level = 2;
450 qos->context_mode = 1;
451 qos->effective_only = 0;
453 s->openpol.in.attr->sec_qos = qos;
454 s->openpol.out.handle = &s->handle;
456 /* send rpc request */
457 openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
458 if (composite_nomem(openpol_req, c)) return c;
460 composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
466 Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
468 static void continue_rpc_connect_lsa(struct composite_context *ctx)
470 struct composite_context *c;
471 struct domain_open_lsa_state *s;
472 struct lsa_QosInfo *qos;
473 struct rpc_request *openpol_req;
475 c = talloc_get_type(ctx->async.private_data, struct composite_context);
476 s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
478 /* receive rpc connection */
479 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
480 if (!composite_is_ok(c)) return;
482 /* RpcConnect function leaves the pipe in libnet context,
483 so get it from there */
484 s->pipe = s->ctx->lsa.pipe;
486 /* prepare lsa_OpenPolicy2 call */
487 s->openpol.in.system_name = s->name;
488 s->openpol.in.access_mask = s->access_mask;
489 s->openpol.in.attr = talloc_zero(c, struct lsa_ObjectAttribute);
491 qos = talloc_zero(c, struct lsa_QosInfo);
493 qos->impersonation_level = 2;
494 qos->context_mode = 1;
495 qos->effective_only = 0;
497 s->openpol.in.attr->sec_qos = qos;
498 s->openpol.out.handle = &s->handle;
500 /* send rpc request */
501 openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
502 if (composite_nomem(openpol_req, c)) return;
504 composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
509 Stage 1: Lsa policy opened - we're done, if successfully
511 static void continue_lsa_policy_open(struct rpc_request *req)
513 struct composite_context *c;
514 struct domain_open_lsa_state *s;
516 c = talloc_get_type(req->async.private_data, struct composite_context);
517 s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
519 c->status = dcerpc_ndr_request_recv(req);
520 if (!composite_is_ok(c)) return;
523 struct monitor_msg msg;
525 msg.type = mon_LsaOpenPolicy;
536 * Receives result of asynchronous DomainOpenLsa call
538 * @param c composite context returned by asynchronous DomainOpenLsa call
539 * @param ctx initialised libnet context
540 * @param mem_ctx memory context of the call
541 * @param io pointer to results (and arguments) of the call
542 * @return nt status code of execution
545 NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
546 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
549 struct domain_open_lsa_state *s;
551 status = composite_wait(c);
553 if (NT_STATUS_IS_OK(status) && io) {
554 /* everything went fine - get the results and
555 return the error string */
556 s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
557 io->out.domain_handle = s->handle;
559 ctx->lsa.handle = s->handle;
560 ctx->lsa.name = talloc_steal(ctx, s->name);
561 ctx->lsa.access_mask = s->access_mask;
563 io->out.error_string = talloc_strdup(mem_ctx, "Success");
565 } else if (!NT_STATUS_IS_OK(status)) {
566 /* there was an error, so provide nt status code description */
567 io->out.error_string = talloc_asprintf(mem_ctx,
568 "Failed to open domain: %s",
578 * Sends a request to open a domain in desired service
580 * @param ctx initalised libnet context
581 * @param io arguments and results of the call
582 * @param monitor pointer to monitor function that is passed monitor message
585 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
586 struct libnet_DomainOpen *io,
587 void (*monitor)(struct monitor_msg*))
589 struct composite_context *c;
591 switch (io->in.type) {
593 /* reques to open a policy handle on \pipe\lsarpc */
594 c = libnet_DomainOpenLsa_send(ctx, io, monitor);
599 /* request to open a domain policy handle on \pipe\samr */
600 c = libnet_DomainOpenSamr_send(ctx, io, monitor);
609 * Receive result of domain open request
611 * @param c composite context returned by DomainOpen_send function
612 * @param ctx initialised libnet context
613 * @param mem_ctx memory context of the call
614 * @param io results and arguments of the call
617 NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
618 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
622 switch (io->in.type) {
624 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
629 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
638 * Synchronous version of DomainOpen call
640 * @param ctx initialised libnet context
641 * @param mem_ctx memory context for the call
642 * @param io arguments and results of the call
643 * @return nt status code of execution
646 NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
648 struct libnet_DomainOpen *io)
650 struct composite_context *c = libnet_DomainOpen_send(ctx, io, NULL);
651 return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
655 struct domain_close_lsa_state {
656 struct dcerpc_pipe *pipe;
657 struct lsa_Close close;
658 struct policy_handle handle;
660 void (*monitor_fn)(struct monitor_msg*);
664 static void continue_lsa_close(struct rpc_request *req);
667 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
668 struct libnet_DomainClose *io,
669 void (*monitor)(struct monitor_msg*))
671 struct composite_context *c;
672 struct domain_close_lsa_state *s;
673 struct rpc_request *close_req;
675 /* composite context and state structure allocation */
676 c = composite_create(ctx, ctx->event_ctx);
677 if (c == NULL) return c;
679 s = talloc_zero(c, struct domain_close_lsa_state);
680 if (composite_nomem(s, c)) return c;
683 s->monitor_fn = monitor;
685 /* TODO: check if lsa pipe pointer is non-null */
687 if (!strequal(ctx->lsa.name, io->in.domain_name)) {
688 composite_error(c, NT_STATUS_INVALID_PARAMETER);
692 /* get opened lsarpc pipe pointer */
693 s->pipe = ctx->lsa.pipe;
695 /* prepare close handle call arguments */
696 s->close.in.handle = &ctx->lsa.handle;
697 s->close.out.handle = &s->handle;
699 /* send the request */
700 close_req = dcerpc_lsa_Close_send(s->pipe, c, &s->close);
701 if (composite_nomem(close_req, c)) return c;
703 composite_continue_rpc(c, close_req, continue_lsa_close, c);
709 Stage 1: Receive result of lsa close call
711 static void continue_lsa_close(struct rpc_request *req)
713 struct composite_context *c;
714 struct domain_close_lsa_state *s;
716 c = talloc_get_type(req->async.private_data, struct composite_context);
717 s = talloc_get_type(c->private_data, struct domain_close_lsa_state);
719 c->status = dcerpc_ndr_request_recv(req);
720 if (!composite_is_ok(c)) return;
723 struct monitor_msg msg;
725 msg.type = mon_LsaClose;
735 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
736 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
740 status = composite_wait(c);
742 if (NT_STATUS_IS_OK(status) && io) {
743 /* policy handle closed successfully */
745 ctx->lsa.name = NULL;
746 ZERO_STRUCT(ctx->lsa.handle);
748 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
750 } else if (!NT_STATUS_IS_OK(status)) {
751 /* there was an error, so return description of the status code */
752 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
760 struct domain_close_samr_state {
761 struct samr_Close close;
762 struct policy_handle handle;
764 void (*monitor_fn)(struct monitor_msg*);
768 static void continue_samr_close(struct rpc_request *req);
771 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
772 struct libnet_DomainClose *io,
773 void (*monitor)(struct monitor_msg*))
775 struct composite_context *c;
776 struct domain_close_samr_state *s;
777 struct rpc_request *close_req;
779 /* composite context and state structure allocation */
780 c = composite_create(ctx, ctx->event_ctx);
781 if (c == NULL) return c;
783 s = talloc_zero(c, struct domain_close_samr_state);
784 if (composite_nomem(s, c)) return c;
787 s->monitor_fn = monitor;
789 /* TODO: check if samr pipe pointer is non-null */
791 if (!strequal(ctx->samr.name, io->in.domain_name)) {
792 composite_error(c, NT_STATUS_INVALID_PARAMETER);
796 /* prepare close domain handle call arguments */
797 ZERO_STRUCT(s->close);
798 s->close.in.handle = &ctx->samr.handle;
799 s->close.out.handle = &s->handle;
801 /* send the request */
802 close_req = dcerpc_samr_Close_send(ctx->samr.pipe, ctx, &s->close);
803 if (composite_nomem(close_req, c)) return c;
805 composite_continue_rpc(c, close_req, continue_samr_close, c);
811 Stage 1: Receive result of samr close call
813 static void continue_samr_close(struct rpc_request *req)
815 struct composite_context *c;
816 struct domain_close_samr_state *s;
818 c = talloc_get_type(req->async.private_data, struct composite_context);
819 s = talloc_get_type(c->private_data, struct domain_close_samr_state);
821 c->status = dcerpc_ndr_request_recv(req);
822 if (!composite_is_ok(c)) return;
825 struct monitor_msg msg;
827 msg.type = mon_SamrClose;
837 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
838 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
842 status = composite_wait(c);
844 if (NT_STATUS_IS_OK(status) && io) {
845 /* domain policy handle closed successfully */
847 ZERO_STRUCT(ctx->samr.handle);
848 talloc_free(ctx->samr.name);
849 talloc_free(ctx->samr.sid);
850 ctx->samr.name = NULL;
851 ctx->samr.sid = NULL;
853 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
855 } else if (!NT_STATUS_IS_OK(status)) {
856 /* there was an error, so return description of the status code */
857 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
865 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
866 struct libnet_DomainClose *io,
867 void (*monitor)(struct monitor_msg*))
869 struct composite_context *c;
871 switch (io->in.type) {
873 /* request to close policy handle on \pipe\lsarpc */
874 c = libnet_DomainCloseLsa_send(ctx, io, monitor);
879 /* request to close domain policy handle on \pipe\samr */
880 c = libnet_DomainCloseSamr_send(ctx, io, monitor);
888 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
889 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
893 switch (io->in.type) {
895 /* receive result of closing lsa policy handle */
896 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
901 /* receive result of closing samr domain policy handle */
902 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
910 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
911 struct libnet_DomainClose *io)
913 struct composite_context *c;
915 c = libnet_DomainClose_send(ctx, io, NULL);
916 return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
920 struct domain_list_state {
921 struct libnet_context *ctx;
922 struct libnet_RpcConnect rpcconn;
923 struct samr_Connect samrconn;
924 struct samr_EnumDomains enumdom;
925 struct samr_Close samrclose;
926 const char *hostname;
927 struct policy_handle connect_handle;
929 struct domainlist *domains;
930 uint32_t resume_handle;
933 void (*monitor_fn)(struct monitor_msg*);
937 static void continue_rpc_connect(struct composite_context *c);
938 static void continue_samr_connect(struct rpc_request *c);
939 static void continue_samr_enum_domains(struct rpc_request *req);
940 static void continue_samr_close_handle(struct rpc_request *req);
942 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
946 Stage 1: Receive connected rpc pipe and send connection
947 request to SAMR service
949 static void continue_rpc_connect(struct composite_context *ctx)
951 struct composite_context *c;
952 struct domain_list_state *s;
953 struct rpc_request *samrconn_req;
955 c = talloc_get_type(ctx->async.private_data, struct composite_context);
956 s = talloc_get_type(c->private_data, struct domain_list_state);
958 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
959 if (!composite_is_ok(c)) return;
961 s->samrconn.in.system_name = 0;
962 s->samrconn.in.access_mask = SEC_GENERIC_READ; /* should be enough */
963 s->samrconn.out.connect_handle = &s->connect_handle;
965 samrconn_req = dcerpc_samr_Connect_send(s->ctx->samr.pipe, c, &s->samrconn);
966 if (composite_nomem(samrconn_req, c)) return;
968 composite_continue_rpc(c, samrconn_req, continue_samr_connect, c);
973 Stage 2: Receive policy handle to the connected SAMR service and issue
974 a request to enumerate domain databases available
976 static void continue_samr_connect(struct rpc_request *req)
978 struct composite_context *c;
979 struct domain_list_state *s;
980 struct rpc_request *enumdom_req;
982 c = talloc_get_type(req->async.private_data, struct composite_context);
983 s = talloc_get_type(c->private_data, struct domain_list_state);
985 c->status = dcerpc_ndr_request_recv(req);
986 if (!composite_is_ok(c)) return;
989 struct monitor_msg msg;
991 msg.type = mon_SamrConnect;
997 s->enumdom.in.connect_handle = &s->connect_handle;
998 s->enumdom.in.resume_handle = &s->resume_handle;
999 s->enumdom.in.buf_size = s->buf_size;
1000 s->enumdom.out.resume_handle = &s->resume_handle;
1002 enumdom_req = dcerpc_samr_EnumDomains_send(s->ctx->samr.pipe, c, &s->enumdom);
1003 if (composite_nomem(enumdom_req, c)) return;
1005 composite_continue_rpc(c, enumdom_req, continue_samr_enum_domains, c);
1010 Stage 3: Receive domain names available and repeat the request
1011 enumeration is not complete yet. Close samr connection handle
1014 static void continue_samr_enum_domains(struct rpc_request *req)
1016 struct composite_context *c;
1017 struct domain_list_state *s;
1018 struct rpc_request *enumdom_req;
1019 struct rpc_request *samrclose_req;
1021 c = talloc_get_type(req->async.private_data, struct composite_context);
1022 s = talloc_get_type(c->private_data, struct domain_list_state);
1024 c->status = dcerpc_ndr_request_recv(req);
1025 if (!composite_is_ok(c)) return;
1027 if (s->monitor_fn) {
1028 struct monitor_msg msg;
1030 msg.type = mon_SamrEnumDomains;
1033 s->monitor_fn(&msg);
1036 if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
1038 s->domains = get_domain_list(c, s);
1040 } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
1042 s->domains = get_domain_list(c, s);
1044 /* prepare next round of enumeration */
1045 s->enumdom.in.connect_handle = &s->connect_handle;
1046 s->enumdom.in.resume_handle = &s->resume_handle;
1047 s->enumdom.in.buf_size = s->ctx->samr.buf_size;
1048 s->enumdom.out.resume_handle = &s->resume_handle;
1050 /* send the request */
1051 enumdom_req = dcerpc_samr_EnumDomains_send(s->ctx->samr.pipe, c, &s->enumdom);
1052 if (composite_nomem(enumdom_req, c)) return;
1054 composite_continue_rpc(c, enumdom_req, continue_samr_enum_domains, c);
1057 composite_error(c, s->enumdom.out.result);
1061 /* close samr connection handle */
1062 s->samrclose.in.handle = &s->connect_handle;
1063 s->samrclose.out.handle = &s->connect_handle;
1065 /* send the request */
1066 samrclose_req = dcerpc_samr_Close_send(s->ctx->samr.pipe, c, &s->samrclose);
1067 if (composite_nomem(samrclose_req, c)) return;
1069 composite_continue_rpc(c, samrclose_req, continue_samr_close_handle, c);
1074 Stage 4: Receive result of closing samr connection handle.
1076 static void continue_samr_close_handle(struct rpc_request *req)
1078 struct composite_context *c;
1079 struct domain_list_state *s;
1081 c = talloc_get_type(req->async.private_data, struct composite_context);
1082 s = talloc_get_type(c->private_data, struct domain_list_state);
1084 c->status = dcerpc_ndr_request_recv(req);
1085 if (!composite_is_ok(c)) return;
1087 if (s->monitor_fn) {
1088 struct monitor_msg msg;
1090 msg.type = mon_SamrClose;
1093 s->monitor_fn(&msg);
1096 /* did everything go fine ? */
1097 if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
1098 composite_error(c, s->samrclose.out.result);
1106 Utility function to copy domain names from result of samr_EnumDomains call
1108 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
1111 if (mem_ctx == NULL || s == NULL) return NULL;
1113 /* prepare domains array */
1114 if (s->domains == NULL) {
1115 s->domains = talloc_array(mem_ctx, struct domainlist,
1116 s->enumdom.out.num_entries);
1118 s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
1119 s->count + s->enumdom.out.num_entries);
1122 /* copy domain names returned from samr_EnumDomains call */
1123 for (i = s->count; i < s->count + s->enumdom.out.num_entries; i++)
1125 struct lsa_String *domain_name = &s->enumdom.out.sam->entries[i - s->count].name;
1127 /* strdup name as a child of allocated array to make it follow the array
1128 in case of talloc_steal or talloc_free */
1129 s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
1130 s->domains[i].sid = NULL; /* this is to be filled out later */
1133 /* number of entries returned (domains enumerated) */
1134 s->count += s->enumdom.out.num_entries;
1141 * Sends a request to list domains on given host
1143 * @param ctx initalised libnet context
1144 * @param mem_ctx memory context
1145 * @param io arguments and results of the call
1146 * @param monitor pointer to monitor function that is passed monitor messages
1149 struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
1150 TALLOC_CTX *mem_ctx,
1151 struct libnet_DomainList *io,
1152 void (*monitor)(struct monitor_msg*))
1154 struct composite_context *c;
1155 struct domain_list_state *s;
1156 struct composite_context *rpcconn_req;
1157 struct rpc_request *samrconn_req;
1159 /* composite context and state structure allocation */
1160 c = composite_create(ctx, ctx->event_ctx);
1161 if (c == NULL) return c;
1163 s = talloc_zero(c, struct domain_list_state);
1164 if (composite_nomem(s, c)) return c;
1166 c->private_data = s;
1167 s->monitor_fn = monitor;
1170 s->hostname = talloc_strdup(c, io->in.hostname);
1171 if (composite_nomem(s->hostname, c)) return c;
1173 /* check whether samr pipe has already been opened */
1174 if (ctx->samr.pipe == NULL) {
1175 /* prepare rpc connect call */
1176 s->rpcconn.level = LIBNET_RPC_CONNECT_SERVER;
1177 s->rpcconn.in.name = s->hostname;
1178 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
1180 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
1181 if (composite_nomem(rpcconn_req, c)) return c;
1183 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
1186 /* prepare samr_Connect call */
1187 s->samrconn.in.system_name = 0;
1188 s->samrconn.in.access_mask = SEC_GENERIC_READ;
1189 s->samrconn.out.connect_handle = &s->connect_handle;
1191 samrconn_req = dcerpc_samr_Connect_send(s->ctx->samr.pipe, c, &s->samrconn);
1192 if (composite_nomem(samrconn_req, c)) return c;
1194 composite_continue_rpc(c, samrconn_req, continue_samr_connect, c);
1202 * Receive result of domain list request
1204 * @param c composite context returned by DomainList_send function
1205 * @param ctx initialised libnet context
1206 * @param mem_ctx memory context of the call
1207 * @param io results and arguments of the call
1210 NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
1211 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
1214 struct domain_list_state *s;
1216 status = composite_wait(c);
1218 s = talloc_get_type(c->private_data, struct domain_list_state);
1220 if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
1221 /* fetch the results to be returned by io structure */
1222 io->out.count = s->count;
1223 io->out.domains = talloc_steal(mem_ctx, s->domains);
1224 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
1226 } else if (!NT_STATUS_IS_OK(status)) {
1227 /* there was an error, so return description of the status code */
1228 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1237 * Synchronous version of DomainList call
1239 * @param ctx initialised libnet context
1240 * @param mem_ctx memory context for the call
1241 * @param io arguments and results of the call
1242 * @return nt status code of execution
1245 NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1246 struct libnet_DomainList *io)
1248 struct composite_context *c;
1250 c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
1251 return libnet_DomainList_recv(c, ctx, mem_ctx, io);