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