source: vendor/current/source4/libnet/libnet_rpc.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 30.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Copyright (C) Stefan Metzmacher 2004
5 Copyright (C) Rafal Szczesniak 2005
6
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.
11
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.
16
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/>.
19*/
20
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"
28#include "auth/credentials/credentials.h"
29
30struct rpc_connect_srv_state {
31 struct libnet_context *ctx;
32 struct libnet_RpcConnect r;
33 const char *binding;
34
35 /* information about the progress */
36 void (*monitor_fn)(struct monitor_msg*);
37};
38
39
40static void continue_pipe_connect(struct composite_context *ctx);
41
42
43/**
44 * Initiates connection to rpc pipe on remote server
45 *
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 **/
51
52static 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*))
56{
57 struct composite_context *c;
58 struct rpc_connect_srv_state *s;
59 struct dcerpc_binding *b;
60 struct composite_context *pipe_connect_req;
61
62 /* composite context allocation and setup */
63 c = composite_create(ctx, ctx->event_ctx);
64 if (c == NULL) return c;
65
66 s = talloc_zero(c, struct rpc_connect_srv_state);
67 if (composite_nomem(s, c)) return c;
68
69 c->private_data = s;
70 s->monitor_fn = monitor;
71
72 s->ctx = ctx;
73 s->r = *r;
74 ZERO_STRUCT(s->r.out);
75
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[target_hostname=%s]",
83 r->in.address, r->in.name);
84 break;
85
86 case LIBNET_RPC_CONNECT_BINDING:
87 s->binding = talloc_strdup(s, r->in.binding);
88 break;
89
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;
99 }
100
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;
107 }
108
109 switch (r->level) {
110 case LIBNET_RPC_CONNECT_SERVER:
111 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
112 c->status = dcerpc_binding_set_flags(b, r->in.dcerpc_flags, 0);
113 if (!composite_is_ok(c)) return c;
114 break;
115 default:
116 /* other types have already been checked before */
117 break;
118 }
119
120 if (DEBUGLEVEL >= 10) {
121 c->status = dcerpc_binding_set_flags(b, DCERPC_DEBUG_PRINT_BOTH, 0);
122 if (!composite_is_ok(c)) return c;
123 }
124
125 /* connect to remote dcerpc pipe */
126 pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
127 ctx->cred, c->event_ctx,
128 ctx->lp_ctx);
129 if (composite_nomem(pipe_connect_req, c)) return c;
130
131 composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
132 return c;
133}
134
135
136/*
137 Step 2 of RpcConnectSrv - get rpc connection
138*/
139static void continue_pipe_connect(struct composite_context *ctx)
140{
141 struct composite_context *c;
142 struct rpc_connect_srv_state *s;
143
144 c = talloc_get_type(ctx->async.private_data, struct composite_context);
145 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
146
147 /* receive result of rpc pipe connection */
148 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
149
150 /* post monitor message */
151 if (s->monitor_fn) {
152 struct monitor_msg msg;
153 struct msg_net_rpc_connect data;
154 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
155
156 /* prepare monitor message and post it */
157 data.host = dcerpc_binding_get_string_option(b, "host");
158 data.endpoint = dcerpc_binding_get_string_option(b, "endpoint");
159 data.transport = dcerpc_binding_get_transport(b);
160 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
161
162 msg.type = mon_NetRpcConnect;
163 msg.data = (void*)&data;
164 msg.data_size = sizeof(data);
165 s->monitor_fn(&msg);
166 }
167
168 composite_done(c);
169}
170
171
172/**
173 * Receives result of connection to rpc pipe on remote server
174 *
175 * @param c composite context
176 * @param ctx initialised libnet context
177 * @param mem_ctx memory context of this call
178 * @param r data structure containing necessary parameters and return values
179 * @return nt status of rpc connection
180 **/
181
182static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
183 struct libnet_context *ctx,
184 TALLOC_CTX *mem_ctx,
185 struct libnet_RpcConnect *r)
186{
187 NTSTATUS status;
188
189 status = composite_wait(c);
190 if (NT_STATUS_IS_OK(status)) {
191 struct rpc_connect_srv_state *s;
192
193 /* move the returned rpc pipe between memory contexts */
194 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
195 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
196
197 /* reference created pipe structure to long-term libnet_context
198 so that it can be used by other api functions even after short-term
199 mem_ctx is freed */
200 if (r->in.dcerpc_iface == &ndr_table_samr) {
201 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
202 ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
203
204 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
205 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
206 ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
207 }
208
209 r->out.error_string = talloc_strdup(mem_ctx, "Success");
210
211 } else {
212 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
213 }
214
215 talloc_free(c);
216 return status;
217}
218
219
220struct rpc_connect_dc_state {
221 struct libnet_context *ctx;
222 struct libnet_RpcConnect r;
223 struct libnet_RpcConnect r2;
224 struct libnet_LookupDCs f;
225 const char *connect_name;
226
227 /* information about the progress */
228 void (*monitor_fn)(struct monitor_msg *);
229};
230
231
232static void continue_lookup_dc(struct tevent_req *req);
233static void continue_rpc_connect(struct composite_context *ctx);
234
235
236/**
237 * Initiates connection to rpc pipe on domain pdc
238 *
239 * @param ctx initialised libnet context
240 * @param mem_ctx memory context of this call
241 * @param r data structure containing necessary parameters and return values
242 * @return composite context of this call
243 **/
244
245static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
246 TALLOC_CTX *mem_ctx,
247 struct libnet_RpcConnect *r,
248 void (*monitor)(struct monitor_msg *msg))
249{
250 struct composite_context *c;
251 struct rpc_connect_dc_state *s;
252 struct tevent_req *lookup_dc_req;
253
254 /* composite context allocation and setup */
255 c = composite_create(ctx, ctx->event_ctx);
256 if (c == NULL) return c;
257
258 s = talloc_zero(c, struct rpc_connect_dc_state);
259 if (composite_nomem(s, c)) return c;
260
261 c->private_data = s;
262 s->monitor_fn = monitor;
263
264 s->ctx = ctx;
265 s->r = *r;
266 ZERO_STRUCT(s->r.out);
267
268 switch (r->level) {
269 case LIBNET_RPC_CONNECT_PDC:
270 s->f.in.name_type = NBT_NAME_PDC;
271 break;
272
273 case LIBNET_RPC_CONNECT_DC:
274 s->f.in.name_type = NBT_NAME_LOGON;
275 break;
276
277 default:
278 break;
279 }
280
281 s->f.in.domain_name = r->in.name;
282 s->f.out.num_dcs = 0;
283 s->f.out.dcs = NULL;
284
285 /* find the domain pdc first */
286 lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
287 if (composite_nomem(lookup_dc_req, c)) return c;
288
289 tevent_req_set_callback(lookup_dc_req, continue_lookup_dc, c);
290 return c;
291}
292
293
294/*
295 Step 2 of RpcConnectDC: get domain controller name and
296 initiate RpcConnect to it
297*/
298static void continue_lookup_dc(struct tevent_req *req)
299{
300 struct composite_context *c;
301 struct rpc_connect_dc_state *s;
302 struct composite_context *rpc_connect_req;
303 struct monitor_msg msg;
304 struct msg_net_lookup_dc data;
305
306 c = tevent_req_callback_data(req, struct composite_context);
307 s = talloc_get_type_abort(c->private_data, struct rpc_connect_dc_state);
308
309 /* receive result of domain controller lookup */
310 c->status = libnet_LookupDCs_recv(req, c, &s->f);
311 if (!composite_is_ok(c)) return;
312
313 /* decide on preferred address type depending on DC type */
314 s->connect_name = s->f.out.dcs[0].name;
315
316 /* post monitor message */
317 if (s->monitor_fn) {
318 /* prepare a monitor message and post it */
319 data.domain_name = s->f.in.domain_name;
320 data.hostname = s->f.out.dcs[0].name;
321 data.address = s->f.out.dcs[0].address;
322
323 msg.type = mon_NetLookupDc;
324 msg.data = &data;
325 msg.data_size = sizeof(data);
326 s->monitor_fn(&msg);
327 }
328
329 /* ok, pdc has been found so do attempt to rpc connect */
330 s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
331
332 /* this will cause yet another name resolution, but at least
333 * we pass the right name down the stack now */
334 s->r2.in.name = talloc_strdup(s, s->connect_name);
335 s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address);
336 s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface;
337 s->r2.in.dcerpc_flags = s->r.in.dcerpc_flags;
338
339 /* send rpc connect request to the server */
340 rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);
341 if (composite_nomem(rpc_connect_req, c)) return;
342
343 composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
344}
345
346
347/*
348 Step 3 of RpcConnectDC: get rpc connection to the server
349*/
350static void continue_rpc_connect(struct composite_context *ctx)
351{
352 struct composite_context *c;
353 struct rpc_connect_dc_state *s;
354
355 c = talloc_get_type(ctx->async.private_data, struct composite_context);
356 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
357
358 c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
359
360 /* error string is to be passed anyway */
361 s->r.out.error_string = s->r2.out.error_string;
362 if (!composite_is_ok(c)) return;
363
364 s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
365
366 /* post monitor message */
367 if (s->monitor_fn) {
368 struct monitor_msg msg;
369 struct msg_net_rpc_connect data;
370 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
371
372 data.host = dcerpc_binding_get_string_option(b, "host");
373 data.endpoint = dcerpc_binding_get_string_option(b, "endpoint");
374 data.transport = dcerpc_binding_get_transport(b);
375 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
376
377 msg.type = mon_NetRpcConnect;
378 msg.data = (void*)&data;
379 msg.data_size = sizeof(data);
380 s->monitor_fn(&msg);
381 }
382
383 composite_done(c);
384}
385
386
387/**
388 * Receives result of connection to rpc pipe on domain pdc
389 *
390 * @param c composite context
391 * @param ctx initialised libnet context
392 * @param mem_ctx memory context of this call
393 * @param r data structure containing necessary parameters and return values
394 * @return nt status of rpc connection
395 **/
396
397static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
398 struct libnet_context *ctx,
399 TALLOC_CTX *mem_ctx,
400 struct libnet_RpcConnect *r)
401{
402 NTSTATUS status;
403 struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
404 struct rpc_connect_dc_state);
405
406 status = composite_wait(c);
407 if (NT_STATUS_IS_OK(status)) {
408 /* move connected rpc pipe between memory contexts
409
410 The use of talloc_reparent(talloc_parent(), ...) is
411 bizarre, but it is needed because of the absolutely
412 atrocious use of talloc in this code. We need to
413 force the original parent to change, but finding
414 the original parent is well nigh impossible at this
415 point in the code (yes, I tried).
416 */
417 r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe),
418 mem_ctx, s->r.out.dcerpc_pipe);
419
420 /* reference created pipe structure to long-term libnet_context
421 so that it can be used by other api functions even after short-term
422 mem_ctx is freed */
423 if (r->in.dcerpc_iface == &ndr_table_samr) {
424 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
425 ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
426 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
427 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
428 ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
429 }
430
431 } else {
432 r->out.error_string = talloc_asprintf(mem_ctx,
433 "Failed to rpc connect: %s",
434 nt_errstr(status));
435 }
436
437 talloc_free(c);
438 return status;
439}
440
441
442
443struct rpc_connect_dci_state {
444 struct libnet_context *ctx;
445 struct libnet_RpcConnect r;
446 struct libnet_RpcConnect rpc_conn;
447 struct policy_handle lsa_handle;
448 struct lsa_QosInfo qos;
449 struct lsa_ObjectAttribute attr;
450 struct lsa_OpenPolicy2 lsa_open_policy;
451 struct dcerpc_pipe *lsa_pipe;
452 struct lsa_QueryInfoPolicy2 lsa_query_info2;
453 struct lsa_QueryInfoPolicy lsa_query_info;
454 struct dcerpc_binding *final_binding;
455 struct dcerpc_pipe *final_pipe;
456
457 /* information about the progress */
458 void (*monitor_fn)(struct monitor_msg*);
459};
460
461
462static void continue_dci_rpc_connect(struct composite_context *ctx);
463static void continue_lsa_policy(struct tevent_req *subreq);
464static void continue_lsa_query_info(struct tevent_req *subreq);
465static void continue_lsa_query_info2(struct tevent_req *subreq);
466static void continue_epm_map_binding(struct composite_context *ctx);
467static void continue_secondary_conn(struct composite_context *ctx);
468static void continue_epm_map_binding_send(struct composite_context *c);
469
470
471/**
472 * Initiates connection to rpc pipe on remote server or pdc. Received result
473 * contains info on the domain name, domain sid and realm.
474 *
475 * @param ctx initialised libnet context
476 * @param mem_ctx memory context of this call
477 * @param r data structure containing necessary parameters and return values. Must be a talloc context
478 * @return composite context of this call
479 **/
480
481static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
482 TALLOC_CTX *mem_ctx,
483 struct libnet_RpcConnect *r,
484 void (*monitor)(struct monitor_msg*))
485{
486 struct composite_context *c, *conn_req;
487 struct rpc_connect_dci_state *s;
488
489 /* composite context allocation and setup */
490 c = composite_create(ctx, ctx->event_ctx);
491 if (c == NULL) return c;
492
493 s = talloc_zero(c, struct rpc_connect_dci_state);
494 if (composite_nomem(s, c)) return c;
495
496 c->private_data = s;
497 s->monitor_fn = monitor;
498
499 s->ctx = ctx;
500 s->r = *r;
501 ZERO_STRUCT(s->r.out);
502
503
504 /* proceed to pure rpc connection if the binding string is provided,
505 otherwise try to connect domain controller */
506 if (r->in.binding == NULL) {
507 /* Pass on any binding flags (such as anonymous fallback) that have been set */
508 s->rpc_conn.in.dcerpc_flags = r->in.dcerpc_flags;
509
510 s->rpc_conn.in.name = r->in.name;
511 s->rpc_conn.level = LIBNET_RPC_CONNECT_DC;
512 } else {
513 s->rpc_conn.in.binding = r->in.binding;
514 s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING;
515 }
516
517 /* we need to query information on lsarpc interface first */
518 s->rpc_conn.in.dcerpc_iface = &ndr_table_lsarpc;
519
520 /* request connection to the lsa pipe on the pdc */
521 conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
522 if (composite_nomem(c, conn_req)) return c;
523
524 composite_continue(c, conn_req, continue_dci_rpc_connect, c);
525 return c;
526}
527
528
529/*
530 Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
531 lsa policy handle
532*/
533static void continue_dci_rpc_connect(struct composite_context *ctx)
534{
535 struct composite_context *c;
536 struct rpc_connect_dci_state *s;
537 struct tevent_req *subreq;
538 enum dcerpc_transport_t transport;
539
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);
542
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;
547 }
548
549 /* post monitor message */
550 if (s->monitor_fn) {
551 struct monitor_msg msg;
552 struct msg_net_rpc_connect data;
553 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
554
555 data.host = dcerpc_binding_get_string_option(b, "host");
556 data.endpoint = dcerpc_binding_get_string_option(b, "endpoint");
557 data.transport = dcerpc_binding_get_transport(b);
558 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
559
560 msg.type = mon_NetRpcConnect;
561 msg.data = (void*)&data;
562 msg.data_size = sizeof(data);
563 s->monitor_fn(&msg);
564 }
565
566 /* prepare to open a policy handle on lsa pipe */
567 s->lsa_pipe = s->ctx->lsa.pipe;
568
569 s->qos.len = 0;
570 s->qos.impersonation_level = 2;
571 s->qos.context_mode = 1;
572 s->qos.effective_only = 0;
573
574 s->attr.sec_qos = &s->qos;
575
576 transport = dcerpc_binding_get_transport(s->lsa_pipe->binding);
577 if (transport == NCACN_IP_TCP) {
578 /*
579 * Skip to creating the actual connection. We can't open a
580 * policy handle over tcpip.
581 */
582 continue_epm_map_binding_send(c);
583 return;
584 }
585
586 s->lsa_open_policy.in.attr = &s->attr;
587 s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
588 if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
589
590 s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
591 s->lsa_open_policy.out.handle = &s->lsa_handle;
592
593 subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
594 s->lsa_pipe->binding_handle,
595 &s->lsa_open_policy);
596 if (composite_nomem(subreq, c)) return;
597
598 tevent_req_set_callback(subreq, continue_lsa_policy, c);
599}
600
601
602/*
603 Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
604 for kerberos realm (dns name) and guid. The query may fail.
605*/
606static void continue_lsa_policy(struct tevent_req *subreq)
607{
608 struct composite_context *c;
609 struct rpc_connect_dci_state *s;
610
611 c = tevent_req_callback_data(subreq, struct composite_context);
612 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
613
614 c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
615 TALLOC_FREE(subreq);
616 if (!NT_STATUS_IS_OK(c->status)) {
617 composite_error(c, c->status);
618 return;
619 }
620
621 if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
622 s->r.out.realm = NULL;
623 s->r.out.guid = NULL;
624 s->r.out.domain_name = NULL;
625 s->r.out.domain_sid = NULL;
626
627 /* Skip to the creating the actual connection, no info available on this transport */
628 continue_epm_map_binding_send(c);
629 return;
630
631 } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
632 composite_error(c, s->lsa_open_policy.out.result);
633 return;
634 }
635
636 /* post monitor message */
637 if (s->monitor_fn) {
638 struct monitor_msg msg;
639
640 msg.type = mon_LsaOpenPolicy;
641 msg.data = NULL;
642 msg.data_size = 0;
643 s->monitor_fn(&msg);
644 }
645
646 /* query lsa info for dns domain name and guid */
647 s->lsa_query_info2.in.handle = &s->lsa_handle;
648 s->lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
649 s->lsa_query_info2.out.info = talloc_zero(c, union lsa_PolicyInformation *);
650 if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
651
652 subreq = dcerpc_lsa_QueryInfoPolicy2_r_send(s, c->event_ctx,
653 s->lsa_pipe->binding_handle,
654 &s->lsa_query_info2);
655 if (composite_nomem(subreq, c)) return;
656
657 tevent_req_set_callback(subreq, continue_lsa_query_info2, c);
658}
659
660
661/*
662 Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
663 may result in failure) and query lsa info for domain name and sid.
664*/
665static void continue_lsa_query_info2(struct tevent_req *subreq)
666{
667 struct composite_context *c;
668 struct rpc_connect_dci_state *s;
669
670 c = tevent_req_callback_data(subreq, struct composite_context);
671 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
672
673 c->status = dcerpc_lsa_QueryInfoPolicy2_r_recv(subreq, s);
674 TALLOC_FREE(subreq);
675
676 /* In case of error just null the realm and guid and proceed
677 to the next step. After all, it doesn't have to be AD domain
678 controller we talking to - NT-style PDC also counts */
679
680 if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
681 s->r.out.realm = NULL;
682 s->r.out.guid = NULL;
683
684 } else {
685 if (!NT_STATUS_IS_OK(c->status)) {
686 s->r.out.error_string = talloc_asprintf(c,
687 "lsa_QueryInfoPolicy2 failed: %s",
688 nt_errstr(c->status));
689 composite_error(c, c->status);
690 return;
691 }
692
693 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
694 s->r.out.error_string = talloc_asprintf(c,
695 "lsa_QueryInfoPolicy2 failed: %s",
696 nt_errstr(s->lsa_query_info2.out.result));
697 composite_error(c, s->lsa_query_info2.out.result);
698 return;
699 }
700
701 /* Copy the dns domain name and guid from the query result */
702
703 /* this should actually be a conversion from lsa_StringLarge */
704 s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
705 s->r.out.guid = talloc(c, struct GUID);
706 if (composite_nomem(s->r.out.guid, c)) {
707 s->r.out.error_string = NULL;
708 return;
709 }
710 *s->r.out.guid = (*s->lsa_query_info2.out.info)->dns.domain_guid;
711 }
712
713 /* post monitor message */
714 if (s->monitor_fn) {
715 struct monitor_msg msg;
716
717 msg.type = mon_LsaQueryPolicy;
718 msg.data = NULL;
719 msg.data_size = 0;
720 s->monitor_fn(&msg);
721 }
722
723 /* query lsa info for domain name and sid */
724 s->lsa_query_info.in.handle = &s->lsa_handle;
725 s->lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
726 s->lsa_query_info.out.info = talloc_zero(c, union lsa_PolicyInformation *);
727 if (composite_nomem(s->lsa_query_info.out.info, c)) return;
728
729 subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
730 s->lsa_pipe->binding_handle,
731 &s->lsa_query_info);
732 if (composite_nomem(subreq, c)) return;
733
734 tevent_req_set_callback(subreq, continue_lsa_query_info, c);
735}
736
737
738/*
739 Step 5 of RpcConnectDCInfo: Get domain name and sid
740*/
741static void continue_lsa_query_info(struct tevent_req *subreq)
742{
743 struct composite_context *c;
744 struct rpc_connect_dci_state *s;
745
746 c = tevent_req_callback_data(subreq, struct composite_context);
747 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
748
749 c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
750 TALLOC_FREE(subreq);
751 if (!NT_STATUS_IS_OK(c->status)) {
752 s->r.out.error_string = talloc_asprintf(c,
753 "lsa_QueryInfoPolicy failed: %s",
754 nt_errstr(c->status));
755 composite_error(c, c->status);
756 return;
757 }
758
759 /* post monitor message */
760 if (s->monitor_fn) {
761 struct monitor_msg msg;
762
763 msg.type = mon_LsaQueryPolicy;
764 msg.data = NULL;
765 msg.data_size = 0;
766 s->monitor_fn(&msg);
767 }
768
769 /* Copy the domain name and sid from the query result */
770 s->r.out.domain_sid = (*s->lsa_query_info.out.info)->domain.sid;
771 s->r.out.domain_name = (*s->lsa_query_info.out.info)->domain.name.string;
772
773 continue_epm_map_binding_send(c);
774}
775
776/*
777 Step 5 (continued) of RpcConnectDCInfo: request endpoint
778 map binding.
779
780 We may short-cut to this step if we don't support LSA OpenPolicy on this transport
781*/
782static void continue_epm_map_binding_send(struct composite_context *c)
783{
784 struct rpc_connect_dci_state *s;
785 struct composite_context *epm_map_req;
786 struct cli_credentials *epm_creds = NULL;
787
788 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
789
790 /* prepare to get endpoint mapping for the requested interface */
791 s->final_binding = dcerpc_binding_dup(s, s->lsa_pipe->binding);
792 if (composite_nomem(s->final_binding, c)) return;
793
794 epm_creds = cli_credentials_init_anon(s);
795 if (composite_nomem(epm_creds, c)) return;
796
797 epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
798 epm_creds,
799 s->ctx->event_ctx, s->ctx->lp_ctx);
800 if (composite_nomem(epm_map_req, c)) return;
801
802 composite_continue(c, epm_map_req, continue_epm_map_binding, c);
803}
804
805/*
806 Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
807 rpc connection derived from already used pipe but connected to the requested
808 one (as specified in libnet_RpcConnect structure)
809*/
810static void continue_epm_map_binding(struct composite_context *ctx)
811{
812 struct composite_context *c, *sec_conn_req;
813 struct rpc_connect_dci_state *s;
814
815 c = talloc_get_type(ctx->async.private_data, struct composite_context);
816 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
817
818 c->status = dcerpc_epm_map_binding_recv(ctx);
819 if (!NT_STATUS_IS_OK(c->status)) {
820 s->r.out.error_string = talloc_asprintf(c,
821 "failed to map pipe with endpoint mapper - %s",
822 nt_errstr(c->status));
823 composite_error(c, c->status);
824 return;
825 }
826
827 /* create secondary connection derived from lsa pipe */
828 sec_conn_req = dcerpc_secondary_auth_connection_send(s->lsa_pipe,
829 s->final_binding,
830 s->r.in.dcerpc_iface,
831 s->ctx->cred,
832 s->ctx->lp_ctx);
833 if (composite_nomem(sec_conn_req, c)) return;
834
835 composite_continue(c, sec_conn_req, continue_secondary_conn, c);
836}
837
838
839/*
840 Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
841 and complete this composite call
842*/
843static void continue_secondary_conn(struct composite_context *ctx)
844{
845 struct composite_context *c;
846 struct rpc_connect_dci_state *s;
847
848 c = talloc_get_type(ctx->async.private_data, struct composite_context);
849 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
850
851 c->status = dcerpc_secondary_auth_connection_recv(ctx, s->lsa_pipe,
852 &s->final_pipe);
853 if (!NT_STATUS_IS_OK(c->status)) {
854 s->r.out.error_string = talloc_asprintf(c,
855 "secondary connection failed: %s",
856 nt_errstr(c->status));
857
858 composite_error(c, c->status);
859 return;
860 }
861
862 s->r.out.dcerpc_pipe = s->final_pipe;
863
864 /* post monitor message */
865 if (s->monitor_fn) {
866 struct monitor_msg msg;
867 struct msg_net_rpc_connect data;
868 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
869
870 /* prepare monitor message and post it */
871 data.host = dcerpc_binding_get_string_option(b, "host");
872 data.endpoint = dcerpc_binding_get_string_option(b, "endpoint");
873 data.transport = dcerpc_binding_get_transport(b);
874 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
875
876 msg.type = mon_NetRpcConnect;
877 msg.data = (void*)&data;
878 msg.data_size = sizeof(data);
879 s->monitor_fn(&msg);
880 }
881
882 composite_done(c);
883}
884
885
886/**
887 * Receives result of connection to rpc pipe and gets basic
888 * domain info (name, sid, realm, guid)
889 *
890 * @param c composite context
891 * @param ctx initialised libnet context
892 * @param mem_ctx memory context of this call
893 * @param r data structure containing return values
894 * @return nt status of rpc connection
895 **/
896
897static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
898 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
899{
900 NTSTATUS status;
901 struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
902 struct rpc_connect_dci_state);
903
904 status = composite_wait(c);
905 if (NT_STATUS_IS_OK(status)) {
906 r->out.realm = talloc_steal(mem_ctx, s->r.out.realm);
907 r->out.guid = talloc_steal(mem_ctx, s->r.out.guid);
908 r->out.domain_name = talloc_steal(mem_ctx, s->r.out.domain_name);
909 r->out.domain_sid = talloc_steal(mem_ctx, s->r.out.domain_sid);
910
911 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
912
913 /* reference created pipe structure to long-term libnet_context
914 so that it can be used by other api functions even after short-term
915 mem_ctx is freed */
916 if (r->in.dcerpc_iface == &ndr_table_samr) {
917 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
918 ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
919
920 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
921 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
922 ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
923 }
924
925 } else {
926 if (s->r.out.error_string) {
927 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
928 } else if (r->in.binding == NULL) {
929 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
930 } else {
931 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s",
932 r->in.binding, nt_errstr(status));
933 }
934 }
935
936 talloc_free(c);
937 return status;
938}
939
940
941/**
942 * Initiates connection to rpc pipe on remote server or pdc, optionally
943 * providing domain info
944 *
945 * @param ctx initialised libnet context
946 * @param mem_ctx memory context of this call
947 * @param r data structure containing necessary parameters and return values
948 * @return composite context of this call
949 **/
950
951struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
952 TALLOC_CTX *mem_ctx,
953 struct libnet_RpcConnect *r,
954 void (*monitor)(struct monitor_msg*))
955{
956 struct composite_context *c;
957
958 switch (r->level) {
959 case LIBNET_RPC_CONNECT_SERVER:
960 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
961 case LIBNET_RPC_CONNECT_BINDING:
962 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
963 break;
964
965 case LIBNET_RPC_CONNECT_PDC:
966 case LIBNET_RPC_CONNECT_DC:
967 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
968 break;
969
970 case LIBNET_RPC_CONNECT_DC_INFO:
971 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
972 break;
973
974 default:
975 c = talloc_zero(mem_ctx, struct composite_context);
976 composite_error(c, NT_STATUS_INVALID_LEVEL);
977 }
978
979 return c;
980}
981
982
983/**
984 * Receives result of connection to rpc pipe on remote server or pdc
985 *
986 * @param c composite context
987 * @param ctx initialised libnet context
988 * @param mem_ctx memory context of this call
989 * @param r data structure containing necessary parameters and return values
990 * @return nt status of rpc connection
991 **/
992
993NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
994 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
995{
996 switch (r->level) {
997 case LIBNET_RPC_CONNECT_SERVER:
998 case LIBNET_RPC_CONNECT_BINDING:
999 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
1000
1001 case LIBNET_RPC_CONNECT_PDC:
1002 case LIBNET_RPC_CONNECT_DC:
1003 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
1004
1005 case LIBNET_RPC_CONNECT_DC_INFO:
1006 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
1007
1008 default:
1009 ZERO_STRUCT(r->out);
1010 return NT_STATUS_INVALID_LEVEL;
1011 }
1012}
1013
1014
1015/**
1016 * Connect to a rpc pipe on a remote server - sync version
1017 *
1018 * @param ctx initialised libnet context
1019 * @param mem_ctx memory context of this call
1020 * @param r data structure containing necessary parameters and return values
1021 * @return nt status of rpc connection
1022 **/
1023
1024NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1025 struct libnet_RpcConnect *r)
1026{
1027 struct composite_context *c;
1028
1029 c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
1030 return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
1031}
Note: See TracBrowser for help on using the repository browser.