Note that the delaytime for update has changed betweek w2k3 and w2k8.
[Samba/gbeck.git] / source4 / libnet / libnet_rpc.c
bloba0d93287a5bfa39eda86868e10ccdc05209c8db6
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.h"
26 #include "librpc/rpc/dcerpc_proto.h"
27 #include "librpc/gen_ndr/ndr_lsa_c.h"
28 #include "librpc/gen_ndr/ndr_samr.h"
31 struct rpc_connect_srv_state {
32 struct libnet_context *ctx;
33 struct libnet_RpcConnect r;
34 const char *binding;
36 /* information about the progress */
37 void (*monitor_fn)(struct monitor_msg*);
41 static void continue_pipe_connect(struct composite_context *ctx);
44 /**
45 * Initiates connection to rpc pipe on remote server
47 * @param ctx initialised libnet context
48 * @param mem_ctx memory context of this call
49 * @param r data structure containing necessary parameters and return values
50 * @return composite context of this call
51 **/
53 static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
54 TALLOC_CTX *mem_ctx,
55 struct libnet_RpcConnect *r,
56 void (*monitor)(struct monitor_msg*))
58 struct composite_context *c;
59 struct rpc_connect_srv_state *s;
60 struct dcerpc_binding *b;
61 struct composite_context *pipe_connect_req;
63 /* composite context allocation and setup */
64 c = composite_create(ctx, ctx->event_ctx);
65 if (c == NULL) return c;
67 s = talloc_zero(c, struct rpc_connect_srv_state);
68 if (composite_nomem(s, c)) return c;
70 c->private_data = s;
71 s->monitor_fn = monitor;
73 s->ctx = ctx;
74 s->r = *r;
75 ZERO_STRUCT(s->r.out);
77 /* prepare binding string */
78 switch (r->level) {
79 case LIBNET_RPC_CONNECT_SERVER:
80 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
81 break;
82 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
83 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
84 break;
86 case LIBNET_RPC_CONNECT_BINDING:
87 s->binding = talloc_strdup(s, r->in.binding);
88 break;
90 case LIBNET_RPC_CONNECT_DC:
91 case LIBNET_RPC_CONNECT_PDC:
92 /* this should never happen - DC and PDC level has a separate
93 composite function */
94 case LIBNET_RPC_CONNECT_DC_INFO:
95 /* this should never happen - DC_INFO level has a separate
96 composite function */
97 composite_error(c, NT_STATUS_INVALID_LEVEL);
98 return c;
101 /* parse binding string to the structure */
102 c->status = dcerpc_parse_binding(c, s->binding, &b);
103 if (!NT_STATUS_IS_OK(c->status)) {
104 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
105 composite_error(c, c->status);
106 return c;
109 if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
110 b->target_hostname = talloc_reference(b, r->in.name);
111 if (composite_nomem(b->target_hostname, c)) {
112 return c;
116 /* connect to remote dcerpc pipe */
117 pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
118 ctx->cred, c->event_ctx,
119 ctx->lp_ctx);
120 if (composite_nomem(pipe_connect_req, c)) return c;
122 composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
123 return c;
128 Step 2 of RpcConnectSrv - get rpc connection
130 static void continue_pipe_connect(struct composite_context *ctx)
132 struct composite_context *c;
133 struct rpc_connect_srv_state *s;
135 c = talloc_get_type(ctx->async.private_data, struct composite_context);
136 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
138 /* receive result of rpc pipe connection */
139 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
141 /* post monitor message */
142 if (s->monitor_fn) {
143 struct monitor_msg msg;
144 struct msg_net_rpc_connect data;
145 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
147 /* prepare monitor message and post it */
148 data.host = binding->host;
149 data.endpoint = binding->endpoint;
150 data.transport = binding->transport;
151 data.domain_name = binding->target_hostname;
153 msg.type = mon_NetRpcConnect;
154 msg.data = (void*)&data;
155 msg.data_size = sizeof(data);
156 s->monitor_fn(&msg);
159 composite_done(c);
164 * Receives result of connection to rpc pipe on remote server
166 * @param c composite context
167 * @param ctx initialised libnet context
168 * @param mem_ctx memory context of this call
169 * @param r data structure containing necessary parameters and return values
170 * @return nt status of rpc connection
173 static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
174 struct libnet_context *ctx,
175 TALLOC_CTX *mem_ctx,
176 struct libnet_RpcConnect *r)
178 NTSTATUS status;
179 struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
180 struct rpc_connect_srv_state);
182 status = composite_wait(c);
183 if (NT_STATUS_IS_OK(status)) {
184 /* move the returned rpc pipe between memory contexts */
185 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
186 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
188 /* reference created pipe structure to long-term libnet_context
189 so that it can be used by other api functions even after short-term
190 mem_ctx is freed */
191 if (r->in.dcerpc_iface == &ndr_table_samr) {
192 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
194 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
195 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
198 r->out.error_string = talloc_strdup(mem_ctx, "Success");
200 } else {
201 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
204 talloc_free(c);
205 return status;
209 struct rpc_connect_dc_state {
210 struct libnet_context *ctx;
211 struct libnet_RpcConnect r;
212 struct libnet_RpcConnect r2;
213 struct libnet_LookupDCs f;
214 const char *connect_name;
216 /* information about the progress */
217 void (*monitor_fn)(struct monitor_msg *);
221 static void continue_lookup_dc(struct composite_context *ctx);
222 static void continue_rpc_connect(struct composite_context *ctx);
226 * Initiates connection to rpc pipe on domain pdc
228 * @param ctx initialised libnet context
229 * @param mem_ctx memory context of this call
230 * @param r data structure containing necessary parameters and return values
231 * @return composite context of this call
234 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
235 TALLOC_CTX *mem_ctx,
236 struct libnet_RpcConnect *r,
237 void (*monitor)(struct monitor_msg *msg))
239 struct composite_context *c;
240 struct rpc_connect_dc_state *s;
241 struct composite_context *lookup_dc_req;
243 /* composite context allocation and setup */
244 c = composite_create(ctx, ctx->event_ctx);
245 if (c == NULL) return c;
247 s = talloc_zero(c, struct rpc_connect_dc_state);
248 if (composite_nomem(s, c)) return c;
250 c->private_data = s;
251 s->monitor_fn = monitor;
253 s->ctx = ctx;
254 s->r = *r;
255 ZERO_STRUCT(s->r.out);
257 switch (r->level) {
258 case LIBNET_RPC_CONNECT_PDC:
259 s->f.in.name_type = NBT_NAME_PDC;
260 break;
262 case LIBNET_RPC_CONNECT_DC:
263 s->f.in.name_type = NBT_NAME_LOGON;
264 break;
266 default:
267 break;
270 s->f.in.domain_name = r->in.name;
271 s->f.out.num_dcs = 0;
272 s->f.out.dcs = NULL;
274 /* find the domain pdc first */
275 lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
276 if (composite_nomem(lookup_dc_req, c)) return c;
278 composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
279 return c;
284 Step 2 of RpcConnectDC: get domain controller name and
285 initiate RpcConnect to it
287 static void continue_lookup_dc(struct composite_context *ctx)
289 struct composite_context *c;
290 struct rpc_connect_dc_state *s;
291 struct composite_context *rpc_connect_req;
292 struct monitor_msg msg;
293 struct msg_net_lookup_dc data;
295 c = talloc_get_type(ctx->async.private_data, struct composite_context);
296 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
298 /* receive result of domain controller lookup */
299 c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
300 if (!composite_is_ok(c)) return;
302 /* decide on preferred address type depending on DC type */
303 s->connect_name = s->f.out.dcs[0].name;
305 /* post monitor message */
306 if (s->monitor_fn) {
307 /* prepare a monitor message and post it */
308 data.domain_name = s->f.in.domain_name;
309 data.hostname = s->f.out.dcs[0].name;
310 data.address = s->f.out.dcs[0].address;
312 msg.type = mon_NetLookupDc;
313 msg.data = &data;
314 msg.data_size = sizeof(data);
315 s->monitor_fn(&msg);
318 /* ok, pdc has been found so do attempt to rpc connect */
319 s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
321 /* this will cause yet another name resolution, but at least
322 * we pass the right name down the stack now */
323 s->r2.in.name = talloc_strdup(s, s->connect_name);
324 s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address);
325 s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface;
327 /* send rpc connect request to the server */
328 rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);
329 if (composite_nomem(rpc_connect_req, c)) return;
331 composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
336 Step 3 of RpcConnectDC: get rpc connection to the server
338 static void continue_rpc_connect(struct composite_context *ctx)
340 struct composite_context *c;
341 struct rpc_connect_dc_state *s;
343 c = talloc_get_type(ctx->async.private_data, struct composite_context);
344 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
346 c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
348 /* error string is to be passed anyway */
349 s->r.out.error_string = s->r2.out.error_string;
350 if (!composite_is_ok(c)) return;
352 s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
354 /* post monitor message */
355 if (s->monitor_fn) {
356 struct monitor_msg msg;
357 struct msg_net_rpc_connect data;
358 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
360 data.host = binding->host;
361 data.endpoint = binding->endpoint;
362 data.transport = binding->transport;
363 data.domain_name = binding->target_hostname;
365 msg.type = mon_NetRpcConnect;
366 msg.data = (void*)&data;
367 msg.data_size = sizeof(data);
368 s->monitor_fn(&msg);
371 composite_done(c);
376 * Receives result of connection to rpc pipe on domain pdc
378 * @param c composite context
379 * @param ctx initialised libnet context
380 * @param mem_ctx memory context of this call
381 * @param r data structure containing necessary parameters and return values
382 * @return nt status of rpc connection
385 static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
386 struct libnet_context *ctx,
387 TALLOC_CTX *mem_ctx,
388 struct libnet_RpcConnect *r)
390 NTSTATUS status;
391 struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
392 struct rpc_connect_dc_state);
394 status = composite_wait(c);
395 if (NT_STATUS_IS_OK(status)) {
396 /* move connected rpc pipe between memory contexts */
397 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
399 /* reference created pipe structure to long-term libnet_context
400 so that it can be used by other api functions even after short-term
401 mem_ctx is freed */
402 if (r->in.dcerpc_iface == &ndr_table_samr) {
403 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
405 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
406 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
409 } else {
410 r->out.error_string = talloc_asprintf(mem_ctx,
411 "Failed to rpc connect: %s",
412 nt_errstr(status));
415 talloc_free(c);
416 return status;
421 struct rpc_connect_dci_state {
422 struct libnet_context *ctx;
423 struct libnet_RpcConnect r;
424 struct libnet_RpcConnect rpc_conn;
425 struct policy_handle lsa_handle;
426 struct lsa_QosInfo qos;
427 struct lsa_ObjectAttribute attr;
428 struct lsa_OpenPolicy2 lsa_open_policy;
429 struct dcerpc_pipe *lsa_pipe;
430 struct lsa_QueryInfoPolicy2 lsa_query_info2;
431 struct lsa_QueryInfoPolicy lsa_query_info;
432 struct dcerpc_binding *final_binding;
433 struct dcerpc_pipe *final_pipe;
435 /* information about the progress */
436 void (*monitor_fn)(struct monitor_msg*);
440 static void continue_dci_rpc_connect(struct composite_context *ctx);
441 static void continue_lsa_policy(struct rpc_request *req);
442 static void continue_lsa_query_info(struct rpc_request *req);
443 static void continue_lsa_query_info2(struct rpc_request *req);
444 static void continue_epm_map_binding(struct composite_context *ctx);
445 static void continue_secondary_conn(struct composite_context *ctx);
446 static void continue_epm_map_binding_send(struct composite_context *c);
450 * Initiates connection to rpc pipe on remote server or pdc. Received result
451 * contains info on the domain name, domain sid and realm.
453 * @param ctx initialised libnet context
454 * @param mem_ctx memory context of this call
455 * @param r data structure containing necessary parameters and return values. Must be a talloc context
456 * @return composite context of this call
459 static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
460 TALLOC_CTX *mem_ctx,
461 struct libnet_RpcConnect *r,
462 void (*monitor)(struct monitor_msg*))
464 struct composite_context *c, *conn_req;
465 struct rpc_connect_dci_state *s;
467 /* composite context allocation and setup */
468 c = composite_create(ctx, ctx->event_ctx);
469 if (c == NULL) return c;
471 s = talloc_zero(c, struct rpc_connect_dci_state);
472 if (composite_nomem(s, c)) return c;
474 c->private_data = s;
475 s->monitor_fn = monitor;
477 s->ctx = ctx;
478 s->r = *r;
479 ZERO_STRUCT(s->r.out);
481 /* proceed to pure rpc connection if the binding string is provided,
482 otherwise try to connect domain controller */
483 if (r->in.binding == NULL) {
484 s->rpc_conn.in.name = r->in.name;
485 s->rpc_conn.level = LIBNET_RPC_CONNECT_DC;
486 } else {
487 s->rpc_conn.in.binding = r->in.binding;
488 s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING;
491 /* we need to query information on lsarpc interface first */
492 s->rpc_conn.in.dcerpc_iface = &ndr_table_lsarpc;
494 /* request connection to the lsa pipe on the pdc */
495 conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
496 if (composite_nomem(c, conn_req)) return c;
498 composite_continue(c, conn_req, continue_dci_rpc_connect, c);
499 return c;
504 Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
505 lsa policy handle
507 static void continue_dci_rpc_connect(struct composite_context *ctx)
509 struct composite_context *c;
510 struct rpc_connect_dci_state *s;
511 struct rpc_request *open_pol_req;
513 c = talloc_get_type(ctx->async.private_data, struct composite_context);
514 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
516 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
517 if (!NT_STATUS_IS_OK(c->status)) {
518 composite_error(c, c->status);
519 return;
522 /* post monitor message */
523 if (s->monitor_fn) {
524 struct monitor_msg msg;
525 struct msg_net_rpc_connect data;
526 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
528 data.host = binding->host;
529 data.endpoint = binding->endpoint;
530 data.transport = binding->transport;
531 data.domain_name = binding->target_hostname;
533 msg.type = mon_NetRpcConnect;
534 msg.data = (void*)&data;
535 msg.data_size = sizeof(data);
536 s->monitor_fn(&msg);
539 /* prepare to open a policy handle on lsa pipe */
540 s->lsa_pipe = s->ctx->lsa.pipe;
542 s->qos.len = 0;
543 s->qos.impersonation_level = 2;
544 s->qos.context_mode = 1;
545 s->qos.effective_only = 0;
547 s->attr.sec_qos = &s->qos;
549 s->lsa_open_policy.in.attr = &s->attr;
550 s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
551 if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
553 s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
554 s->lsa_open_policy.out.handle = &s->lsa_handle;
556 open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
557 if (composite_nomem(open_pol_req, c)) return;
559 composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
564 Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
565 for kerberos realm (dns name) and guid. The query may fail.
567 static void continue_lsa_policy(struct rpc_request *req)
569 struct composite_context *c;
570 struct rpc_connect_dci_state *s;
571 struct rpc_request *query_info_req;
573 c = talloc_get_type(req->async.private_data, struct composite_context);
574 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
576 c->status = dcerpc_ndr_request_recv(req);
577 if (!NT_STATUS_IS_OK(c->status)) {
578 composite_error(c, c->status);
579 return;
582 if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
583 s->r.out.realm = NULL;
584 s->r.out.guid = NULL;
585 s->r.out.domain_name = NULL;
586 s->r.out.domain_sid = NULL;
588 /* Skip to the creating the actual connection, no info available on this transport */
589 continue_epm_map_binding_send(c);
590 return;
592 } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
593 composite_error(c, s->lsa_open_policy.out.result);
594 return;
597 /* post monitor message */
598 if (s->monitor_fn) {
599 struct monitor_msg msg;
601 msg.type = mon_LsaOpenPolicy;
602 msg.data = NULL;
603 msg.data_size = 0;
604 s->monitor_fn(&msg);
607 /* query lsa info for dns domain name and guid */
608 s->lsa_query_info2.in.handle = &s->lsa_handle;
609 s->lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
610 s->lsa_query_info2.out.info = talloc_zero(c, union lsa_PolicyInformation *);
611 if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
613 query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
614 if (composite_nomem(query_info_req, c)) return;
616 composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
621 Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
622 may result in failure) and query lsa info for domain name and sid.
624 static void continue_lsa_query_info2(struct rpc_request *req)
626 struct composite_context *c;
627 struct rpc_connect_dci_state *s;
628 struct rpc_request *query_info_req;
630 c = talloc_get_type(req->async.private_data, struct composite_context);
631 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
633 c->status = dcerpc_ndr_request_recv(req);
635 /* In case of error just null the realm and guid and proceed
636 to the next step. After all, it doesn't have to be AD domain
637 controller we talking to - NT-style PDC also counts */
639 if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
640 s->r.out.realm = NULL;
641 s->r.out.guid = NULL;
643 } else {
644 if (!NT_STATUS_IS_OK(c->status)) {
645 s->r.out.error_string = talloc_asprintf(c,
646 "lsa_QueryInfoPolicy2 failed: %s",
647 nt_errstr(c->status));
648 composite_error(c, c->status);
649 return;
652 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
653 s->r.out.error_string = talloc_asprintf(c,
654 "lsa_QueryInfoPolicy2 failed: %s",
655 nt_errstr(s->lsa_query_info2.out.result));
656 composite_error(c, s->lsa_query_info2.out.result);
657 return;
660 /* Copy the dns domain name and guid from the query result */
662 /* this should actually be a conversion from lsa_StringLarge */
663 s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
664 s->r.out.guid = talloc(c, struct GUID);
665 if (composite_nomem(s->r.out.guid, c)) {
666 s->r.out.error_string = NULL;
667 return;
669 *s->r.out.guid = (*s->lsa_query_info2.out.info)->dns.domain_guid;
672 /* post monitor message */
673 if (s->monitor_fn) {
674 struct monitor_msg msg;
676 msg.type = mon_LsaQueryPolicy;
677 msg.data = NULL;
678 msg.data_size = 0;
679 s->monitor_fn(&msg);
682 /* query lsa info for domain name and sid */
683 s->lsa_query_info.in.handle = &s->lsa_handle;
684 s->lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
685 s->lsa_query_info.out.info = talloc_zero(c, union lsa_PolicyInformation *);
686 if (composite_nomem(s->lsa_query_info.out.info, c)) return;
688 query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
689 if (composite_nomem(query_info_req, c)) return;
691 composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
696 Step 5 of RpcConnectDCInfo: Get domain name and sid
698 static void continue_lsa_query_info(struct rpc_request *req)
700 struct composite_context *c;
701 struct rpc_connect_dci_state *s;
703 c = talloc_get_type(req->async.private_data, struct composite_context);
704 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
706 c->status = dcerpc_ndr_request_recv(req);
707 if (!NT_STATUS_IS_OK(c->status)) {
708 s->r.out.error_string = talloc_asprintf(c,
709 "lsa_QueryInfoPolicy failed: %s",
710 nt_errstr(c->status));
711 composite_error(c, c->status);
712 return;
715 /* post monitor message */
716 if (s->monitor_fn) {
717 struct monitor_msg msg;
719 msg.type = mon_LsaQueryPolicy;
720 msg.data = NULL;
721 msg.data_size = 0;
722 s->monitor_fn(&msg);
725 /* Copy the domain name and sid from the query result */
726 s->r.out.domain_sid = (*s->lsa_query_info.out.info)->domain.sid;
727 s->r.out.domain_name = (*s->lsa_query_info.out.info)->domain.name.string;
729 continue_epm_map_binding_send(c);
733 Step 5 (continued) of RpcConnectDCInfo: request endpoint
734 map binding.
736 We may short-cut to this step if we don't support LSA OpenPolicy on this transport
738 static void continue_epm_map_binding_send(struct composite_context *c)
740 struct rpc_connect_dci_state *s;
741 struct composite_context *epm_map_req;
742 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
744 /* prepare to get endpoint mapping for the requested interface */
745 s->final_binding = talloc(s, struct dcerpc_binding);
746 if (composite_nomem(s->final_binding, c)) return;
748 *s->final_binding = *s->lsa_pipe->binding;
749 /* Ensure we keep hold of the member elements */
750 if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
752 epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
753 s->lsa_pipe->conn->event_ctx, s->ctx->lp_ctx);
754 if (composite_nomem(epm_map_req, c)) return;
756 composite_continue(c, epm_map_req, continue_epm_map_binding, c);
760 Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
761 rpc connection derived from already used pipe but connected to the requested
762 one (as specified in libnet_RpcConnect structure)
764 static void continue_epm_map_binding(struct composite_context *ctx)
766 struct composite_context *c, *sec_conn_req;
767 struct rpc_connect_dci_state *s;
769 c = talloc_get_type(ctx->async.private_data, struct composite_context);
770 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
772 c->status = dcerpc_epm_map_binding_recv(ctx);
773 if (!NT_STATUS_IS_OK(c->status)) {
774 s->r.out.error_string = talloc_asprintf(c,
775 "failed to map pipe with endpoint mapper - %s",
776 nt_errstr(c->status));
777 composite_error(c, c->status);
778 return;
781 /* create secondary connection derived from lsa pipe */
782 sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
783 if (composite_nomem(sec_conn_req, c)) return;
785 composite_continue(c, sec_conn_req, continue_secondary_conn, c);
790 Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
791 and complete this composite call
793 static void continue_secondary_conn(struct composite_context *ctx)
795 struct composite_context *c;
796 struct rpc_connect_dci_state *s;
798 c = talloc_get_type(ctx->async.private_data, struct composite_context);
799 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
801 c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
802 if (!NT_STATUS_IS_OK(c->status)) {
803 s->r.out.error_string = talloc_asprintf(c,
804 "secondary connection failed: %s",
805 nt_errstr(c->status));
807 composite_error(c, c->status);
808 return;
811 s->r.out.dcerpc_pipe = s->final_pipe;
813 /* post monitor message */
814 if (s->monitor_fn) {
815 struct monitor_msg msg;
816 struct msg_net_rpc_connect data;
817 struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;
819 /* prepare monitor message and post it */
820 data.host = binding->host;
821 data.endpoint = binding->endpoint;
822 data.transport = binding->transport;
823 data.domain_name = binding->target_hostname;
825 msg.type = mon_NetRpcConnect;
826 msg.data = (void*)&data;
827 msg.data_size = sizeof(data);
828 s->monitor_fn(&msg);
831 composite_done(c);
836 * Receives result of connection to rpc pipe and gets basic
837 * domain info (name, sid, realm, guid)
839 * @param c composite context
840 * @param ctx initialised libnet context
841 * @param mem_ctx memory context of this call
842 * @param r data structure containing return values
843 * @return nt status of rpc connection
846 static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
847 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
849 NTSTATUS status;
850 struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
851 struct rpc_connect_dci_state);
853 status = composite_wait(c);
854 if (NT_STATUS_IS_OK(status)) {
855 r->out.realm = talloc_steal(mem_ctx, s->r.out.realm);
856 r->out.guid = talloc_steal(mem_ctx, s->r.out.guid);
857 r->out.domain_name = talloc_steal(mem_ctx, s->r.out.domain_name);
858 r->out.domain_sid = talloc_steal(mem_ctx, s->r.out.domain_sid);
860 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
862 /* reference created pipe structure to long-term libnet_context
863 so that it can be used by other api functions even after short-term
864 mem_ctx is freed */
865 if (r->in.dcerpc_iface == &ndr_table_samr) {
866 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
868 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
869 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
872 } else {
873 if (s->r.out.error_string) {
874 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
875 } else if (r->in.binding == NULL) {
876 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
877 } else {
878 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s",
879 r->in.binding, nt_errstr(status));
883 talloc_free(c);
884 return status;
889 * Initiates connection to rpc pipe on remote server or pdc, optionally
890 * providing domain info
892 * @param ctx initialised libnet context
893 * @param mem_ctx memory context of this call
894 * @param r data structure containing necessary parameters and return values
895 * @return composite context of this call
898 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
899 TALLOC_CTX *mem_ctx,
900 struct libnet_RpcConnect *r,
901 void (*monitor)(struct monitor_msg*))
903 struct composite_context *c;
905 switch (r->level) {
906 case LIBNET_RPC_CONNECT_SERVER:
907 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
908 case LIBNET_RPC_CONNECT_BINDING:
909 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
910 break;
912 case LIBNET_RPC_CONNECT_PDC:
913 case LIBNET_RPC_CONNECT_DC:
914 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
915 break;
917 case LIBNET_RPC_CONNECT_DC_INFO:
918 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
919 break;
921 default:
922 c = talloc_zero(mem_ctx, struct composite_context);
923 composite_error(c, NT_STATUS_INVALID_LEVEL);
926 return c;
931 * Receives result of connection to rpc pipe on remote server or pdc
933 * @param c composite context
934 * @param ctx initialised libnet context
935 * @param mem_ctx memory context of this call
936 * @param r data structure containing necessary parameters and return values
937 * @return nt status of rpc connection
940 NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
941 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
943 switch (r->level) {
944 case LIBNET_RPC_CONNECT_SERVER:
945 case LIBNET_RPC_CONNECT_BINDING:
946 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
948 case LIBNET_RPC_CONNECT_PDC:
949 case LIBNET_RPC_CONNECT_DC:
950 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
952 case LIBNET_RPC_CONNECT_DC_INFO:
953 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
955 default:
956 ZERO_STRUCT(r->out);
957 return NT_STATUS_INVALID_LEVEL;
963 * Connect to a rpc pipe on a remote server - sync version
965 * @param ctx initialised libnet context
966 * @param mem_ctx memory context of this call
967 * @param r data structure containing necessary parameters and return values
968 * @return nt status of rpc connection
971 NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
972 struct libnet_RpcConnect *r)
974 struct composite_context *c;
976 c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
977 return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);