1 /*
2    Unix SMB/CIFS implementation.
3 
4    dcerpc utility functions
5 
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9    Copyright (C) Rafal Szczesniak 2006
10    Copyright (C) Stefan Metzmacher 2014
11 
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16 
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25 
26 #include "includes.h"
27 #include "../../lib/util/util_net.h"
28 #include "librpc/gen_ndr/ndr_epmapper.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/rpc/dcerpc.h"
31 #include "rpc_common.h"
32 
33 #undef strcasecmp
34 #undef strncasecmp
35 
36 #define MAX_PROTSEQ		10
37 
38 struct dcerpc_binding {
39 	enum dcerpc_transport_t transport;
40 	struct GUID object;
41 	const char *object_string;
42 	const char *host;
43 	const char *target_hostname;
44 	const char *target_principal;
45 	const char *endpoint;
46 	const char **options;
47 	uint32_t flags;
48 	uint32_t assoc_group_id;
49 	char assoc_group_string[11]; /* 0x3456789a + '\0' */
50 };
51 
52 static const struct {
53 	const char *name;
54 	enum dcerpc_transport_t transport;
55 	int num_protocols;
56 	enum epm_protocol protseq[MAX_PROTSEQ];
57 } transports[] = {
58 	{ "ncacn_np",     NCACN_NP, 3,
59 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
60 	{ "ncacn_ip_tcp", NCACN_IP_TCP, 3,
61 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } },
62 	{ "ncacn_http", NCACN_HTTP, 3,
63 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } },
64 	{ "ncadg_ip_udp", NCACN_IP_UDP, 3,
65 		{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
66 	{ "ncalrpc", NCALRPC, 2,
67 		{ EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_NAMED_PIPE } },
68 	{ "ncacn_unix_stream", NCACN_UNIX_STREAM, 2,
69 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
70 	{ "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2,
71 		{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
72 	{ "ncacn_at_dsp", NCACN_AT_DSP, 3,
73 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
74 	{ "ncadg_at_ddp", NCADG_AT_DDP, 3,
75 		{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
76 	{ "ncacn_vns_ssp", NCACN_VNS_SPP, 3,
77 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
78 	{ "ncacn_vns_ipc", NCACN_VNS_IPC, 3,
79 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
80 	{ "ncadg_ipx", NCADG_IPX, 2,
81 		{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
82 	},
83 	{ "ncacn_spx", NCACN_SPX, 3,
84 		/* I guess some MS programmer confused the identifier for
85 		 * EPM_PROTOCOL_UUID (0x0D or 13) with the one for
86 		 * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
87 		{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
88 	},
89 };
90 
91 static const struct ncacn_option {
92 	const char *name;
93 	uint32_t flag;
94 } ncacn_options[] = {
95 	{"sign", DCERPC_SIGN},
96 	{"seal", DCERPC_SEAL},
97 	{"connect", DCERPC_CONNECT},
98 	{"spnego", DCERPC_AUTH_SPNEGO},
99 	{"ntlm", DCERPC_AUTH_NTLM},
100 	{"krb5", DCERPC_AUTH_KRB5},
101 	{"schannel", DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO},
102 	{"validate", DCERPC_DEBUG_VALIDATE_BOTH},
103 	{"print", DCERPC_DEBUG_PRINT_BOTH},
104 	{"padcheck", DCERPC_DEBUG_PAD_CHECK},
105 	{"bigendian", DCERPC_PUSH_BIGENDIAN},
106 	{"smb1", DCERPC_SMB1},
107 	{"smb2", DCERPC_SMB2},
108 	{"ndr64", DCERPC_NDR64},
109 	{"packet", DCERPC_PACKET},
110 };
111 
ncacn_option_by_name(const char * name)112 static const struct ncacn_option *ncacn_option_by_name(const char *name)
113 {
114 	size_t i;
115 
116 	for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
117 		int ret;
118 
119 		ret = strcasecmp(ncacn_options[i].name, name);
120 		if (ret != 0) {
121 			continue;
122 		}
123 
124 		return &ncacn_options[i];
125 	}
126 
127 	return NULL;
128 }
129 
epm_floor_string(TALLOC_CTX * mem_ctx,struct epm_floor * epm_floor)130 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
131 {
132 	struct ndr_syntax_id syntax;
133 	NTSTATUS status;
134 
135 	switch(epm_floor->lhs.protocol) {
136 		case EPM_PROTOCOL_UUID:
137 			status = dcerpc_floor_get_lhs_data(epm_floor, &syntax);
138 			if (NT_STATUS_IS_OK(status)) {
139 				/* lhs is used: UUID */
140 				char *uuidstr;
141 
142 				if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
143 					return "NDR";
144 				}
145 
146 				if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
147 					return "NDR64";
148 				}
149 
150 				uuidstr = GUID_string(mem_ctx, &syntax.uuid);
151 
152 				return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, syntax.if_version);
153 			} else { /* IPX */
154 				return talloc_asprintf(mem_ctx, "IPX:%s",
155 						data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
156 			}
157 
158 		case EPM_PROTOCOL_NCACN:
159 			return "RPC-C";
160 
161 		case EPM_PROTOCOL_NCADG:
162 			return "RPC";
163 
164 		case EPM_PROTOCOL_NCALRPC:
165 			return "NCALRPC";
166 
167 		case EPM_PROTOCOL_DNET_NSP:
168 			return "DNET/NSP";
169 
170 		case EPM_PROTOCOL_IP:
171 			return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
172 
173 		case EPM_PROTOCOL_NAMED_PIPE:
174 			return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
175 
176 		case EPM_PROTOCOL_SMB:
177 			return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
178 
179 		case EPM_PROTOCOL_UNIX_DS:
180 			return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
181 
182 		case EPM_PROTOCOL_NETBIOS:
183 			return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
184 
185 		case EPM_PROTOCOL_NETBEUI:
186 			return "NETBeui";
187 
188 		case EPM_PROTOCOL_SPX:
189 			return "SPX";
190 
191 		case EPM_PROTOCOL_NB_IPX:
192 			return "NB_IPX";
193 
194 		case EPM_PROTOCOL_HTTP:
195 			return talloc_asprintf(mem_ctx, "HTTP:%d", epm_floor->rhs.http.port);
196 
197 		case EPM_PROTOCOL_TCP:
198 			return talloc_asprintf(mem_ctx, "TCP:%d", epm_floor->rhs.tcp.port);
199 
200 		case EPM_PROTOCOL_UDP:
201 			return talloc_asprintf(mem_ctx, "UDP:%d", epm_floor->rhs.udp.port);
202 
203 		default:
204 			return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
205 	}
206 }
207 
208 
209 /*
210   form a binding string from a binding structure
211 */
dcerpc_binding_string(TALLOC_CTX * mem_ctx,const struct dcerpc_binding * b)212 _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
213 {
214 	char *s = talloc_strdup(mem_ctx, "");
215 	char *o = s;
216 	int i;
217 	const char *t_name = NULL;
218 	bool option_section = false;
219 	const char *target_hostname = NULL;
220 
221 	if (b->transport != NCA_UNKNOWN) {
222 		t_name = derpc_transport_string_by_transport(b->transport);
223 		if (!t_name) {
224 			talloc_free(o);
225 			return NULL;
226 		}
227 	}
228 
229 	if (!GUID_all_zero(&b->object)) {
230 		o = s;
231 		s = talloc_asprintf_append_buffer(s, "%s@",
232 				    GUID_string(mem_ctx, &b->object));
233 		if (s == NULL) {
234 			talloc_free(o);
235 			return NULL;
236 		}
237 	}
238 
239 	if (t_name != NULL) {
240 		o = s;
241 		s = talloc_asprintf_append_buffer(s, "%s:", t_name);
242 		if (s == NULL) {
243 			talloc_free(o);
244 			return NULL;
245 		}
246 	}
247 
248 	if (b->host) {
249 		o = s;
250 		s = talloc_asprintf_append_buffer(s, "%s", b->host);
251 		if (s == NULL) {
252 			talloc_free(o);
253 			return NULL;
254 		}
255 	}
256 
257 	target_hostname = b->target_hostname;
258 	if (target_hostname != NULL && b->host != NULL) {
259 		if (strcmp(target_hostname, b->host) == 0) {
260 			target_hostname = NULL;
261 		}
262 	}
263 
264 	if (b->endpoint) {
265 		option_section = true;
266 	} else if (target_hostname) {
267 		option_section = true;
268 	} else if (b->target_principal) {
269 		option_section = true;
270 	} else if (b->assoc_group_id != 0) {
271 		option_section = true;
272 	} else if (b->options) {
273 		option_section = true;
274 	} else if (b->flags) {
275 		option_section = true;
276 	}
277 
278 	if (!option_section) {
279 		return s;
280 	}
281 
282 	o = s;
283 	s = talloc_asprintf_append_buffer(s, "[");
284 	if (s == NULL) {
285 		talloc_free(o);
286 		return NULL;
287 	}
288 
289 	if (b->endpoint) {
290 		o = s;
291 		s = talloc_asprintf_append_buffer(s, "%s", b->endpoint);
292 		if (s == NULL) {
293 			talloc_free(o);
294 			return NULL;
295 		}
296 	}
297 
298 	for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
299 		if (!(b->flags & ncacn_options[i].flag)) {
300 			continue;
301 		}
302 
303 		o = s;
304 		s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
305 		if (s == NULL) {
306 			talloc_free(o);
307 			return NULL;
308 		}
309 	}
310 
311 	if (target_hostname) {
312 		o = s;
313 		s = talloc_asprintf_append_buffer(s, ",target_hostname=%s",
314 						  b->target_hostname);
315 		if (s == NULL) {
316 			talloc_free(o);
317 			return NULL;
318 		}
319 	}
320 
321 	if (b->target_principal) {
322 		o = s;
323 		s = talloc_asprintf_append_buffer(s, ",target_principal=%s",
324 						  b->target_principal);
325 		if (s == NULL) {
326 			talloc_free(o);
327 			return NULL;
328 		}
329 	}
330 
331 	if (b->assoc_group_id != 0) {
332 		o = s;
333 		s = talloc_asprintf_append_buffer(s, ",assoc_group_id=0x%08x",
334 						  b->assoc_group_id);
335 		if (s == NULL) {
336 			talloc_free(o);
337 			return NULL;
338 		}
339 	}
340 
341 	for (i=0;b->options && b->options[i];i++) {
342 		o = s;
343 		s = talloc_asprintf_append_buffer(s, ",%s", b->options[i]);
344 		if (s == NULL) {
345 			talloc_free(o);
346 			return NULL;
347 		}
348 	}
349 
350 	o = s;
351 	s = talloc_asprintf_append_buffer(s, "]");
352 	if (s == NULL) {
353 		talloc_free(o);
354 		return NULL;
355 	}
356 
357 	return s;
358 }
359 
360 /*
361   parse a binding string into a dcerpc_binding structure
362 */
dcerpc_parse_binding(TALLOC_CTX * mem_ctx,const char * _s,struct dcerpc_binding ** b_out)363 _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
364 {
365 	char *_t;
366 	struct dcerpc_binding *b;
367 	char *s;
368 	char *options = NULL;
369 	char *p;
370 	size_t i;
371 	NTSTATUS status;
372 
373 	b = talloc_zero(mem_ctx, struct dcerpc_binding);
374 	if (!b) {
375 		return NT_STATUS_NO_MEMORY;
376 	}
377 
378 	_t = talloc_strdup(b, _s);
379 	if (_t == NULL) {
380 		talloc_free(b);
381 		return NT_STATUS_NO_MEMORY;
382 	}
383 
384 	s = _t;
385 
386 	p = strchr(s, '[');
387 	if (p) {
388 		*p = '\0';
389 		options = p + 1;
390 		if (options[strlen(options)-1] != ']') {
391 			talloc_free(b);
392 			return NT_STATUS_INVALID_PARAMETER_MIX;
393 		}
394 		options[strlen(options)-1] = 0;
395 	}
396 
397 	p = strchr(s, '@');
398 
399 	if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
400 		*p = '\0';
401 
402 		status = dcerpc_binding_set_string_option(b, "object", s);
403 		if (!NT_STATUS_IS_OK(status)) {
404 			talloc_free(b);
405 			return status;
406 		}
407 
408 		s = p + 1;
409 	}
410 
411 	p = strchr(s, ':');
412 
413 	if (p == NULL) {
414 		b->transport = NCA_UNKNOWN;
415 	} else if (is_ipaddress_v6(s)) {
416 		b->transport = NCA_UNKNOWN;
417 	} else {
418 		*p = '\0';
419 
420 		status = dcerpc_binding_set_string_option(b, "transport", s);
421 		if (!NT_STATUS_IS_OK(status)) {
422 			talloc_free(b);
423 			return status;
424 		}
425 
426 		s = p + 1;
427 	}
428 
429 	if (strlen(s) > 0) {
430 		status = dcerpc_binding_set_string_option(b, "host", s);
431 		if (!NT_STATUS_IS_OK(status)) {
432 			talloc_free(b);
433 			return status;
434 		}
435 
436 		b->target_hostname = talloc_strdup(b, b->host);
437 		if (b->target_hostname == NULL) {
438 			talloc_free(b);
439 			return NT_STATUS_NO_MEMORY;
440 		}
441 	}
442 
443 	for (i=0; options != NULL; i++) {
444 		const char *name = options;
445 		const char *value = NULL;
446 
447 		p = strchr(options, ',');
448 		if (p != NULL) {
449 			*p = '\0';
450 			options = p+1;
451 		} else {
452 			options = NULL;
453 		}
454 
455 		p = strchr(name, '=');
456 		if (p != NULL) {
457 			*p = '\0';
458 			value = p + 1;
459 		}
460 
461 		if (value == NULL) {
462 			/*
463 			 * If it's not a key=value pair
464 			 * it might be a ncacn_option
465 			 * or if it's the first option
466 			 * it's the endpoint.
467 			 */
468 			const struct ncacn_option *no = NULL;
469 
470 			value = name;
471 
472 			no = ncacn_option_by_name(name);
473 			if (no == NULL) {
474 				if (i > 0) {
475 					/*
476 					 * we don't allow unknown options
477 					 */
478 					return NT_STATUS_INVALID_PARAMETER_MIX;
479 				}
480 
481 				/*
482 				 * This is the endpoint
483 				 */
484 				name = "endpoint";
485 				if (strlen(value) == 0) {
486 					value = NULL;
487 				}
488 			}
489 		}
490 
491 		status = dcerpc_binding_set_string_option(b, name, value);
492 		if (!NT_STATUS_IS_OK(status)) {
493 			talloc_free(b);
494 			return status;
495 		}
496 	}
497 
498 	talloc_free(_t);
499 	*b_out = b;
500 	return NT_STATUS_OK;
501 }
502 
dcerpc_binding_get_object(const struct dcerpc_binding * b)503 _PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
504 {
505 	return b->object;
506 }
507 
dcerpc_binding_set_object(struct dcerpc_binding * b,struct GUID object)508 _PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
509 					    struct GUID object)
510 {
511 	char *tmp = discard_const_p(char, b->object_string);
512 
513 	if (GUID_all_zero(&object)) {
514 		talloc_free(tmp);
515 		b->object_string = NULL;
516 		ZERO_STRUCT(b->object);
517 		return NT_STATUS_OK;
518 	}
519 
520 	b->object_string = GUID_string(b, &object);
521 	if (b->object_string == NULL) {
522 		b->object_string = tmp;
523 		return NT_STATUS_NO_MEMORY;
524 	}
525 	talloc_free(tmp);
526 
527 	b->object = object;
528 	return NT_STATUS_OK;
529 }
530 
dcerpc_binding_get_transport(const struct dcerpc_binding * b)531 _PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
532 {
533 	return b->transport;
534 }
535 
dcerpc_binding_set_transport(struct dcerpc_binding * b,enum dcerpc_transport_t transport)536 _PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
537 					       enum dcerpc_transport_t transport)
538 {
539 	NTSTATUS status;
540 
541 	/*
542 	 * TODO: we may want to check the transport value is
543 	 * wellknown.
544 	 */
545 	if (b->transport == transport) {
546 		return NT_STATUS_OK;
547 	}
548 
549 	/*
550 	 * This implicitly resets the endpoint
551 	 * as the endpoint is transport specific.
552 	 *
553 	 * It also resets the assoc group as it's
554 	 * also endpoint specific.
555 	 *
556 	 * TODO: in future we may reset more options
557 	 * here.
558 	 */
559 	status = dcerpc_binding_set_string_option(b, "endpoint", NULL);
560 	if (!NT_STATUS_IS_OK(status)) {
561 		return status;
562 	}
563 
564 	b->assoc_group_id = 0;
565 
566 	b->transport = transport;
567 	return NT_STATUS_OK;
568 }
569 
dcerpc_binding_get_auth_info(const struct dcerpc_binding * b,enum dcerpc_AuthType * _auth_type,enum dcerpc_AuthLevel * _auth_level)570 _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
571 					   enum dcerpc_AuthType *_auth_type,
572 					   enum dcerpc_AuthLevel *_auth_level)
573 {
574 	enum dcerpc_AuthType auth_type;
575 	enum dcerpc_AuthLevel auth_level;
576 
577 	if (b->flags & DCERPC_AUTH_SPNEGO) {
578 		auth_type = DCERPC_AUTH_TYPE_SPNEGO;
579 	} else if (b->flags & DCERPC_AUTH_KRB5) {
580 		auth_type = DCERPC_AUTH_TYPE_KRB5;
581 	} else if (b->flags & DCERPC_SCHANNEL) {
582 		auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
583 	} else if (b->flags & DCERPC_AUTH_NTLM) {
584 		auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
585 	} else {
586 		auth_type = DCERPC_AUTH_TYPE_NONE;
587 	}
588 
589 	if (b->flags & DCERPC_SEAL) {
590 		auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
591 	} else if (b->flags & DCERPC_SIGN) {
592 		auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
593 	} else if (b->flags & DCERPC_CONNECT) {
594 		auth_level = DCERPC_AUTH_LEVEL_CONNECT;
595 	} else if (b->flags & DCERPC_PACKET) {
596 		auth_level = DCERPC_AUTH_LEVEL_PACKET;
597 	} else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
598 		auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
599 	} else {
600 		auth_level = DCERPC_AUTH_LEVEL_NONE;
601 	}
602 
603 	if (_auth_type != NULL) {
604 		*_auth_type = auth_type;
605 	}
606 
607 	if (_auth_level != NULL) {
608 		*_auth_level = auth_level;
609 	}
610 }
611 
dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding * b)612 _PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
613 {
614 	return b->assoc_group_id;
615 }
616 
dcerpc_binding_set_assoc_group_id(struct dcerpc_binding * b,uint32_t assoc_group_id)617 _PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
618 						    uint32_t assoc_group_id)
619 {
620 	b->assoc_group_id = assoc_group_id;
621 	return NT_STATUS_OK;
622 }
623 
dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding * b)624 _PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
625 {
626 	const char *s = dcerpc_binding_get_string_option(b, "abstract_syntax");
627 	bool ok;
628 	struct ndr_syntax_id id;
629 
630 	if (s == NULL) {
631 		return ndr_syntax_id_null;
632 	}
633 
634 	ok = ndr_syntax_id_from_string(s, &id);
635 	if (!ok) {
636 		return ndr_syntax_id_null;
637 	}
638 
639 	return id;
640 }
641 
dcerpc_binding_set_abstract_syntax(struct dcerpc_binding * b,const struct ndr_syntax_id * syntax)642 _PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
643 						     const struct ndr_syntax_id *syntax)
644 {
645 	NTSTATUS status;
646 	char *s = NULL;
647 
648 	if (syntax == NULL) {
649 		status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
650 		if (!NT_STATUS_IS_OK(status)) {
651 			return status;
652 		}
653 
654 		return NT_STATUS_OK;
655 	}
656 
657 	if (ndr_syntax_id_equal(&ndr_syntax_id_null, syntax)) {
658 		status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
659 		if (!NT_STATUS_IS_OK(status)) {
660 			return status;
661 		}
662 
663 		return NT_STATUS_OK;
664 	}
665 
666 	s = ndr_syntax_id_to_string(b, syntax);
667 	if (s == NULL) {
668 		return NT_STATUS_NO_MEMORY;
669 	}
670 
671 	status = dcerpc_binding_set_string_option(b, "abstract_syntax", s);
672 	TALLOC_FREE(s);
673 	if (!NT_STATUS_IS_OK(status)) {
674 		return status;
675 	}
676 
677 	return NT_STATUS_OK;
678 }
679 
dcerpc_binding_get_string_option(const struct dcerpc_binding * b,const char * name)680 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
681 						      const char *name)
682 {
683 	struct {
684 		const char *name;
685 		const char *value;
686 #define _SPECIAL(x) { .name = #x, .value = b->x, }
687 	} specials[] = {
688 		{ .name = "object", .value = b->object_string, },
689 		_SPECIAL(host),
690 		_SPECIAL(endpoint),
691 		_SPECIAL(target_hostname),
692 		_SPECIAL(target_principal),
693 #undef _SPECIAL
694 	};
695 	const struct ncacn_option *no = NULL;
696 	size_t name_len = strlen(name);
697 	size_t i;
698 	int ret;
699 
700 	ret = strcmp(name, "transport");
701 	if (ret == 0) {
702 		return derpc_transport_string_by_transport(b->transport);
703 	}
704 
705 	ret = strcmp(name, "assoc_group_id");
706 	if (ret == 0) {
707 		char *tmp = discard_const_p(char, b->assoc_group_string);
708 
709 		if (b->assoc_group_id == 0) {
710 			return NULL;
711 		}
712 
713 		snprintf(tmp, sizeof(b->assoc_group_string),
714 			 "0x%08x", b->assoc_group_id);
715 		return (const char *)b->assoc_group_string;
716 	}
717 
718 	for (i=0; i < ARRAY_SIZE(specials); i++) {
719 		ret = strcmp(specials[i].name, name);
720 		if (ret != 0) {
721 			continue;
722 		}
723 
724 		return specials[i].value;
725 	}
726 
727 	no = ncacn_option_by_name(name);
728 	if (no != NULL) {
729 		if (b->flags & no->flag) {
730 			return no->name;
731 		}
732 
733 		return NULL;
734 	}
735 
736 	if (b->options == NULL) {
737 		return NULL;
738 	}
739 
740 	for (i=0; b->options[i]; i++) {
741 		const char *o = b->options[i];
742 		const char *vs = NULL;
743 
744 		ret = strncmp(name, o, name_len);
745 		if (ret != 0) {
746 			continue;
747 		}
748 
749 		if (o[name_len] != '=') {
750 			continue;
751 		}
752 
753 		vs = &o[name_len + 1];
754 
755 		return vs;
756 	}
757 
758 	return NULL;
759 }
760 
dcerpc_binding_copy_string_option(TALLOC_CTX * mem_ctx,const struct dcerpc_binding * b,const char * name)761 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
762 						 const struct dcerpc_binding *b,
763 						 const char *name)
764 {
765 	const char *c = dcerpc_binding_get_string_option(b, name);
766 	char *v;
767 
768 	if (c == NULL) {
769 		errno = ENOENT;
770 		return NULL;
771 	}
772 
773 	v = talloc_strdup(mem_ctx, c);
774 	if (v == NULL) {
775 		errno = ENOMEM;
776 		return NULL;
777 	}
778 
779 	return v;
780 }
781 
dcerpc_binding_set_string_option(struct dcerpc_binding * b,const char * name,const char * value)782 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
783 						   const char *name,
784 						   const char *value)
785 {
786 	struct {
787 		const char *name;
788 		const char **ptr;
789 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
790 	} specials[] = {
791 		_SPECIAL(host),
792 		_SPECIAL(endpoint),
793 		_SPECIAL(target_hostname),
794 		_SPECIAL(target_principal),
795 #undef _SPECIAL
796 	};
797 	const struct ncacn_option *no = NULL;
798 	size_t name_len = strlen(name);
799 	const char *opt = NULL;
800 	char *tmp;
801 	size_t i;
802 	int ret;
803 
804 	/*
805 	 * Note: value == NULL, means delete it.
806 	 * value != NULL means add or reset.
807 	 */
808 
809 	ret = strcmp(name, "transport");
810 	if (ret == 0) {
811 		enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
812 
813 		if (t == NCA_UNKNOWN && value != NULL) {
814 			return NT_STATUS_INVALID_PARAMETER_MIX;
815 		}
816 
817 		return dcerpc_binding_set_transport(b, t);
818 	}
819 
820 	ret = strcmp(name, "object");
821 	if (ret == 0) {
822 		NTSTATUS status;
823 		struct GUID uuid = GUID_zero();
824 
825 		if (value != NULL) {
826 			DATA_BLOB blob;
827 			blob = data_blob_string_const(value);
828 			if (blob.length != 36) {
829 				return NT_STATUS_INVALID_PARAMETER_MIX;
830 			}
831 
832 			status = GUID_from_data_blob(&blob, &uuid);
833 			if (!NT_STATUS_IS_OK(status)) {
834 				return status;
835 			}
836 		}
837 
838 		return dcerpc_binding_set_object(b, uuid);
839 	}
840 
841 	ret = strcmp(name, "assoc_group_id");
842 	if (ret == 0) {
843 		uint32_t assoc_group_id = 0;
844 
845 		if (value != NULL) {
846 			char c;
847 
848 			ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
849 			if (ret != 1) {
850 				return NT_STATUS_INVALID_PARAMETER_MIX;
851 			}
852 		}
853 
854 		return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
855 	}
856 
857 	for (i=0; i < ARRAY_SIZE(specials); i++) {
858 		ret = strcmp(specials[i].name, name);
859 		if (ret != 0) {
860 			continue;
861 		}
862 
863 		tmp = discard_const_p(char, *specials[i].ptr);
864 
865 		if (value == NULL) {
866 			talloc_free(tmp);
867 			*specials[i].ptr = NULL;
868 			return NT_STATUS_OK;
869 		}
870 
871 		if (value[0] == '\0') {
872 			return NT_STATUS_INVALID_PARAMETER_MIX;
873 		}
874 
875 		*specials[i].ptr = talloc_strdup(b, value);
876 		if (*specials[i].ptr == NULL) {
877 			*specials[i].ptr = tmp;
878 			return NT_STATUS_NO_MEMORY;
879 		}
880 		talloc_free(tmp);
881 
882 		return NT_STATUS_OK;
883 	}
884 
885 	no = ncacn_option_by_name(name);
886 	if (no != NULL) {
887 		if (value == NULL) {
888 			b->flags &= ~no->flag;
889 			return NT_STATUS_OK;
890 		}
891 
892 		ret = strcasecmp(no->name, value);
893 		if (ret != 0) {
894 			return NT_STATUS_INVALID_PARAMETER_MIX;
895 		}
896 
897 		b->flags |= no->flag;
898 		return NT_STATUS_OK;
899 	}
900 
901 	for (i=0; b->options && b->options[i]; i++) {
902 		const char *o = b->options[i];
903 
904 		ret = strncmp(name, o, name_len);
905 		if (ret != 0) {
906 			continue;
907 		}
908 
909 		if (o[name_len] != '=') {
910 			continue;
911 		}
912 
913 		opt = o;
914 		break;
915 	}
916 
917 	if (opt == NULL) {
918 		const char **n;
919 
920 		if (value == NULL) {
921 			return NT_STATUS_OK;
922 		}
923 
924 		n = talloc_realloc(b, b->options, const char *, i + 2);
925 		if (n == NULL) {
926 			return NT_STATUS_NO_MEMORY;
927 		}
928 		n[i] = NULL;
929 		n[i + 1] = NULL;
930 		b->options = n;
931 	}
932 
933 	tmp = discard_const_p(char, opt);
934 
935 	if (value == NULL) {
936 		for (;b->options[i];i++) {
937 			b->options[i] = b->options[i+1];
938 		}
939 		talloc_free(tmp);
940 		return NT_STATUS_OK;
941 	}
942 
943 	b->options[i] = talloc_asprintf(b->options, "%s=%s",
944 					name, value);
945 	if (b->options[i] == NULL) {
946 		b->options[i] = tmp;
947 		return NT_STATUS_NO_MEMORY;
948 	}
949 
950 	return NT_STATUS_OK;
951 }
952 
dcerpc_binding_get_flags(const struct dcerpc_binding * b)953 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
954 {
955 	return b->flags;
956 }
957 
dcerpc_binding_set_flags(struct dcerpc_binding * b,uint32_t additional,uint32_t clear)958 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
959 					   uint32_t additional,
960 					   uint32_t clear)
961 {
962 	/*
963 	 * TODO: in future we may want to reject invalid combinations
964 	 */
965 	b->flags &= ~clear;
966 	b->flags |= additional;
967 
968 	return NT_STATUS_OK;
969 }
970 
dcerpc_floor_get_lhs_data(const struct epm_floor * epm_floor,struct ndr_syntax_id * syntax)971 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
972 					    struct ndr_syntax_id *syntax)
973 {
974 	TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
975 	struct ndr_pull *ndr;
976 	enum ndr_err_code ndr_err;
977 	uint16_t if_version=0;
978 
979 	ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
980 	if (ndr == NULL) {
981 		talloc_free(mem_ctx);
982 		return NT_STATUS_NO_MEMORY;
983 	}
984 	ndr->flags |= LIBNDR_FLAG_NOALIGN;
985 
986 	ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
987 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
988 		talloc_free(mem_ctx);
989 		return ndr_map_error2ntstatus(ndr_err);
990 	}
991 
992 	ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
993 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
994 		talloc_free(mem_ctx);
995 		return ndr_map_error2ntstatus(ndr_err);
996 	}
997 
998 	syntax->if_version = if_version;
999 
1000 	talloc_free(mem_ctx);
1001 
1002 	return NT_STATUS_OK;
1003 }
1004 
dcerpc_floor_pack_lhs_data(TALLOC_CTX * mem_ctx,const struct ndr_syntax_id * syntax)1005 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
1006 {
1007 	DATA_BLOB blob;
1008 	enum ndr_err_code ndr_err;
1009 	struct ndr_push *ndr;
1010 
1011 	ndr = ndr_push_init_ctx(mem_ctx);
1012 	if (ndr == NULL) {
1013 		return data_blob_null;
1014 	}
1015 
1016 	ndr->flags |= LIBNDR_FLAG_NOALIGN;
1017 
1018 	ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
1019 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1020 		return data_blob_null;
1021 	}
1022 	ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
1023 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1024 		return data_blob_null;
1025 	}
1026 
1027 	blob = ndr_push_blob(ndr);
1028 	talloc_steal(mem_ctx, blob.data);
1029 	talloc_free(ndr);
1030 	return blob;
1031 }
1032 
dcerpc_floor_pack_rhs_if_version_data(TALLOC_CTX * mem_ctx,const struct ndr_syntax_id * syntax,DATA_BLOB * pblob)1033 static bool dcerpc_floor_pack_rhs_if_version_data(
1034 	TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
1035 	DATA_BLOB *pblob)
1036 {
1037 	DATA_BLOB blob;
1038 	struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
1039 	enum ndr_err_code ndr_err;
1040 
1041 	if (ndr == NULL) {
1042 		return false;
1043 	}
1044 
1045 	ndr->flags |= LIBNDR_FLAG_NOALIGN;
1046 
1047 	ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
1048 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1049 		return false;
1050 	}
1051 
1052 	blob = ndr_push_blob(ndr);
1053 	talloc_steal(mem_ctx, blob.data);
1054 	talloc_free(ndr);
1055 	*pblob = blob;
1056 	return true;
1057 }
1058 
dcerpc_floor_get_rhs_data(TALLOC_CTX * mem_ctx,struct epm_floor * epm_floor)1059 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
1060 {
1061 	switch (epm_floor->lhs.protocol) {
1062 	case EPM_PROTOCOL_TCP:
1063 		if (epm_floor->rhs.tcp.port == 0) return NULL;
1064 		return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
1065 
1066 	case EPM_PROTOCOL_UDP:
1067 		if (epm_floor->rhs.udp.port == 0) return NULL;
1068 		return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
1069 
1070 	case EPM_PROTOCOL_HTTP:
1071 		if (epm_floor->rhs.http.port == 0) return NULL;
1072 		return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
1073 
1074 	case EPM_PROTOCOL_IP:
1075 		return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
1076 
1077 	case EPM_PROTOCOL_NCACN:
1078 		return NULL;
1079 
1080 	case EPM_PROTOCOL_NCADG:
1081 		return NULL;
1082 
1083 	case EPM_PROTOCOL_SMB:
1084 		if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
1085 		return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
1086 
1087 	case EPM_PROTOCOL_NAMED_PIPE:
1088 		if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
1089 		return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
1090 
1091 	case EPM_PROTOCOL_NETBIOS:
1092 		if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
1093 		return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
1094 
1095 	case EPM_PROTOCOL_NCALRPC:
1096 		return NULL;
1097 
1098 	case EPM_PROTOCOL_VINES_SPP:
1099 		return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
1100 
1101 	case EPM_PROTOCOL_VINES_IPC:
1102 		return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
1103 
1104 	case EPM_PROTOCOL_STREETTALK:
1105 		return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
1106 
1107 	case EPM_PROTOCOL_UNIX_DS:
1108 		if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
1109 		return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
1110 
1111 	case EPM_PROTOCOL_NULL:
1112 		return NULL;
1113 
1114 	default:
1115 		DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1116 		break;
1117 	}
1118 
1119 	return NULL;
1120 }
1121 
dcerpc_floor_set_rhs_data(TALLOC_CTX * mem_ctx,struct epm_floor * epm_floor,const char * data)1122 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx,
1123 					  struct epm_floor *epm_floor,
1124 					  const char *data)
1125 {
1126 	if (data == NULL) {
1127 		data = "";
1128 	}
1129 
1130 	switch (epm_floor->lhs.protocol) {
1131 	case EPM_PROTOCOL_TCP:
1132 		epm_floor->rhs.tcp.port = atoi(data);
1133 		return NT_STATUS_OK;
1134 
1135 	case EPM_PROTOCOL_UDP:
1136 		epm_floor->rhs.udp.port = atoi(data);
1137 		return NT_STATUS_OK;
1138 
1139 	case EPM_PROTOCOL_HTTP:
1140 		epm_floor->rhs.http.port = atoi(data);
1141 		return NT_STATUS_OK;
1142 
1143 	case EPM_PROTOCOL_IP:
1144 		if (!is_ipaddress_v4(data)) {
1145 			data = "0.0.0.0";
1146 		}
1147 		epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
1148 		NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
1149 		return NT_STATUS_OK;
1150 
1151 	case EPM_PROTOCOL_NCACN:
1152 		epm_floor->rhs.ncacn.minor_version = 0;
1153 		return NT_STATUS_OK;
1154 
1155 	case EPM_PROTOCOL_NCADG:
1156 		epm_floor->rhs.ncadg.minor_version = 0;
1157 		return NT_STATUS_OK;
1158 
1159 	case EPM_PROTOCOL_SMB:
1160 		epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
1161 		NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
1162 		return NT_STATUS_OK;
1163 
1164 	case EPM_PROTOCOL_NAMED_PIPE:
1165 		epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
1166 		NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
1167 		return NT_STATUS_OK;
1168 
1169 	case EPM_PROTOCOL_NETBIOS:
1170 		epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
1171 		NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
1172 		return NT_STATUS_OK;
1173 
1174 	case EPM_PROTOCOL_NCALRPC:
1175 		return NT_STATUS_OK;
1176 
1177 	case EPM_PROTOCOL_VINES_SPP:
1178 		epm_floor->rhs.vines_spp.port = atoi(data);
1179 		return NT_STATUS_OK;
1180 
1181 	case EPM_PROTOCOL_VINES_IPC:
1182 		epm_floor->rhs.vines_ipc.port = atoi(data);
1183 		return NT_STATUS_OK;
1184 
1185 	case EPM_PROTOCOL_STREETTALK:
1186 		epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
1187 		NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
1188 		return NT_STATUS_OK;
1189 
1190 	case EPM_PROTOCOL_UNIX_DS:
1191 		epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
1192 		NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
1193 		return NT_STATUS_OK;
1194 
1195 	case EPM_PROTOCOL_NULL:
1196 		return NT_STATUS_OK;
1197 
1198 	default:
1199 		DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1200 		break;
1201 	}
1202 
1203 	return NT_STATUS_NOT_SUPPORTED;
1204 }
1205 
dcerpc_transport_by_endpoint_protocol(int prot)1206 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
1207 {
1208 	int i;
1209 
1210 	/* Find a transport that has 'prot' as 4th protocol */
1211 	for (i=0;i<ARRAY_SIZE(transports);i++) {
1212 		if (transports[i].num_protocols >= 2 &&
1213 			transports[i].protseq[1] == prot) {
1214 			return transports[i].transport;
1215 		}
1216 	}
1217 
1218 	/* Unknown transport */
1219 	return (unsigned int)-1;
1220 }
1221 
dcerpc_transport_by_tower(const struct epm_tower * tower)1222 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1223 {
1224 	int i;
1225 
1226 	/* Find a transport that matches this tower */
1227 	for (i=0;i<ARRAY_SIZE(transports);i++) {
1228 		int j;
1229 		if (transports[i].num_protocols != tower->num_floors - 2) {
1230 			continue;
1231 		}
1232 
1233 		for (j = 0; j < transports[i].num_protocols && j < MAX_PROTSEQ; j++) {
1234 			if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
1235 				break;
1236 			}
1237 		}
1238 
1239 		if (j == transports[i].num_protocols) {
1240 			return transports[i].transport;
1241 		}
1242 	}
1243 
1244 	/* Unknown transport */
1245 	return (unsigned int)-1;
1246 }
1247 
derpc_transport_string_by_transport(enum dcerpc_transport_t t)1248 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1249 {
1250 	int i;
1251 
1252 	for (i=0; i<ARRAY_SIZE(transports); i++) {
1253 		if (t == transports[i].transport) {
1254 			return transports[i].name;
1255 		}
1256 	}
1257 	return NULL;
1258 }
1259 
dcerpc_transport_by_name(const char * name)1260 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1261 {
1262 	size_t i;
1263 
1264 	if (name == NULL) {
1265 		return NCA_UNKNOWN;
1266 	}
1267 
1268 	for (i=0; i<ARRAY_SIZE(transports);i++) {
1269 		if (strcasecmp(name, transports[i].name) == 0) {
1270 			return transports[i].transport;
1271 		}
1272 	}
1273 
1274 	return NCA_UNKNOWN;
1275 }
1276 
dcerpc_binding_from_tower(TALLOC_CTX * mem_ctx,struct epm_tower * tower,struct dcerpc_binding ** b_out)1277 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1278 					    struct epm_tower *tower,
1279 					    struct dcerpc_binding **b_out)
1280 {
1281 	NTSTATUS status;
1282 	struct dcerpc_binding *b;
1283 	enum dcerpc_transport_t transport;
1284 	struct ndr_syntax_id abstract_syntax;
1285 	char *endpoint = NULL;
1286 	char *host = NULL;
1287 
1288 	/*
1289 	 * A tower needs to have at least 4 floors to carry useful
1290 	 * information. Floor 3 is the transport identifier which defines
1291 	 * how many floors are required at least.
1292 	 */
1293 	if (tower->num_floors < 4) {
1294 		return NT_STATUS_INVALID_PARAMETER;
1295 	}
1296 
1297 	status = dcerpc_parse_binding(mem_ctx, "", &b);
1298 	if (!NT_STATUS_IS_OK(status)) {
1299 		return status;
1300 	}
1301 
1302 	transport = dcerpc_transport_by_tower(tower);
1303 	if (transport == NCA_UNKNOWN) {
1304 		talloc_free(b);
1305 		return NT_STATUS_NOT_SUPPORTED;
1306 	}
1307 
1308 	status = dcerpc_binding_set_transport(b, transport);
1309 	if (!NT_STATUS_IS_OK(status)) {
1310 		talloc_free(b);
1311 		return status;
1312 	}
1313 
1314 	/* Set abstract syntax */
1315 	status = dcerpc_floor_get_lhs_data(&tower->floors[0], &abstract_syntax);
1316 	if (!NT_STATUS_IS_OK(status)) {
1317 		talloc_free(b);
1318 		return status;
1319 	}
1320 
1321 	status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
1322 	if (!NT_STATUS_IS_OK(status)) {
1323 		talloc_free(b);
1324 		return status;
1325 	}
1326 
1327 	/* Ignore floor 1, it contains the NDR version info */
1328 
1329 	/* Set endpoint */
1330 	errno = 0;
1331 	if (tower->num_floors >= 4) {
1332 		endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
1333 	}
1334 	if (errno != 0) {
1335 		int saved_errno = errno;
1336 		talloc_free(b);
1337 		return map_nt_error_from_unix_common(saved_errno);
1338 	}
1339 
1340 	status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
1341 	if (!NT_STATUS_IS_OK(status)) {
1342 		talloc_free(b);
1343 		return status;
1344 	}
1345 	TALLOC_FREE(endpoint);
1346 
1347 	/* Set network address */
1348 	errno = 0;
1349 	if (tower->num_floors >= 5) {
1350 		host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
1351 	}
1352 	if (errno != 0) {
1353 		int saved_errno = errno;
1354 		talloc_free(b);
1355 		return map_nt_error_from_unix_common(saved_errno);
1356 	}
1357 
1358 	status = dcerpc_binding_set_string_option(b, "host", host);
1359 	if (!NT_STATUS_IS_OK(status)) {
1360 		talloc_free(b);
1361 		return status;
1362 	}
1363 	status = dcerpc_binding_set_string_option(b, "target_hostname", host);
1364 	if (!NT_STATUS_IS_OK(status)) {
1365 		talloc_free(b);
1366 		return status;
1367 	}
1368 	TALLOC_FREE(host);
1369 
1370 	*b_out = b;
1371 	return NT_STATUS_OK;
1372 }
1373 
dcerpc_binding_dup(TALLOC_CTX * mem_ctx,const struct dcerpc_binding * b)1374 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1375 						   const struct dcerpc_binding *b)
1376 {
1377 	struct dcerpc_binding *n;
1378 	uint32_t count;
1379 
1380 	n = talloc_zero(mem_ctx, struct dcerpc_binding);
1381 	if (n == NULL) {
1382 		return NULL;
1383 	}
1384 
1385 	n->transport = b->transport;
1386 	n->object = b->object;
1387 	n->flags = b->flags;
1388 	n->assoc_group_id = b->assoc_group_id;
1389 
1390 	if (b->object_string != NULL) {
1391 		n->object_string = talloc_strdup(n, b->object_string);
1392 		if (n->object_string == NULL) {
1393 			talloc_free(n);
1394 			return NULL;
1395 		}
1396 	}
1397 	if (b->host != NULL) {
1398 		n->host = talloc_strdup(n, b->host);
1399 		if (n->host == NULL) {
1400 			talloc_free(n);
1401 			return NULL;
1402 		}
1403 	}
1404 
1405 	if (b->target_hostname != NULL) {
1406 		n->target_hostname = talloc_strdup(n, b->target_hostname);
1407 		if (n->target_hostname == NULL) {
1408 			talloc_free(n);
1409 			return NULL;
1410 		}
1411 	}
1412 
1413 	if (b->target_principal != NULL) {
1414 		n->target_principal = talloc_strdup(n, b->target_principal);
1415 		if (n->target_principal == NULL) {
1416 			talloc_free(n);
1417 			return NULL;
1418 		}
1419 	}
1420 
1421 	if (b->endpoint != NULL) {
1422 		n->endpoint = talloc_strdup(n, b->endpoint);
1423 		if (n->endpoint == NULL) {
1424 			talloc_free(n);
1425 			return NULL;
1426 		}
1427 	}
1428 
1429 	for (count = 0; b->options && b->options[count]; count++);
1430 
1431 	if (count > 0) {
1432 		uint32_t i;
1433 
1434 		n->options = talloc_array(n, const char *, count + 1);
1435 		if (n->options == NULL) {
1436 			talloc_free(n);
1437 			return NULL;
1438 		}
1439 
1440 		for (i = 0; i < count; i++) {
1441 			n->options[i] = talloc_strdup(n->options, b->options[i]);
1442 			if (n->options[i] == NULL) {
1443 				talloc_free(n);
1444 				return NULL;
1445 			}
1446 		}
1447 		n->options[count] = NULL;
1448 	}
1449 
1450 	return n;
1451 }
1452 
dcerpc_binding_build_tower(TALLOC_CTX * mem_ctx,const struct dcerpc_binding * binding,struct epm_tower * tower)1453 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1454 					     const struct dcerpc_binding *binding,
1455 					     struct epm_tower *tower)
1456 {
1457 	const enum epm_protocol *protseq = NULL;
1458 	int num_protocols = -1, i;
1459 	struct ndr_syntax_id abstract_syntax;
1460 	NTSTATUS status;
1461 
1462 	/* Find transport */
1463 	for (i=0;i<ARRAY_SIZE(transports);i++) {
1464 		if (transports[i].transport == binding->transport) {
1465 			protseq = transports[i].protseq;
1466 			num_protocols = transports[i].num_protocols;
1467 			break;
1468 		}
1469 	}
1470 
1471 	if (num_protocols == -1) {
1472 		DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1473 		return NT_STATUS_UNSUCCESSFUL;
1474 	}
1475 
1476 	tower->num_floors = 2 + num_protocols;
1477 	tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1478 
1479 	/* Floor 0 */
1480 	tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
1481 
1482 	abstract_syntax = dcerpc_binding_get_abstract_syntax(binding);
1483 	tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1484 								   &abstract_syntax);
1485 
1486 	if (!dcerpc_floor_pack_rhs_if_version_data(
1487 		    tower->floors, &abstract_syntax,
1488 		    &tower->floors[0].rhs.uuid.unknown)) {
1489 		return NT_STATUS_NO_MEMORY;
1490 	}
1491 
1492 	/* Floor 1 */
1493 	tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1494 
1495 	tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1496 								&ndr_transfer_syntax_ndr);
1497 
1498 	tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
1499 
1500 	/* Floor 2 to num_protocols */
1501 	for (i = 0; i < num_protocols; i++) {
1502 		tower->floors[2 + i].lhs.protocol = protseq[i];
1503 		tower->floors[2 + i].lhs.lhs_data = data_blob_null;
1504 		ZERO_STRUCT(tower->floors[2 + i].rhs);
1505 		status = dcerpc_floor_set_rhs_data(tower->floors,
1506 						   &tower->floors[2 + i],
1507 						   NULL);
1508 		if (!NT_STATUS_IS_OK(status)) {
1509 			return status;
1510 		}
1511 	}
1512 
1513 	/* The 4th floor contains the endpoint */
1514 	if (num_protocols >= 2 && binding->endpoint) {
1515 		status = dcerpc_floor_set_rhs_data(tower->floors,
1516 						   &tower->floors[3],
1517 						   binding->endpoint);
1518 		if (!NT_STATUS_IS_OK(status)) {
1519 			return status;
1520 		}
1521 	}
1522 
1523 	/* The 5th contains the network address */
1524 	if (num_protocols >= 3 && binding->host) {
1525 		status = dcerpc_floor_set_rhs_data(tower->floors,
1526 						   &tower->floors[4],
1527 						   binding->host);
1528 		if (!NT_STATUS_IS_OK(status)) {
1529 			return status;
1530 		}
1531 	}
1532 
1533 	return NT_STATUS_OK;
1534 }
1535