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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "libnet/libnet.h"
24 #include "libcli/libcli.h"
25 #include "libcli/composite/composite.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/gen_ndr/ndr_lsa_c.h"
28 #include "librpc/gen_ndr/ndr_samr.h"
29
30
31 struct rpc_connect_srv_state {
32 struct libnet_context *ctx;
33 struct libnet_RpcConnect r;
34 const char *binding;
35 };
36
37
38 static void continue_pipe_connect(struct composite_context *ctx);
39
40
41 /**
42 * Initiates connection to rpc pipe on remote server
43 *
44 * @param ctx initialised libnet context
45 * @param mem_ctx memory context of this call
46 * @param r data structure containing necessary parameters and return values
47 * @return composite context of this call
48 **/
49
libnet_RpcConnectSrv_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)50 static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
51 TALLOC_CTX *mem_ctx,
52 struct libnet_RpcConnect *r)
53 {
54 struct composite_context *c;
55 struct rpc_connect_srv_state *s;
56 struct dcerpc_binding *b;
57 struct composite_context *pipe_connect_req;
58
59 /* composite context allocation and setup */
60 c = talloc_zero(mem_ctx, struct composite_context);
61 if (c == NULL) return NULL;
62
63 s = talloc_zero(c, struct rpc_connect_srv_state);
64 if (composite_nomem(s, c)) return c;
65
66 c->state = COMPOSITE_STATE_IN_PROGRESS;
67 c->private_data = s;
68 c->event_ctx = ctx->event_ctx;
69
70 s->ctx = ctx;
71 s->r = *r;
72 ZERO_STRUCT(s->r.out);
73
74 /* prepare binding string */
75 switch (r->level) {
76 case LIBNET_RPC_CONNECT_SERVER:
77 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
78 break;
79 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
80 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
81 break;
82
83 case LIBNET_RPC_CONNECT_BINDING:
84 s->binding = talloc_strdup(s, r->in.binding);
85 break;
86
87 case LIBNET_RPC_CONNECT_DC:
88 case LIBNET_RPC_CONNECT_PDC:
89 /* this should never happen - DC and PDC level has a separate
90 composite function */
91 case LIBNET_RPC_CONNECT_DC_INFO:
92 /* this should never happen - DC_INFO level has a separate
93 composite function */
94 composite_error(c, NT_STATUS_INVALID_LEVEL);
95 return c;
96 }
97
98 /* parse binding string to the structure */
99 c->status = dcerpc_parse_binding(c, s->binding, &b);
100 if (!NT_STATUS_IS_OK(c->status)) {
101 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
102 composite_error(c, c->status);
103 return c;
104 }
105
106 if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
107 b->target_hostname = talloc_reference(b, r->in.name);
108 if (composite_nomem(b->target_hostname, c)) {
109 return c;
110 }
111 }
112
113 /* connect to remote dcerpc pipe */
114 pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
115 ctx->cred, c->event_ctx);
116 if (composite_nomem(pipe_connect_req, c)) return c;
117
118 composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
119 return c;
120 }
121
122
123 /*
124 Step 2 of RpcConnectSrv - get rpc connection
125 */
continue_pipe_connect(struct composite_context * ctx)126 static void continue_pipe_connect(struct composite_context *ctx)
127 {
128 struct composite_context *c;
129 struct rpc_connect_srv_state *s;
130
131 c = talloc_get_type(ctx->async.private_data, struct composite_context);
132 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
133
134 /* receive result of rpc pipe connection */
135 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
136
137 composite_done(c);
138 }
139
140
141 /**
142 * Receives result of connection to rpc pipe on remote server
143 *
144 * @param c composite context
145 * @param ctx initialised libnet context
146 * @param mem_ctx memory context of this call
147 * @param r data structure containing necessary parameters and return values
148 * @return nt status of rpc connection
149 **/
150
libnet_RpcConnectSrv_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)151 static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
152 struct libnet_context *ctx,
153 TALLOC_CTX *mem_ctx,
154 struct libnet_RpcConnect *r)
155 {
156 NTSTATUS status;
157 struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
158 struct rpc_connect_srv_state);
159
160 status = composite_wait(c);
161 if (NT_STATUS_IS_OK(status)) {
162 /* move the returned rpc pipe between memory contexts */
163 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
164 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
165
166 /* reference created pipe structure to long-term libnet_context
167 so that it can be used by other api functions even after short-term
168 mem_ctx is freed */
169 if (r->in.dcerpc_iface == &dcerpc_table_samr) {
170 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
171
172 } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
173 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
174 }
175
176 r->out.error_string = talloc_strdup(mem_ctx, "Success");
177
178 } else {
179 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
180 }
181
182 talloc_free(c);
183 return status;
184 }
185
186
187 struct rpc_connect_dc_state {
188 struct libnet_context *ctx;
189 struct libnet_RpcConnect r;
190 struct libnet_RpcConnect r2;
191 struct libnet_LookupDCs f;
192 const char *connect_name;
193
194 /* information about the progress */
195 void (*monitor_fn)(struct monitor_msg *);
196 };
197
198
199 static void continue_lookup_dc(struct composite_context *ctx);
200 static void continue_rpc_connect(struct composite_context *ctx);
201
202
203 /**
204 * Initiates connection to rpc pipe on domain pdc
205 *
206 * @param ctx initialised libnet context
207 * @param mem_ctx memory context of this call
208 * @param r data structure containing necessary parameters and return values
209 * @return composite context of this call
210 **/
211
libnet_RpcConnectDC_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)212 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
213 TALLOC_CTX *mem_ctx,
214 struct libnet_RpcConnect *r)
215 {
216 struct composite_context *c;
217 struct rpc_connect_dc_state *s;
218 struct composite_context *lookup_dc_req;
219
220 /* composite context allocation and setup */
221 c = talloc_zero(mem_ctx, struct composite_context);
222 if (c == NULL) return NULL;
223
224 s = talloc_zero(c, struct rpc_connect_dc_state);
225 if (composite_nomem(s, c)) return c;
226
227 c->state = COMPOSITE_STATE_IN_PROGRESS;
228 c->private_data = s;
229 c->event_ctx = ctx->event_ctx;
230
231 s->ctx = ctx;
232 s->r = *r;
233 ZERO_STRUCT(s->r.out);
234
235 switch (r->level) {
236 case LIBNET_RPC_CONNECT_PDC:
237 s->f.in.name_type = NBT_NAME_PDC;
238 break;
239
240 case LIBNET_RPC_CONNECT_DC:
241 s->f.in.name_type = NBT_NAME_LOGON;
242 break;
243
244 default:
245 break;
246 }
247
248 s->f.in.domain_name = r->in.name;
249 s->f.out.num_dcs = 0;
250 s->f.out.dcs = NULL;
251
252 /* find the domain pdc first */
253 lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
254 if (composite_nomem(lookup_dc_req, c)) return c;
255
256 composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
257 return c;
258 }
259
260
261 /*
262 Step 2 of RpcConnectDC: get domain controller name and
263 initiate RpcConnect to it
264 */
continue_lookup_dc(struct composite_context * ctx)265 static void continue_lookup_dc(struct composite_context *ctx)
266 {
267 struct composite_context *c;
268 struct rpc_connect_dc_state *s;
269 struct composite_context *rpc_connect_req;
270 struct monitor_msg msg;
271 struct msg_net_lookup_dc data;
272
273 c = talloc_get_type(ctx->async.private_data, struct composite_context);
274 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
275
276 /* receive result of domain controller lookup */
277 c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
278 if (!composite_is_ok(c)) return;
279
280 /* decide on preferred address type depending on DC type */
281 s->connect_name = s->f.out.dcs[0].name;
282
283 /* prepare a monitor message and post it */
284 msg.type = net_lookup_dc;
285 msg.data = &data;
286 msg.data_size = sizeof(data);
287
288 data.domain_name = s->f.in.domain_name;
289 data.hostname = s->f.out.dcs[0].name;
290 data.address = s->f.out.dcs[0].address;
291
292 if (s->monitor_fn) s->monitor_fn(&msg);
293
294 /* ok, pdc has been found so do attempt to rpc connect */
295 s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
296
297 /* this will cause yet another name resolution, but at least
298 * we pass the right name down the stack now */
299 s->r2.in.name = talloc_strdup(s, s->connect_name);
300 s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address);
301 s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface;
302
303 /* send rpc connect request to the server */
304 rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2);
305 if (composite_nomem(rpc_connect_req, c)) return;
306
307 composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
308 }
309
310
311 /*
312 Step 3 of RpcConnectDC: get rpc connection to the server
313 */
continue_rpc_connect(struct composite_context * ctx)314 static void continue_rpc_connect(struct composite_context *ctx)
315 {
316 struct composite_context *c;
317 struct rpc_connect_dc_state *s;
318 struct monitor_msg msg;
319 struct msg_net_pipe_connected data;
320
321 c = talloc_get_type(ctx->async.private_data, struct composite_context);
322 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
323
324 c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
325
326 /* error string is to be passed anyway */
327 s->r.out.error_string = s->r2.out.error_string;
328 if (!composite_is_ok(c)) return;
329
330 s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
331
332 /* prepare a monitor message and post it */
333 data.host = s->r.out.dcerpc_pipe->binding->host;
334 data.endpoint = s->r.out.dcerpc_pipe->binding->endpoint;
335 data.transport = s->r.out.dcerpc_pipe->binding->transport;
336
337 msg.type = net_pipe_connected;
338 msg.data = (void*)&data;
339 msg.data_size = sizeof(data);
340
341 if (s->monitor_fn) s->monitor_fn(&msg);
342
343 composite_done(c);
344 }
345
346
347 /**
348 * Receives result of connection to rpc pipe on domain pdc
349 *
350 * @param c composite context
351 * @param ctx initialised libnet context
352 * @param mem_ctx memory context of this call
353 * @param r data structure containing necessary parameters and return values
354 * @return nt status of rpc connection
355 **/
356
libnet_RpcConnectDC_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)357 static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
358 struct libnet_context *ctx,
359 TALLOC_CTX *mem_ctx,
360 struct libnet_RpcConnect *r)
361 {
362 NTSTATUS status;
363 struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
364 struct rpc_connect_dc_state);
365
366 status = composite_wait(c);
367 if (NT_STATUS_IS_OK(status)) {
368 /* move connected rpc pipe between memory contexts */
369 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
370
371 /* reference created pipe structure to long-term libnet_context
372 so that it can be used by other api functions even after short-term
373 mem_ctx is freed */
374 if (r->in.dcerpc_iface == &dcerpc_table_samr) {
375 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
376
377 } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
378 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
379 }
380
381 } else {
382 r->out.error_string = talloc_asprintf(mem_ctx,
383 "Failed to rpc connect: %s",
384 nt_errstr(status));
385 }
386
387 talloc_free(c);
388 return status;
389 }
390
391
392
393 struct rpc_connect_dci_state {
394 struct libnet_context *ctx;
395 struct libnet_RpcConnect r;
396 struct libnet_RpcConnect rpc_conn;
397 struct policy_handle lsa_handle;
398 struct lsa_QosInfo qos;
399 struct lsa_ObjectAttribute attr;
400 struct lsa_OpenPolicy2 lsa_open_policy;
401 struct dcerpc_pipe *lsa_pipe;
402 struct lsa_QueryInfoPolicy2 lsa_query_info2;
403 struct lsa_QueryInfoPolicy lsa_query_info;
404 struct dcerpc_binding *final_binding;
405 struct dcerpc_pipe *final_pipe;
406 };
407
408
409 static void continue_dci_rpc_connect(struct composite_context *ctx);
410 static void continue_lsa_policy(struct rpc_request *req);
411 static void continue_lsa_query_info(struct rpc_request *req);
412 static void continue_lsa_query_info2(struct rpc_request *req);
413 static void continue_epm_map_binding(struct composite_context *ctx);
414 static void continue_secondary_conn(struct composite_context *ctx);
415 static void continue_epm_map_binding_send(struct composite_context *c);
416
417
418 /**
419 * Initiates connection to rpc pipe on remote server or pdc. Received result
420 * contains info on the domain name, domain sid and realm.
421 *
422 * @param ctx initialised libnet context
423 * @param mem_ctx memory context of this call
424 * @param r data structure containing necessary parameters and return values. Must be a talloc context
425 * @return composite context of this call
426 **/
427
libnet_RpcConnectDCInfo_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)428 static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
429 TALLOC_CTX *mem_ctx,
430 struct libnet_RpcConnect *r)
431 {
432 struct composite_context *c, *conn_req;
433 struct rpc_connect_dci_state *s;
434
435 /* composite context allocation and setup */
436 c = talloc_zero(mem_ctx, struct composite_context);
437 if (c == NULL) return NULL;
438
439 s = talloc_zero(c, struct rpc_connect_dci_state);
440 if (composite_nomem(s, c)) return c;
441
442 c->state = COMPOSITE_STATE_IN_PROGRESS;
443 c->private_data = s;
444 c->event_ctx = ctx->event_ctx;
445
446 s->ctx = ctx;
447 s->r = *r;
448 ZERO_STRUCT(s->r.out);
449
450 /* proceed to pure rpc connection if the binding string is provided,
451 otherwise try to connect domain controller */
452 if (r->in.binding == NULL) {
453 s->rpc_conn.in.name = r->in.name;
454 s->rpc_conn.level = LIBNET_RPC_CONNECT_DC;
455 } else {
456 s->rpc_conn.in.binding = r->in.binding;
457 s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING;
458 }
459
460 /* we need to query information on lsarpc interface first */
461 s->rpc_conn.in.dcerpc_iface = &dcerpc_table_lsarpc;
462
463 /* request connection to the lsa pipe on the pdc */
464 conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn);
465 if (composite_nomem(c, conn_req)) return c;
466
467 composite_continue(c, conn_req, continue_dci_rpc_connect, c);
468 return c;
469 }
470
471
472 /*
473 Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
474 lsa policy handle
475 */
continue_dci_rpc_connect(struct composite_context * ctx)476 static void continue_dci_rpc_connect(struct composite_context *ctx)
477 {
478 struct composite_context *c;
479 struct rpc_connect_dci_state *s;
480 struct rpc_request *open_pol_req;
481
482 c = talloc_get_type(ctx->async.private_data, struct composite_context);
483 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
484
485 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
486 if (!NT_STATUS_IS_OK(c->status)) {
487 composite_error(c, c->status);
488 return;
489 }
490
491 /* prepare to open a policy handle on lsa pipe */
492 s->lsa_pipe = s->ctx->lsa.pipe;
493
494 s->qos.len = 0;
495 s->qos.impersonation_level = 2;
496 s->qos.context_mode = 1;
497 s->qos.effective_only = 0;
498
499 s->attr.sec_qos = &s->qos;
500
501 s->lsa_open_policy.in.attr = &s->attr;
502 s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
503 if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
504
505 s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
506 s->lsa_open_policy.out.handle = &s->lsa_handle;
507
508 open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
509 if (composite_nomem(open_pol_req, c)) return;
510
511 composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
512 }
513
514
515 /*
516 Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
517 for kerberos realm (dns name) and guid. The query may fail.
518 */
continue_lsa_policy(struct rpc_request * req)519 static void continue_lsa_policy(struct rpc_request *req)
520 {
521 struct composite_context *c;
522 struct rpc_connect_dci_state *s;
523 struct rpc_request *query_info_req;
524
525 c = talloc_get_type(req->async.private, struct composite_context);
526 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
527
528 c->status = dcerpc_ndr_request_recv(req);
529 if (!NT_STATUS_IS_OK(c->status)) {
530 composite_error(c, c->status);
531 return;
532 }
533
534 if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
535 s->r.out.realm = NULL;
536 s->r.out.guid = NULL;
537 s->r.out.domain_name = NULL;
538 s->r.out.domain_sid = NULL;
539 /* Skip to the creating the actual connection, no info available on this transport */
540 continue_epm_map_binding_send(c);
541 return;
542 } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
543 composite_error(c, s->lsa_open_policy.out.result);
544 return;
545 }
546
547 /* query lsa info for dns domain name and guid */
548 s->lsa_query_info2.in.handle = &s->lsa_handle;
549 s->lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
550
551 query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
552 if (composite_nomem(query_info_req, c)) return;
553
554 composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
555 }
556
557
558 /*
559 Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
560 may result in failure) and query lsa info for domain name and sid.
561 */
continue_lsa_query_info2(struct rpc_request * req)562 static void continue_lsa_query_info2(struct rpc_request *req)
563 {
564 struct composite_context *c;
565 struct rpc_connect_dci_state *s;
566 struct rpc_request *query_info_req;
567
568 c = talloc_get_type(req->async.private, struct composite_context);
569 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
570
571 c->status = dcerpc_ndr_request_recv(req);
572
573 /* In case of error just null the realm and guid and proceed
574 to the next step. After all, it doesn't have to be AD domain
575 controller we talking to - NT-style PDC also counts */
576
577 if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
578 s->r.out.realm = NULL;
579 s->r.out.guid = NULL;
580
581 } else {
582 if (!NT_STATUS_IS_OK(c->status)) {
583 s->r.out.error_string = talloc_asprintf(c,
584 "lsa_QueryInfoPolicy2 failed: %s",
585 nt_errstr(c->status));
586 composite_error(c, c->status);
587 return;
588 }
589
590 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
591 s->r.out.error_string = talloc_asprintf(c,
592 "lsa_QueryInfoPolicy2 failed: %s",
593 nt_errstr(s->lsa_query_info2.out.result));
594 composite_error(c, s->lsa_query_info2.out.result);
595 return;
596 }
597
598 /* Copy the dns domain name and guid from the query result */
599
600 /* this should actually be a conversion from lsa_StringLarge */
601 s->r.out.realm = s->lsa_query_info2.out.info->dns.dns_domain.string;
602 s->r.out.guid = talloc(c, struct GUID);
603 if (composite_nomem(s->r.out.guid, c)) {
604 s->r.out.error_string = NULL;
605 return;
606 }
607 *s->r.out.guid = s->lsa_query_info2.out.info->dns.domain_guid;
608 }
609
610 /* query lsa info for domain name and sid */
611 s->lsa_query_info.in.handle = &s->lsa_handle;
612 s->lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
613
614 query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
615 if (composite_nomem(query_info_req, c)) return;
616
617 composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
618 }
619
620
621 /*
622 Step 5 of RpcConnectDCInfo: Get domain name and sid
623 */
continue_lsa_query_info(struct rpc_request * req)624 static void continue_lsa_query_info(struct rpc_request *req)
625 {
626 struct composite_context *c;
627 struct rpc_connect_dci_state *s;
628
629 c = talloc_get_type(req->async.private, struct composite_context);
630 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
631
632 c->status = dcerpc_ndr_request_recv(req);
633 if (!NT_STATUS_IS_OK(c->status)) {
634 s->r.out.error_string = talloc_asprintf(c,
635 "lsa_QueryInfoPolicy failed: %s",
636 nt_errstr(c->status));
637 composite_error(c, c->status);
638 return;
639 }
640
641 /* Copy the domain name and sid from the query result */
642 s->r.out.domain_sid = s->lsa_query_info.out.info->domain.sid;
643 s->r.out.domain_name = s->lsa_query_info.out.info->domain.name.string;
644
645 continue_epm_map_binding_send(c);
646 }
647
648 /*
649 Step 5 (continued) of RpcConnectDCInfo: request endpoint
650 map binding.
651
652 We may short-cut to this step if we dont' support LSA OpenPolicy on this transport
653 */
continue_epm_map_binding_send(struct composite_context * c)654 static void continue_epm_map_binding_send(struct composite_context *c)
655 {
656 struct rpc_connect_dci_state *s;
657 struct composite_context *epm_map_req;
658 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
659
660 /* prepare to get endpoint mapping for the requested interface */
661 s->final_binding = talloc(s, struct dcerpc_binding);
662 if (composite_nomem(s->final_binding, c)) return;
663
664 *s->final_binding = *s->lsa_pipe->binding;
665 /* Ensure we keep hold of the member elements */
666 if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
667
668 epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
669 s->lsa_pipe->conn->event_ctx);
670 if (composite_nomem(epm_map_req, c)) return;
671
672 composite_continue(c, epm_map_req, continue_epm_map_binding, c);
673 }
674
675 /*
676 Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
677 rpc connection derived from already used pipe but connected to the requested
678 one (as specified in libnet_RpcConnect structure)
679 */
continue_epm_map_binding(struct composite_context * ctx)680 static void continue_epm_map_binding(struct composite_context *ctx)
681 {
682 struct composite_context *c, *sec_conn_req;
683 struct rpc_connect_dci_state *s;
684
685 c = talloc_get_type(ctx->async.private_data, struct composite_context);
686 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
687
688 c->status = dcerpc_epm_map_binding_recv(ctx);
689 if (!NT_STATUS_IS_OK(c->status)) {
690 s->r.out.error_string = talloc_asprintf(c,
691 "failed to map pipe with endpoint mapper - %s",
692 nt_errstr(c->status));
693 composite_error(c, c->status);
694 return;
695 }
696
697 /* create secondary connection derived from lsa pipe */
698 sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
699 if (composite_nomem(sec_conn_req, c)) return;
700
701 composite_continue(c, sec_conn_req, continue_secondary_conn, c);
702 }
703
704
705 /*
706 Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
707 and complete this composite call
708 */
continue_secondary_conn(struct composite_context * ctx)709 static void continue_secondary_conn(struct composite_context *ctx)
710 {
711 struct composite_context *c;
712 struct rpc_connect_dci_state *s;
713
714 c = talloc_get_type(ctx->async.private_data, struct composite_context);
715 s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
716
717 c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
718 if (!NT_STATUS_IS_OK(c->status)) {
719 s->r.out.error_string = talloc_asprintf(c,
720 "secondary connection failed: %s",
721 nt_errstr(c->status));
722
723 composite_error(c, c->status);
724 return;
725 }
726
727 s->r.out.dcerpc_pipe = s->final_pipe;
728 composite_done(c);
729 }
730
731
732 /**
733 * Receives result of connection to rpc pipe and gets basic
734 * domain info (name, sid, realm, guid)
735 *
736 * @param c composite context
737 * @param ctx initialised libnet context
738 * @param mem_ctx memory context of this call
739 * @param r data structure containing return values
740 * @return nt status of rpc connection
741 **/
742
libnet_RpcConnectDCInfo_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)743 static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
744 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
745 {
746 NTSTATUS status;
747 struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
748 struct rpc_connect_dci_state);
749
750 status = composite_wait(c);
751 if (NT_STATUS_IS_OK(status)) {
752 r->out.realm = talloc_steal(mem_ctx, s->r.out.realm);
753 r->out.guid = talloc_steal(mem_ctx, s->r.out.guid);
754 r->out.domain_name = talloc_steal(mem_ctx, s->r.out.domain_name);
755 r->out.domain_sid = talloc_steal(mem_ctx, s->r.out.domain_sid);
756
757 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
758
759 /* reference created pipe structure to long-term libnet_context
760 so that it can be used by other api functions even after short-term
761 mem_ctx is freed */
762 if (r->in.dcerpc_iface == &dcerpc_table_samr) {
763 ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
764
765 } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
766 ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
767 }
768
769 } else {
770 if (s->r.out.error_string) {
771 r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
772 } else {
773 r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
774 }
775 }
776
777 talloc_free(c);
778 return status;
779 }
780
781
782 /**
783 * Initiates connection to rpc pipe on remote server or pdc, optionally
784 * providing domain info
785 *
786 * @param ctx initialised libnet context
787 * @param mem_ctx memory context of this call
788 * @param r data structure containing necessary parameters and return values
789 * @return composite context of this call
790 **/
791
libnet_RpcConnect_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)792 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
793 TALLOC_CTX *mem_ctx,
794 struct libnet_RpcConnect *r)
795 {
796 struct composite_context *c;
797
798 switch (r->level) {
799 case LIBNET_RPC_CONNECT_SERVER:
800 case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
801 case LIBNET_RPC_CONNECT_BINDING:
802 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r);
803 break;
804
805 case LIBNET_RPC_CONNECT_PDC:
806 case LIBNET_RPC_CONNECT_DC:
807 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r);
808 break;
809
810 case LIBNET_RPC_CONNECT_DC_INFO:
811 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r);
812 break;
813
814 default:
815 c = talloc_zero(mem_ctx, struct composite_context);
816 composite_error(c, NT_STATUS_INVALID_LEVEL);
817 }
818
819 return c;
820 }
821
822
823 /**
824 * Receives result of connection to rpc pipe on remote server or pdc
825 *
826 * @param c composite context
827 * @param ctx initialised libnet context
828 * @param mem_ctx memory context of this call
829 * @param r data structure containing necessary parameters and return values
830 * @return nt status of rpc connection
831 **/
832
libnet_RpcConnect_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)833 NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
834 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
835 {
836 switch (r->level) {
837 case LIBNET_RPC_CONNECT_SERVER:
838 case LIBNET_RPC_CONNECT_BINDING:
839 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
840
841 case LIBNET_RPC_CONNECT_PDC:
842 case LIBNET_RPC_CONNECT_DC:
843 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
844
845 case LIBNET_RPC_CONNECT_DC_INFO:
846 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
847
848 default:
849 ZERO_STRUCT(r->out);
850 return NT_STATUS_INVALID_LEVEL;
851 }
852 }
853
854
855 /**
856 * Connect to a rpc pipe on a remote server - sync version
857 *
858 * @param ctx initialised libnet context
859 * @param mem_ctx memory context of this call
860 * @param r data structure containing necessary parameters and return values
861 * @return nt status of rpc connection
862 **/
863
libnet_RpcConnect(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_RpcConnect * r)864 NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
865 struct libnet_RpcConnect *r)
866 {
867 struct composite_context *c;
868
869 c = libnet_RpcConnect_send(ctx, mem_ctx, r);
870 return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
871 }
872