s3-docs: Fix several typos.
[Samba/gbeck.git] / source4 / libnet / libnet_rpc.c
blob8aacfc398a1d9c7be7f89d3f5ec59931b9bb5a67
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2004
5 Copyright (C) Rafal Szczesniak 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "libnet/libnet.h"
23 #include "libcli/libcli.h"
24 #include "libcli/composite/composite.h"
25 #include "librpc/rpc/dcerpc_proto.h"
26 #include "librpc/gen_ndr/ndr_lsa_c.h"
27 #include "librpc/gen_ndr/ndr_samr.h"
30 struct rpc_connect_srv_state {
31 struct libnet_context *ctx;
32 struct libnet_RpcConnect r;
33 const char *binding;
35 /* information about the progress */
36 void (*monitor_fn)(struct monitor_msg*);
40 static void continue_pipe_connect(struct composite_context *ctx);
43 /**
44 * Initiates connection to rpc pipe on remote server
46 * @param ctx initialised libnet context
47 * @param mem_ctx memory context of this call
48 * @param r data structure containing necessary parameters and return values
49 * @return composite context of this call
50 **/
52 static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
53 TALLOC_CTX *mem_ctx,
54 struct libnet_RpcConnect *r,
55 void (*monitor)(struct monitor_msg*))
57 struct composite_context *c;
58 struct rpc_connect_srv_state *s;
59 struct dcerpc_binding *b;
60 struct composite_context *pipe_connect_req;
62 /* composite context allocation and setup */
63 c = composite_create(ctx, ctx->event_ctx);
64 if (c == NULL) return c;
66 s = talloc_zero(c, struct rpc_connect_srv_state);
67 if (composite_nomem(s, c)) return c;
69 c->private_data = s;
70 s->monitor_fn = monitor;
72 s->ctx = ctx;
73 s->r = *r;
74 ZERO_STRUCT(s->r.out);
76 /* prepare binding string */
77 switch (r->level) {
78 case LIBNET_RPC_CONNECT_SERVER:
79 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
80 break;
81 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
82 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
83 break;
85 case LIBNET_RPC_CONNECT_BINDING:
86 s->binding = talloc_strdup(s, r->in.binding);
87 break;
89 case LIBNET_RPC_CONNECT_DC:
90 case LIBNET_RPC_CONNECT_PDC:
91 /* this should never happen - DC and PDC level has a separate
92 composite function */
93 case LIBNET_RPC_CONNECT_DC_INFO:
94 /* this should never happen - DC_INFO level has a separate
95 composite function */
96 composite_error(c, NT_STATUS_INVALID_LEVEL);
97 return c;
100 /* parse binding string to the structure */
101 c->status = dcerpc_parse_binding(c, s->binding, &b);
102 if (!NT_STATUS_IS_OK(c->status)) {
103 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
104 composite_error(c, c->status);
105 return c;
108 switch (r->level) {
109 case LIBNET_RPC_CONNECT_SERVER:
110 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
111 b->flags = r->in.dcerpc_flags;
112 break;
113 default:
114 /* other types have already been checked before */
115 break;
118 if (DEBUGLEVEL >= 10) {
119 b->flags |= DCERPC_DEBUG_PRINT_BOTH;
122 if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
123 b->target_hostname = talloc_strdup(b, r->in.name);
124 if (composite_nomem(b->target_hostname, c)) {
125 return c;
129 /* connect to remote dcerpc pipe */
130 pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
131 ctx->cred, c->event_ctx,
132 ctx->lp_ctx);
133 if (composite_nomem(pipe_connect_req, c)) return c;
135 composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
136 return c;
141 Step 2 of RpcConnectSrv - get rpc connection
143 static void continue_pipe_connect(struct composite_context *ctx)
145 struct composite_context *c;
146 struct rpc_connect_srv_state *s;
148 c = talloc_get_type(ctx->async.private_data, struct composite_context);
149 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
151 /* receive result of rpc pipe connection */
152 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
154 /* post monitor message */
155 if (s->monitor_fn) {
156 struct monitor_msg msg;
157 struct msg_net_rpc_connect data;
158 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
160 /* prepare monitor message and post it */
161 data.host = binding->host;
162 data.endpoint = binding->endpoint;
163 data.transport = binding->transport;
164 data.domain_name = binding->target_hostname;
166 msg.type = mon_NetRpcConnect;
167 msg.data = (void*)&data;
168 msg.data_size = sizeof(data);
169 s->monitor_fn(&msg);
172 composite_done(c);
177 * Receives result of connection to rpc pipe on remote server
179 * @param c composite context
180 * @param ctx initialised libnet context
181 * @param mem_ctx memory context of this call
182 * @param r data structure containing necessary parameters and return values
183 * @return nt status of rpc connection
186 static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
187 struct libnet_context *ctx,
188 TALLOC_CTX *mem_ctx,
189 struct libnet_RpcConnect *r)
191 NTSTATUS status;
192 struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
193 struct rpc_connect_srv_state);
195 status = composite_wait(c);
196 if (NT_STATUS_IS_OK(status)) {
197 /* move the returned rpc pipe between memory contexts */
198 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
199 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
201 /* reference created pipe structure to long-term libnet_context
202 so that it can be used by other api functions even after short-term
203 mem_ctx is freed */
204 if (r->in.dcerpc_iface == &ndr_table_samr) {
205 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
207 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
208 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
211 r->out.error_string = talloc_strdup(mem_ctx, "Success");
213 } else {
214 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
217 talloc_free(c);
218 return status;
222 struct rpc_connect_dc_state {
223 struct libnet_context *ctx;
224 struct libnet_RpcConnect r;
225 struct libnet_RpcConnect r2;
226 struct libnet_LookupDCs f;
227 const char *connect_name;
229 /* information about the progress */
230 void (*monitor_fn)(struct monitor_msg *);
234 static void continue_lookup_dc(struct tevent_req *req);
235 static void continue_rpc_connect(struct composite_context *ctx);
239 * Initiates connection to rpc pipe on domain pdc
241 * @param ctx initialised libnet context
242 * @param mem_ctx memory context of this call
243 * @param r data structure containing necessary parameters and return values
244 * @return composite context of this call
247 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
248 TALLOC_CTX *mem_ctx,
249 struct libnet_RpcConnect *r,
250 void (*monitor)(struct monitor_msg *msg))
252 struct composite_context *c;
253 struct rpc_connect_dc_state *s;
254 struct tevent_req *lookup_dc_req;
256 /* composite context allocation and setup */
257 c = composite_create(ctx, ctx->event_ctx);
258 if (c == NULL) return c;
260 s = talloc_zero(c, struct rpc_connect_dc_state);
261 if (composite_nomem(s, c)) return c;
263 c->private_data = s;
264 s->monitor_fn = monitor;
266 s->ctx = ctx;
267 s->r = *r;
268 ZERO_STRUCT(s->r.out);
270 switch (r->level) {
271 case LIBNET_RPC_CONNECT_PDC:
272 s->f.in.name_type = NBT_NAME_PDC;
273 break;
275 case LIBNET_RPC_CONNECT_DC:
276 s->f.in.name_type = NBT_NAME_LOGON;
277 break;
279 default:
280 break;
283 s->f.in.domain_name = r->in.name;
284 s->f.out.num_dcs = 0;
285 s->f.out.dcs = NULL;
287 /* find the domain pdc first */
288 lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
289 if (composite_nomem(lookup_dc_req, c)) return c;
291 tevent_req_set_callback(lookup_dc_req, continue_lookup_dc, c);
292 return c;
297 Step 2 of RpcConnectDC: get domain controller name and
298 initiate RpcConnect to it
300 static void continue_lookup_dc(struct tevent_req *req)
302 struct composite_context *c;
303 struct rpc_connect_dc_state *s;
304 struct composite_context *rpc_connect_req;
305 struct monitor_msg msg;
306 struct msg_net_lookup_dc data;
308 c = tevent_req_callback_data(req, struct composite_context);
309 s = talloc_get_type_abort(c->private_data, struct rpc_connect_dc_state);
311 /* receive result of domain controller lookup */
312 c->status = libnet_LookupDCs_recv(req, c, &s->f);
313 if (!composite_is_ok(c)) return;
315 /* decide on preferred address type depending on DC type */
316 s->connect_name = s->f.out.dcs[0].name;
318 /* post monitor message */
319 if (s->monitor_fn) {
320 /* prepare a monitor message and post it */
321 data.domain_name = s->f.in.domain_name;
322 data.hostname = s->f.out.dcs[0].name;
323 data.address = s->f.out.dcs[0].address;
325 msg.type = mon_NetLookupDc;
326 msg.data = &data;
327 msg.data_size = sizeof(data);
328 s->monitor_fn(&msg);
331 /* ok, pdc has been found so do attempt to rpc connect */
332 s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
334 /* this will cause yet another name resolution, but at least
335 * we pass the right name down the stack now */
336 s->r2.in.name = talloc_strdup(s, s->connect_name);
337 s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address);
338 s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface;
339 s->r2.in.dcerpc_flags = s->r.in.dcerpc_flags;
341 /* send rpc connect request to the server */
342 rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);
343 if (composite_nomem(rpc_connect_req, c)) return;
345 composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
350 Step 3 of RpcConnectDC: get rpc connection to the server
352 static void continue_rpc_connect(struct composite_context *ctx)
354 struct composite_context *c;
355 struct rpc_connect_dc_state *s;
357 c = talloc_get_type(ctx->async.private_data, struct composite_context);
358 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
360 c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
362 /* error string is to be passed anyway */
363 s->r.out.error_string = s->r2.out.error_string;
364 if (!composite_is_ok(c)) return;
366 s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
368 /* post monitor message */
369 if (s->monitor_fn) {
370 struct monitor_msg msg;
371 struct msg_net_rpc_connect data;
372 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
374 data.host = binding->host;
375 data.endpoint = binding->endpoint;
376 data.transport = binding->transport;
377 data.domain_name = binding->target_hostname;
379 msg.type = mon_NetRpcConnect;
380 msg.data = (void*)&data;
381 msg.data_size = sizeof(data);
382 s->monitor_fn(&msg);
385 composite_done(c);
390 * Receives result of connection to rpc pipe on domain pdc
392 * @param c composite context
393 * @param ctx initialised libnet context
394 * @param mem_ctx memory context of this call
395 * @param r data structure containing necessary parameters and return values
396 * @return nt status of rpc connection
399 static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
400 struct libnet_context *ctx,
401 TALLOC_CTX *mem_ctx,
402 struct libnet_RpcConnect *r)
404 NTSTATUS status;
405 struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
406 struct rpc_connect_dc_state);
408 status = composite_wait(c);
409 if (NT_STATUS_IS_OK(status)) {
410 /* move connected rpc pipe between memory contexts
412 The use of talloc_reparent(talloc_parent(), ...) is
413 bizarre, but it is needed because of the absolutely
414 atrocious use of talloc in this code. We need to
415 force the original parent to change, but finding
416 the original parent is well nigh impossible at this
417 point in the code (yes, I tried).
419 r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe),
420 mem_ctx, s->r.out.dcerpc_pipe);
422 /* reference created pipe structure to long-term libnet_context
423 so that it can be used by other api functions even after short-term
424 mem_ctx is freed */
425 if (r->in.dcerpc_iface == &ndr_table_samr) {
426 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
428 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
429 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
432 } else {
433 r->out.error_string = talloc_asprintf(mem_ctx,
434 "Failed to rpc connect: %s",
435 nt_errstr(status));
438 talloc_free(c);
439 return status;
444 struct rpc_connect_dci_state {
445 struct libnet_context *ctx;
446 struct libnet_RpcConnect r;
447 struct libnet_RpcConnect rpc_conn;
448 struct policy_handle lsa_handle;
449 struct lsa_QosInfo qos;
450 struct lsa_ObjectAttribute attr;
451 struct lsa_OpenPolicy2 lsa_open_policy;
452 struct dcerpc_pipe *lsa_pipe;
453 struct lsa_QueryInfoPolicy2 lsa_query_info2;
454 struct lsa_QueryInfoPolicy lsa_query_info;
455 struct dcerpc_binding *final_binding;
456 struct dcerpc_pipe *final_pipe;
458 /* information about the progress */
459 void (*monitor_fn)(struct monitor_msg*);
463 static void continue_dci_rpc_connect(struct composite_context *ctx);
464 static void continue_lsa_policy(struct tevent_req *subreq);
465 static void continue_lsa_query_info(struct tevent_req *subreq);
466 static void continue_lsa_query_info2(struct tevent_req *subreq);
467 static void continue_epm_map_binding(struct composite_context *ctx);
468 static void continue_secondary_conn(struct composite_context *ctx);
469 static void continue_epm_map_binding_send(struct composite_context *c);
473 * Initiates connection to rpc pipe on remote server or pdc. Received result
474 * contains info on the domain name, domain sid and realm.
476 * @param ctx initialised libnet context
477 * @param mem_ctx memory context of this call
478 * @param r data structure containing necessary parameters and return values. Must be a talloc context
479 * @return composite context of this call
482 static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
483 TALLOC_CTX *mem_ctx,
484 struct libnet_RpcConnect *r,
485 void (*monitor)(struct monitor_msg*))
487 struct composite_context *c, *conn_req;
488 struct rpc_connect_dci_state *s;
490 /* composite context allocation and setup */
491 c = composite_create(ctx, ctx->event_ctx);
492 if (c == NULL) return c;
494 s = talloc_zero(c, struct rpc_connect_dci_state);
495 if (composite_nomem(s, c)) return c;
497 c->private_data = s;
498 s->monitor_fn = monitor;
500 s->ctx = ctx;
501 s->r = *r;
502 ZERO_STRUCT(s->r.out);
505 /* proceed to pure rpc connection if the binding string is provided,
506 otherwise try to connect domain controller */
507 if (r->in.binding == NULL) {
508 /* Pass on any binding flags (such as anonymous fallback) that have been set */
509 s->rpc_conn.in.dcerpc_flags = r->in.dcerpc_flags;
511 s->rpc_conn.in.name = r->in.name;
512 s->rpc_conn.level = LIBNET_RPC_CONNECT_DC;
513 } else {
514 s->rpc_conn.in.binding = r->in.binding;
515 s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING;
518 /* we need to query information on lsarpc interface first */
519 s->rpc_conn.in.dcerpc_iface = &ndr_table_lsarpc;
521 /* request connection to the lsa pipe on the pdc */
522 conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
523 if (composite_nomem(c, conn_req)) return c;
525 composite_continue(c, conn_req, continue_dci_rpc_connect, c);
526 return c;
531 Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
532 lsa policy handle
534 static void continue_dci_rpc_connect(struct composite_context *ctx)
536 struct composite_context *c;
537 struct rpc_connect_dci_state *s;
538 struct tevent_req *subreq;
540 c = talloc_get_type(ctx->async.private_data, struct composite_context);
541 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
543 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
544 if (!NT_STATUS_IS_OK(c->status)) {
545 composite_error(c, c->status);
546 return;
549 /* post monitor message */
550 if (s->monitor_fn) {
551 struct monitor_msg msg;
552 struct msg_net_rpc_connect data;
553 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
555 data.host = binding->host;
556 data.endpoint = binding->endpoint;
557 data.transport = binding->transport;
558 data.domain_name = binding->target_hostname;
560 msg.type = mon_NetRpcConnect;
561 msg.data = (void*)&data;
562 msg.data_size = sizeof(data);
563 s->monitor_fn(&msg);
566 /* prepare to open a policy handle on lsa pipe */
567 s->lsa_pipe = s->ctx->lsa.pipe;
569 s->qos.len = 0;
570 s->qos.impersonation_level = 2;
571 s->qos.context_mode = 1;
572 s->qos.effective_only = 0;
574 s->attr.sec_qos = &s->qos;
576 s->lsa_open_policy.in.attr = &s->attr;
577 s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
578 if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
580 s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
581 s->lsa_open_policy.out.handle = &s->lsa_handle;
583 subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
584 s->lsa_pipe->binding_handle,
585 &s->lsa_open_policy);
586 if (composite_nomem(subreq, c)) return;
588 tevent_req_set_callback(subreq, continue_lsa_policy, c);
593 Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
594 for kerberos realm (dns name) and guid. The query may fail.
596 static void continue_lsa_policy(struct tevent_req *subreq)
598 struct composite_context *c;
599 struct rpc_connect_dci_state *s;
601 c = tevent_req_callback_data(subreq, struct composite_context);
602 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
604 c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
605 TALLOC_FREE(subreq);
606 if (!NT_STATUS_IS_OK(c->status)) {
607 composite_error(c, c->status);
608 return;
611 if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
612 s->r.out.realm = NULL;
613 s->r.out.guid = NULL;
614 s->r.out.domain_name = NULL;
615 s->r.out.domain_sid = NULL;
617 /* Skip to the creating the actual connection, no info available on this transport */
618 continue_epm_map_binding_send(c);
619 return;
621 } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
622 composite_error(c, s->lsa_open_policy.out.result);
623 return;
626 /* post monitor message */
627 if (s->monitor_fn) {
628 struct monitor_msg msg;
630 msg.type = mon_LsaOpenPolicy;
631 msg.data = NULL;
632 msg.data_size = 0;
633 s->monitor_fn(&msg);
636 /* query lsa info for dns domain name and guid */
637 s->lsa_query_info2.in.handle = &s->lsa_handle;
638 s->lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
639 s->lsa_query_info2.out.info = talloc_zero(c, union lsa_PolicyInformation *);
640 if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
642 subreq = dcerpc_lsa_QueryInfoPolicy2_r_send(s, c->event_ctx,
643 s->lsa_pipe->binding_handle,
644 &s->lsa_query_info2);
645 if (composite_nomem(subreq, c)) return;
647 tevent_req_set_callback(subreq, continue_lsa_query_info2, c);
652 Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
653 may result in failure) and query lsa info for domain name and sid.
655 static void continue_lsa_query_info2(struct tevent_req *subreq)
657 struct composite_context *c;
658 struct rpc_connect_dci_state *s;
660 c = tevent_req_callback_data(subreq, struct composite_context);
661 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
663 c->status = dcerpc_lsa_QueryInfoPolicy2_r_recv(subreq, s);
664 TALLOC_FREE(subreq);
666 /* In case of error just null the realm and guid and proceed
667 to the next step. After all, it doesn't have to be AD domain
668 controller we talking to - NT-style PDC also counts */
670 if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
671 s->r.out.realm = NULL;
672 s->r.out.guid = NULL;
674 } else {
675 if (!NT_STATUS_IS_OK(c->status)) {
676 s->r.out.error_string = talloc_asprintf(c,
677 "lsa_QueryInfoPolicy2 failed: %s",
678 nt_errstr(c->status));
679 composite_error(c, c->status);
680 return;
683 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
684 s->r.out.error_string = talloc_asprintf(c,
685 "lsa_QueryInfoPolicy2 failed: %s",
686 nt_errstr(s->lsa_query_info2.out.result));
687 composite_error(c, s->lsa_query_info2.out.result);
688 return;
691 /* Copy the dns domain name and guid from the query result */
693 /* this should actually be a conversion from lsa_StringLarge */
694 s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
695 s->r.out.guid = talloc(c, struct GUID);
696 if (composite_nomem(s->r.out.guid, c)) {
697 s->r.out.error_string = NULL;
698 return;
700 *s->r.out.guid = (*s->lsa_query_info2.out.info)->dns.domain_guid;
703 /* post monitor message */
704 if (s->monitor_fn) {
705 struct monitor_msg msg;
707 msg.type = mon_LsaQueryPolicy;
708 msg.data = NULL;
709 msg.data_size = 0;
710 s->monitor_fn(&msg);
713 /* query lsa info for domain name and sid */
714 s->lsa_query_info.in.handle = &s->lsa_handle;
715 s->lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
716 s->lsa_query_info.out.info = talloc_zero(c, union lsa_PolicyInformation *);
717 if (composite_nomem(s->lsa_query_info.out.info, c)) return;
719 subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
720 s->lsa_pipe->binding_handle,
721 &s->lsa_query_info);
722 if (composite_nomem(subreq, c)) return;
724 tevent_req_set_callback(subreq, continue_lsa_query_info, c);
729 Step 5 of RpcConnectDCInfo: Get domain name and sid
731 static void continue_lsa_query_info(struct tevent_req *subreq)
733 struct composite_context *c;
734 struct rpc_connect_dci_state *s;
736 c = tevent_req_callback_data(subreq, struct composite_context);
737 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
739 c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
740 TALLOC_FREE(subreq);
741 if (!NT_STATUS_IS_OK(c->status)) {
742 s->r.out.error_string = talloc_asprintf(c,
743 "lsa_QueryInfoPolicy failed: %s",
744 nt_errstr(c->status));
745 composite_error(c, c->status);
746 return;
749 /* post monitor message */
750 if (s->monitor_fn) {
751 struct monitor_msg msg;
753 msg.type = mon_LsaQueryPolicy;
754 msg.data = NULL;
755 msg.data_size = 0;
756 s->monitor_fn(&msg);
759 /* Copy the domain name and sid from the query result */
760 s->r.out.domain_sid = (*s->lsa_query_info.out.info)->domain.sid;
761 s->r.out.domain_name = (*s->lsa_query_info.out.info)->domain.name.string;
763 continue_epm_map_binding_send(c);
767 Step 5 (continued) of RpcConnectDCInfo: request endpoint
768 map binding.
770 We may short-cut to this step if we don't support LSA OpenPolicy on this transport
772 static void continue_epm_map_binding_send(struct composite_context *c)
774 struct rpc_connect_dci_state *s;
775 struct composite_context *epm_map_req;
776 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
778 /* prepare to get endpoint mapping for the requested interface */
779 s->final_binding = talloc_zero(s, struct dcerpc_binding);
780 if (composite_nomem(s->final_binding, c)) return;
782 *s->final_binding = *s->lsa_pipe->binding;
783 /* Ensure we keep hold of the member elements */
784 if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
786 epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
787 s->lsa_pipe->conn->event_ctx, s->ctx->lp_ctx);
788 if (composite_nomem(epm_map_req, c)) return;
790 composite_continue(c, epm_map_req, continue_epm_map_binding, c);
794 Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
795 rpc connection derived from already used pipe but connected to the requested
796 one (as specified in libnet_RpcConnect structure)
798 static void continue_epm_map_binding(struct composite_context *ctx)
800 struct composite_context *c, *sec_conn_req;
801 struct rpc_connect_dci_state *s;
803 c = talloc_get_type(ctx->async.private_data, struct composite_context);
804 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
806 c->status = dcerpc_epm_map_binding_recv(ctx);
807 if (!NT_STATUS_IS_OK(c->status)) {
808 s->r.out.error_string = talloc_asprintf(c,
809 "failed to map pipe with endpoint mapper - %s",
810 nt_errstr(c->status));
811 composite_error(c, c->status);
812 return;
815 /* create secondary connection derived from lsa pipe */
816 sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
817 if (composite_nomem(sec_conn_req, c)) return;
819 composite_continue(c, sec_conn_req, continue_secondary_conn, c);
824 Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
825 and complete this composite call
827 static void continue_secondary_conn(struct composite_context *ctx)
829 struct composite_context *c;
830 struct rpc_connect_dci_state *s;
832 c = talloc_get_type(ctx->async.private_data, struct composite_context);
833 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
835 c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
836 if (!NT_STATUS_IS_OK(c->status)) {
837 s->r.out.error_string = talloc_asprintf(c,
838 "secondary connection failed: %s",
839 nt_errstr(c->status));
841 composite_error(c, c->status);
842 return;
845 s->r.out.dcerpc_pipe = s->final_pipe;
847 /* post monitor message */
848 if (s->monitor_fn) {
849 struct monitor_msg msg;
850 struct msg_net_rpc_connect data;
851 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
853 /* prepare monitor message and post it */
854 data.host = binding->host;
855 data.endpoint = binding->endpoint;
856 data.transport = binding->transport;
857 data.domain_name = binding->target_hostname;
859 msg.type = mon_NetRpcConnect;
860 msg.data = (void*)&data;
861 msg.data_size = sizeof(data);
862 s->monitor_fn(&msg);
865 composite_done(c);
870 * Receives result of connection to rpc pipe and gets basic
871 * domain info (name, sid, realm, guid)
873 * @param c composite context
874 * @param ctx initialised libnet context
875 * @param mem_ctx memory context of this call
876 * @param r data structure containing return values
877 * @return nt status of rpc connection
880 static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
881 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
883 NTSTATUS status;
884 struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
885 struct rpc_connect_dci_state);
887 status = composite_wait(c);
888 if (NT_STATUS_IS_OK(status)) {
889 r->out.realm = talloc_steal(mem_ctx, s->r.out.realm);
890 r->out.guid = talloc_steal(mem_ctx, s->r.out.guid);
891 r->out.domain_name = talloc_steal(mem_ctx, s->r.out.domain_name);
892 r->out.domain_sid = talloc_steal(mem_ctx, s->r.out.domain_sid);
894 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
896 /* reference created pipe structure to long-term libnet_context
897 so that it can be used by other api functions even after short-term
898 mem_ctx is freed */
899 if (r->in.dcerpc_iface == &ndr_table_samr) {
900 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
901 ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
903 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
904 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
905 ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
908 } else {
909 if (s->r.out.error_string) {
910 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
911 } else if (r->in.binding == NULL) {
912 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
913 } else {
914 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s",
915 r->in.binding, nt_errstr(status));
919 talloc_free(c);
920 return status;
925 * Initiates connection to rpc pipe on remote server or pdc, optionally
926 * providing domain info
928 * @param ctx initialised libnet context
929 * @param mem_ctx memory context of this call
930 * @param r data structure containing necessary parameters and return values
931 * @return composite context of this call
934 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
935 TALLOC_CTX *mem_ctx,
936 struct libnet_RpcConnect *r,
937 void (*monitor)(struct monitor_msg*))
939 struct composite_context *c;
941 switch (r->level) {
942 case LIBNET_RPC_CONNECT_SERVER:
943 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
944 case LIBNET_RPC_CONNECT_BINDING:
945 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
946 break;
948 case LIBNET_RPC_CONNECT_PDC:
949 case LIBNET_RPC_CONNECT_DC:
950 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
951 break;
953 case LIBNET_RPC_CONNECT_DC_INFO:
954 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
955 break;
957 default:
958 c = talloc_zero(mem_ctx, struct composite_context);
959 composite_error(c, NT_STATUS_INVALID_LEVEL);
962 return c;
967 * Receives result of connection to rpc pipe on remote server or pdc
969 * @param c composite context
970 * @param ctx initialised libnet context
971 * @param mem_ctx memory context of this call
972 * @param r data structure containing necessary parameters and return values
973 * @return nt status of rpc connection
976 NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
977 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
979 switch (r->level) {
980 case LIBNET_RPC_CONNECT_SERVER:
981 case LIBNET_RPC_CONNECT_BINDING:
982 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
984 case LIBNET_RPC_CONNECT_PDC:
985 case LIBNET_RPC_CONNECT_DC:
986 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
988 case LIBNET_RPC_CONNECT_DC_INFO:
989 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
991 default:
992 ZERO_STRUCT(r->out);
993 return NT_STATUS_INVALID_LEVEL;
999 * Connect to a rpc pipe on a remote server - sync version
1001 * @param ctx initialised libnet context
1002 * @param mem_ctx memory context of this call
1003 * @param r data structure containing necessary parameters and return values
1004 * @return nt status of rpc connection
1007 NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1008 struct libnet_RpcConnect *r)
1010 struct composite_context *c;
1012 c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
1013 return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);