pthreadpool: Add test for fork crash
[Samba.git] / librpc / rpc / binding.c
blob4ee1c6260debb67d5e8f216f2238ac5e29539afe
1 /*
2 Unix SMB/CIFS implementation.
4 dcerpc utility functions
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
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.
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.
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/>.
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"
33 #undef strcasecmp
34 #undef strncasecmp
36 #define MAX_PROTSEQ 10
38 struct dcerpc_binding {
39 enum dcerpc_transport_t transport;
40 struct ndr_syntax_id 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' */
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 },
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 },
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 {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
102 {"print", DCERPC_DEBUG_PRINT_BOTH},
103 {"padcheck", DCERPC_DEBUG_PAD_CHECK},
104 {"bigendian", DCERPC_PUSH_BIGENDIAN},
105 {"smb2", DCERPC_SMB2},
106 {"ndr64", DCERPC_NDR64},
109 static const struct ncacn_option *ncacn_option_by_name(const char *name)
111 size_t i;
113 for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
114 int ret;
116 ret = strcasecmp(ncacn_options[i].name, name);
117 if (ret != 0) {
118 continue;
121 return &ncacn_options[i];
124 return NULL;
127 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
129 struct ndr_syntax_id syntax;
130 NTSTATUS status;
132 switch(epm_floor->lhs.protocol) {
133 case EPM_PROTOCOL_UUID:
134 status = dcerpc_floor_get_lhs_data(epm_floor, &syntax);
135 if (NT_STATUS_IS_OK(status)) {
136 /* lhs is used: UUID */
137 char *uuidstr;
139 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
140 return "NDR";
143 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
144 return "NDR64";
147 uuidstr = GUID_string(mem_ctx, &syntax.uuid);
149 return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, syntax.if_version);
150 } else { /* IPX */
151 return talloc_asprintf(mem_ctx, "IPX:%s",
152 data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
155 case EPM_PROTOCOL_NCACN:
156 return "RPC-C";
158 case EPM_PROTOCOL_NCADG:
159 return "RPC";
161 case EPM_PROTOCOL_NCALRPC:
162 return "NCALRPC";
164 case EPM_PROTOCOL_DNET_NSP:
165 return "DNET/NSP";
167 case EPM_PROTOCOL_IP:
168 return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
170 case EPM_PROTOCOL_NAMED_PIPE:
171 return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
173 case EPM_PROTOCOL_SMB:
174 return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
176 case EPM_PROTOCOL_UNIX_DS:
177 return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
179 case EPM_PROTOCOL_NETBIOS:
180 return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
182 case EPM_PROTOCOL_NETBEUI:
183 return "NETBeui";
185 case EPM_PROTOCOL_SPX:
186 return "SPX";
188 case EPM_PROTOCOL_NB_IPX:
189 return "NB_IPX";
191 case EPM_PROTOCOL_HTTP:
192 return talloc_asprintf(mem_ctx, "HTTP:%d", epm_floor->rhs.http.port);
194 case EPM_PROTOCOL_TCP:
195 return talloc_asprintf(mem_ctx, "TCP:%d", epm_floor->rhs.tcp.port);
197 case EPM_PROTOCOL_UDP:
198 return talloc_asprintf(mem_ctx, "UDP:%d", epm_floor->rhs.udp.port);
200 default:
201 return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
207 form a binding string from a binding structure
209 _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
211 char *s = talloc_strdup(mem_ctx, "");
212 char *o = s;
213 int i;
214 const char *t_name = NULL;
215 bool option_section = false;
216 const char *target_hostname = NULL;
218 if (b->transport != NCA_UNKNOWN) {
219 t_name = derpc_transport_string_by_transport(b->transport);
220 if (!t_name) {
221 talloc_free(o);
222 return NULL;
226 if (!GUID_all_zero(&b->object.uuid)) {
227 o = s;
228 s = talloc_asprintf_append_buffer(s, "%s@",
229 GUID_string(mem_ctx, &b->object.uuid));
230 if (s == NULL) {
231 talloc_free(o);
232 return NULL;
236 if (t_name != NULL) {
237 o = s;
238 s = talloc_asprintf_append_buffer(s, "%s:", t_name);
239 if (s == NULL) {
240 talloc_free(o);
241 return NULL;
245 if (b->host) {
246 o = s;
247 s = talloc_asprintf_append_buffer(s, "%s", b->host);
248 if (s == NULL) {
249 talloc_free(o);
250 return NULL;
254 target_hostname = b->target_hostname;
255 if (target_hostname != NULL && b->host != NULL) {
256 if (strcmp(target_hostname, b->host) == 0) {
257 target_hostname = NULL;
261 if (b->endpoint) {
262 option_section = true;
263 } else if (target_hostname) {
264 option_section = true;
265 } else if (b->target_principal) {
266 option_section = true;
267 } else if (b->assoc_group_id != 0) {
268 option_section = true;
269 } else if (b->options) {
270 option_section = true;
271 } else if (b->flags) {
272 option_section = true;
275 if (!option_section) {
276 return s;
279 o = s;
280 s = talloc_asprintf_append_buffer(s, "[");
281 if (s == NULL) {
282 talloc_free(o);
283 return NULL;
286 if (b->endpoint) {
287 o = s;
288 s = talloc_asprintf_append_buffer(s, "%s", b->endpoint);
289 if (s == NULL) {
290 talloc_free(o);
291 return NULL;
295 for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
296 if (!(b->flags & ncacn_options[i].flag)) {
297 continue;
300 o = s;
301 s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
302 if (s == NULL) {
303 talloc_free(o);
304 return NULL;
308 if (target_hostname) {
309 o = s;
310 s = talloc_asprintf_append_buffer(s, ",target_hostname=%s",
311 b->target_hostname);
312 if (s == NULL) {
313 talloc_free(o);
314 return NULL;
318 if (b->target_principal) {
319 o = s;
320 s = talloc_asprintf_append_buffer(s, ",target_principal=%s",
321 b->target_principal);
322 if (s == NULL) {
323 talloc_free(o);
324 return NULL;
328 if (b->assoc_group_id != 0) {
329 o = s;
330 s = talloc_asprintf_append_buffer(s, ",assoc_group_id=0x%08x",
331 b->assoc_group_id);
332 if (s == NULL) {
333 talloc_free(o);
334 return NULL;
338 for (i=0;b->options && b->options[i];i++) {
339 o = s;
340 s = talloc_asprintf_append_buffer(s, ",%s", b->options[i]);
341 if (s == NULL) {
342 talloc_free(o);
343 return NULL;
347 o = s;
348 s = talloc_asprintf_append_buffer(s, "]");
349 if (s == NULL) {
350 talloc_free(o);
351 return NULL;
354 return s;
358 parse a binding string into a dcerpc_binding structure
360 _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
362 char *_t;
363 struct dcerpc_binding *b;
364 char *s;
365 char *options = NULL;
366 char *p;
367 size_t i;
368 NTSTATUS status;
370 b = talloc_zero(mem_ctx, struct dcerpc_binding);
371 if (!b) {
372 return NT_STATUS_NO_MEMORY;
375 _t = talloc_strdup(b, _s);
376 if (_t == NULL) {
377 talloc_free(b);
378 return NT_STATUS_NO_MEMORY;
381 s = _t;
383 p = strchr(s, '[');
384 if (p) {
385 *p = '\0';
386 options = p + 1;
387 if (options[strlen(options)-1] != ']') {
388 talloc_free(b);
389 return NT_STATUS_INVALID_PARAMETER_MIX;
391 options[strlen(options)-1] = 0;
394 p = strchr(s, '@');
396 if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
397 *p = '\0';
399 status = dcerpc_binding_set_string_option(b, "object", s);
400 if (!NT_STATUS_IS_OK(status)) {
401 talloc_free(b);
402 return status;
405 s = p + 1;
408 p = strchr(s, ':');
410 if (p == NULL) {
411 b->transport = NCA_UNKNOWN;
412 } else {
413 *p = '\0';
415 status = dcerpc_binding_set_string_option(b, "transport", s);
416 if (!NT_STATUS_IS_OK(status)) {
417 talloc_free(b);
418 return status;
421 s = p + 1;
424 if (strlen(s) > 0) {
425 status = dcerpc_binding_set_string_option(b, "host", s);
426 if (!NT_STATUS_IS_OK(status)) {
427 talloc_free(b);
428 return status;
431 b->target_hostname = talloc_strdup(b, b->host);
432 if (b->target_hostname == NULL) {
433 talloc_free(b);
434 return NT_STATUS_NO_MEMORY;
438 for (i=0; options != NULL; i++) {
439 const char *name = options;
440 const char *value = NULL;
442 p = strchr(options, ',');
443 if (p != NULL) {
444 *p = '\0';
445 options = p+1;
446 } else {
447 options = NULL;
450 p = strchr(name, '=');
451 if (p != NULL) {
452 *p = '\0';
453 value = p + 1;
456 if (value == NULL) {
458 * If it's not a key=value pair
459 * it might be a ncacn_option
460 * or if it's the first option
461 * it's the endpoint.
463 const struct ncacn_option *no = NULL;
465 value = name;
467 no = ncacn_option_by_name(name);
468 if (no == NULL) {
469 if (i > 0) {
471 * we don't allow unknown options
473 return NT_STATUS_INVALID_PARAMETER_MIX;
477 * This is the endpoint
479 name = "endpoint";
480 if (strlen(value) == 0) {
481 value = NULL;
486 status = dcerpc_binding_set_string_option(b, name, value);
487 if (!NT_STATUS_IS_OK(status)) {
488 talloc_free(b);
489 return status;
493 talloc_free(_t);
494 *b_out = b;
495 return NT_STATUS_OK;
498 _PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
500 return b->object.uuid;
503 _PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
504 struct GUID object)
506 char *tmp = discard_const_p(char, b->object_string);
508 if (GUID_all_zero(&object)) {
509 talloc_free(tmp);
510 b->object_string = NULL;
511 ZERO_STRUCT(b->object);
512 return NT_STATUS_OK;
515 b->object_string = GUID_string(b, &object);
516 if (b->object_string == NULL) {
517 b->object_string = tmp;
518 return NT_STATUS_NO_MEMORY;
520 talloc_free(tmp);
522 ZERO_STRUCT(b->object);
523 b->object.uuid = object;
524 return NT_STATUS_OK;
527 _PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
529 return b->transport;
532 _PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
533 enum dcerpc_transport_t transport)
535 char *tmp = discard_const_p(char, b->endpoint);
538 * TODO: we may want to check the transport value is
539 * wellknown.
541 if (b->transport == transport) {
542 return NT_STATUS_OK;
545 b->transport = transport;
548 * This implicitly resets the endpoint
549 * as the endpoint is transport specific.
551 * TODO: in future we may reset more options
552 * here.
554 talloc_free(tmp);
555 b->endpoint = NULL;
557 return NT_STATUS_OK;
560 _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
561 enum dcerpc_AuthType *_auth_type,
562 enum dcerpc_AuthLevel *_auth_level)
564 enum dcerpc_AuthType auth_type;
565 enum dcerpc_AuthLevel auth_level;
567 if (b->flags & DCERPC_AUTH_SPNEGO) {
568 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
569 } else if (b->flags & DCERPC_AUTH_KRB5) {
570 auth_type = DCERPC_AUTH_TYPE_KRB5;
571 } else if (b->flags & DCERPC_SCHANNEL) {
572 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
573 } else if (b->flags & DCERPC_AUTH_NTLM) {
574 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
575 } else {
576 auth_type = DCERPC_AUTH_TYPE_NONE;
579 if (b->flags & DCERPC_SEAL) {
580 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
581 } else if (b->flags & DCERPC_SIGN) {
582 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
583 } else if (b->flags & DCERPC_CONNECT) {
584 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
585 } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
586 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
587 } else {
588 auth_level = DCERPC_AUTH_LEVEL_NONE;
591 if (_auth_type == NULL) {
592 *_auth_type = auth_type;
595 if (_auth_level == NULL) {
596 *_auth_level = auth_level;
600 _PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
602 return b->assoc_group_id;
605 _PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
606 uint32_t assoc_group_id)
608 b->assoc_group_id = assoc_group_id;
609 return NT_STATUS_OK;
612 _PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
615 * For now we just use object, until all callers are fixed.
617 return b->object;
620 _PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
621 const struct ndr_syntax_id *syntax)
623 NTSTATUS status;
624 struct GUID object;
627 * For now we just use object, until all callers are fixed.
630 if (syntax != NULL) {
631 object = syntax->uuid;
632 } else {
633 object = GUID_zero();
637 * This sets also the string
639 status = dcerpc_binding_set_object(b, object);
640 if (!NT_STATUS_IS_OK(status)) {
641 return status;
644 if (syntax != NULL) {
646 * Here we need to reset the whole ndr_syntax_id
647 * structure including the .if_version
649 b->object = *syntax;
652 return NT_STATUS_OK;
655 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
656 const char *name)
658 struct {
659 const char *name;
660 const char *value;
661 #define _SPECIAL(x) { .name = #x, .value = b->x, }
662 } specials[] = {
663 { .name = "object", .value = b->object_string, },
664 _SPECIAL(host),
665 _SPECIAL(endpoint),
666 _SPECIAL(target_hostname),
667 _SPECIAL(target_principal),
668 #undef _SPECIAL
670 const struct ncacn_option *no = NULL;
671 size_t name_len = strlen(name);
672 size_t i;
673 int ret;
675 ret = strcmp(name, "transport");
676 if (ret == 0) {
677 return derpc_transport_string_by_transport(b->transport);
680 ret = strcmp(name, "assoc_group_id");
681 if (ret == 0) {
682 char *tmp = discard_const_p(char, b->assoc_group_string);
684 if (b->assoc_group_id == 0) {
685 return NULL;
688 snprintf(tmp, sizeof(b->assoc_group_string),
689 "0x%08x", b->assoc_group_id);
690 return (const char *)b->assoc_group_string;
693 for (i=0; i < ARRAY_SIZE(specials); i++) {
694 ret = strcmp(specials[i].name, name);
695 if (ret != 0) {
696 continue;
699 return specials[i].value;
702 no = ncacn_option_by_name(name);
703 if (no != NULL) {
704 if (b->flags & no->flag) {
705 return no->name;
708 return NULL;
711 if (b->options == NULL) {
712 return NULL;
715 for (i=0; b->options[i]; i++) {
716 const char *o = b->options[i];
717 const char *vs = NULL;
719 ret = strncmp(name, o, name_len);
720 if (ret != 0) {
721 continue;
724 if (o[name_len] != '=') {
725 continue;
728 vs = &o[name_len + 1];
730 return vs;
733 return NULL;
736 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
737 const struct dcerpc_binding *b,
738 const char *name)
740 const char *c = dcerpc_binding_get_string_option(b, name);
741 char *v;
743 if (c == NULL) {
744 errno = ENOENT;
745 return NULL;
748 v = talloc_strdup(mem_ctx, c);
749 if (v == NULL) {
750 errno = ENOMEM;
751 return NULL;
754 return v;
757 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
758 const char *name,
759 const char *value)
761 struct {
762 const char *name;
763 const char **ptr;
764 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
765 } specials[] = {
766 _SPECIAL(host),
767 _SPECIAL(endpoint),
768 _SPECIAL(target_hostname),
769 _SPECIAL(target_principal),
770 #undef _SPECIAL
772 const struct ncacn_option *no = NULL;
773 size_t name_len = strlen(name);
774 const char *opt = NULL;
775 char *tmp;
776 size_t i;
777 int ret;
780 * Note: value == NULL, means delete it.
781 * value != NULL means add or reset.
784 ret = strcmp(name, "transport");
785 if (ret == 0) {
786 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
788 if (t == NCA_UNKNOWN && value != NULL) {
789 return NT_STATUS_INVALID_PARAMETER_MIX;
792 return dcerpc_binding_set_transport(b, t);
795 ret = strcmp(name, "object");
796 if (ret == 0) {
797 NTSTATUS status;
798 struct GUID uuid = GUID_zero();
800 if (value != NULL) {
801 DATA_BLOB blob;
802 blob = data_blob_string_const(value);
803 if (blob.length != 36) {
804 return NT_STATUS_INVALID_PARAMETER_MIX;
807 status = GUID_from_data_blob(&blob, &uuid);
808 if (!NT_STATUS_IS_OK(status)) {
809 return status;
813 return dcerpc_binding_set_object(b, uuid);
816 ret = strcmp(name, "assoc_group_id");
817 if (ret == 0) {
818 uint32_t assoc_group_id = 0;
820 if (value != NULL) {
821 char c;
823 ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
824 if (ret != 1) {
825 return NT_STATUS_INVALID_PARAMETER_MIX;
829 return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
832 for (i=0; i < ARRAY_SIZE(specials); i++) {
833 ret = strcmp(specials[i].name, name);
834 if (ret != 0) {
835 continue;
838 tmp = discard_const_p(char, *specials[i].ptr);
840 if (value == NULL) {
841 talloc_free(tmp);
842 *specials[i].ptr = NULL;
843 return NT_STATUS_OK;
846 if (value[0] == '\0') {
847 return NT_STATUS_INVALID_PARAMETER_MIX;
850 *specials[i].ptr = talloc_strdup(b, value);
851 if (*specials[i].ptr == NULL) {
852 *specials[i].ptr = tmp;
853 return NT_STATUS_NO_MEMORY;
855 talloc_free(tmp);
857 return NT_STATUS_OK;
860 no = ncacn_option_by_name(name);
861 if (no != NULL) {
862 if (value == NULL) {
863 b->flags &= ~no->flag;
864 return NT_STATUS_OK;
867 ret = strcasecmp(no->name, value);
868 if (ret != 0) {
869 return NT_STATUS_INVALID_PARAMETER_MIX;
872 b->flags |= no->flag;
873 return NT_STATUS_OK;
876 for (i=0; b->options && b->options[i]; i++) {
877 const char *o = b->options[i];
879 ret = strncmp(name, o, name_len);
880 if (ret != 0) {
881 continue;
884 if (o[name_len] != '=') {
885 continue;
888 opt = o;
889 break;
892 if (opt == NULL) {
893 const char **n;
895 if (value == NULL) {
896 return NT_STATUS_OK;
899 n = talloc_realloc(b, b->options, const char *, i + 2);
900 if (n == NULL) {
901 return NT_STATUS_NO_MEMORY;
903 n[i] = NULL;
904 n[i + 1] = NULL;
905 b->options = n;
908 tmp = discard_const_p(char, opt);
910 if (value == NULL) {
911 for (;b->options[i];i++) {
912 b->options[i] = b->options[i+1];
914 talloc_free(tmp);
915 return NT_STATUS_OK;
918 b->options[i] = talloc_asprintf(b->options, "%s=%s",
919 name, value);
920 if (b->options[i] == NULL) {
921 b->options[i] = tmp;
922 return NT_STATUS_NO_MEMORY;
925 return NT_STATUS_OK;
928 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
930 return b->flags;
933 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
934 uint32_t additional,
935 uint32_t clear)
938 * TODO: in future we may want to reject invalid combinations
940 b->flags &= ~clear;
941 b->flags |= additional;
943 return NT_STATUS_OK;
946 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
947 struct ndr_syntax_id *syntax)
949 TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
950 struct ndr_pull *ndr;
951 enum ndr_err_code ndr_err;
952 uint16_t if_version=0;
954 ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
955 if (ndr == NULL) {
956 talloc_free(mem_ctx);
957 return NT_STATUS_NO_MEMORY;
959 ndr->flags |= LIBNDR_FLAG_NOALIGN;
961 ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
962 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
963 talloc_free(mem_ctx);
964 return ndr_map_error2ntstatus(ndr_err);
967 ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
968 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
969 talloc_free(mem_ctx);
970 return ndr_map_error2ntstatus(ndr_err);
973 syntax->if_version = if_version;
975 talloc_free(mem_ctx);
977 return NT_STATUS_OK;
980 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
982 DATA_BLOB blob;
983 enum ndr_err_code ndr_err;
984 struct ndr_push *ndr;
986 ndr = ndr_push_init_ctx(mem_ctx);
987 if (ndr == NULL) {
988 return data_blob_null;
991 ndr->flags |= LIBNDR_FLAG_NOALIGN;
993 ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
994 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
995 return data_blob_null;
997 ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
998 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
999 return data_blob_null;
1002 blob = ndr_push_blob(ndr);
1003 talloc_steal(mem_ctx, blob.data);
1004 talloc_free(ndr);
1005 return blob;
1008 static bool dcerpc_floor_pack_rhs_if_version_data(
1009 TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
1010 DATA_BLOB *pblob)
1012 DATA_BLOB blob;
1013 struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
1014 enum ndr_err_code ndr_err;
1016 if (ndr == NULL) {
1017 return false;
1020 ndr->flags |= LIBNDR_FLAG_NOALIGN;
1022 ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
1023 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1024 return false;
1027 blob = ndr_push_blob(ndr);
1028 talloc_steal(mem_ctx, blob.data);
1029 talloc_free(ndr);
1030 *pblob = blob;
1031 return true;
1034 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
1036 switch (epm_floor->lhs.protocol) {
1037 case EPM_PROTOCOL_TCP:
1038 if (epm_floor->rhs.tcp.port == 0) return NULL;
1039 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
1041 case EPM_PROTOCOL_UDP:
1042 if (epm_floor->rhs.udp.port == 0) return NULL;
1043 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
1045 case EPM_PROTOCOL_HTTP:
1046 if (epm_floor->rhs.http.port == 0) return NULL;
1047 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
1049 case EPM_PROTOCOL_IP:
1050 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
1052 case EPM_PROTOCOL_NCACN:
1053 return NULL;
1055 case EPM_PROTOCOL_NCADG:
1056 return NULL;
1058 case EPM_PROTOCOL_SMB:
1059 if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
1060 return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
1062 case EPM_PROTOCOL_NAMED_PIPE:
1063 if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
1064 return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
1066 case EPM_PROTOCOL_NETBIOS:
1067 if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
1068 return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
1070 case EPM_PROTOCOL_NCALRPC:
1071 return NULL;
1073 case EPM_PROTOCOL_VINES_SPP:
1074 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
1076 case EPM_PROTOCOL_VINES_IPC:
1077 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
1079 case EPM_PROTOCOL_STREETTALK:
1080 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
1082 case EPM_PROTOCOL_UNIX_DS:
1083 if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
1084 return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
1086 case EPM_PROTOCOL_NULL:
1087 return NULL;
1089 default:
1090 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1091 break;
1094 return NULL;
1097 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx,
1098 struct epm_floor *epm_floor,
1099 const char *data)
1101 if (data == NULL) {
1102 data = "";
1105 switch (epm_floor->lhs.protocol) {
1106 case EPM_PROTOCOL_TCP:
1107 epm_floor->rhs.tcp.port = atoi(data);
1108 return NT_STATUS_OK;
1110 case EPM_PROTOCOL_UDP:
1111 epm_floor->rhs.udp.port = atoi(data);
1112 return NT_STATUS_OK;
1114 case EPM_PROTOCOL_HTTP:
1115 epm_floor->rhs.http.port = atoi(data);
1116 return NT_STATUS_OK;
1118 case EPM_PROTOCOL_IP:
1119 if (!is_ipaddress_v4(data)) {
1120 data = "0.0.0.0";
1122 epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
1123 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
1124 return NT_STATUS_OK;
1126 case EPM_PROTOCOL_NCACN:
1127 epm_floor->rhs.ncacn.minor_version = 0;
1128 return NT_STATUS_OK;
1130 case EPM_PROTOCOL_NCADG:
1131 epm_floor->rhs.ncadg.minor_version = 0;
1132 return NT_STATUS_OK;
1134 case EPM_PROTOCOL_SMB:
1135 epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
1136 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
1137 return NT_STATUS_OK;
1139 case EPM_PROTOCOL_NAMED_PIPE:
1140 epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
1141 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
1142 return NT_STATUS_OK;
1144 case EPM_PROTOCOL_NETBIOS:
1145 epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
1146 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
1147 return NT_STATUS_OK;
1149 case EPM_PROTOCOL_NCALRPC:
1150 return NT_STATUS_OK;
1152 case EPM_PROTOCOL_VINES_SPP:
1153 epm_floor->rhs.vines_spp.port = atoi(data);
1154 return NT_STATUS_OK;
1156 case EPM_PROTOCOL_VINES_IPC:
1157 epm_floor->rhs.vines_ipc.port = atoi(data);
1158 return NT_STATUS_OK;
1160 case EPM_PROTOCOL_STREETTALK:
1161 epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
1162 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
1163 return NT_STATUS_OK;
1165 case EPM_PROTOCOL_UNIX_DS:
1166 epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
1167 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
1168 return NT_STATUS_OK;
1170 case EPM_PROTOCOL_NULL:
1171 return NT_STATUS_OK;
1173 default:
1174 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1175 break;
1178 return NT_STATUS_NOT_SUPPORTED;
1181 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
1183 int i;
1185 /* Find a transport that has 'prot' as 4th protocol */
1186 for (i=0;i<ARRAY_SIZE(transports);i++) {
1187 if (transports[i].num_protocols >= 2 &&
1188 transports[i].protseq[1] == prot) {
1189 return transports[i].transport;
1193 /* Unknown transport */
1194 return (unsigned int)-1;
1197 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1199 int i;
1201 /* Find a transport that matches this tower */
1202 for (i=0;i<ARRAY_SIZE(transports);i++) {
1203 int j;
1204 if (transports[i].num_protocols != tower->num_floors - 2) {
1205 continue;
1208 for (j = 0; j < transports[i].num_protocols; j++) {
1209 if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
1210 break;
1214 if (j == transports[i].num_protocols) {
1215 return transports[i].transport;
1219 /* Unknown transport */
1220 return (unsigned int)-1;
1223 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1225 int i;
1227 for (i=0; i<ARRAY_SIZE(transports); i++) {
1228 if (t == transports[i].transport) {
1229 return transports[i].name;
1232 return NULL;
1235 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1237 size_t i;
1239 if (name == NULL) {
1240 return NCA_UNKNOWN;
1243 for (i=0; i<ARRAY_SIZE(transports);i++) {
1244 if (strcasecmp(name, transports[i].name) == 0) {
1245 return transports[i].transport;
1249 return NCA_UNKNOWN;
1252 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1253 struct epm_tower *tower,
1254 struct dcerpc_binding **b_out)
1256 NTSTATUS status;
1257 struct dcerpc_binding *b;
1258 enum dcerpc_transport_t transport;
1259 struct ndr_syntax_id abstract_syntax;
1260 char *endpoint = NULL;
1261 char *host = NULL;
1264 * A tower needs to have at least 4 floors to carry useful
1265 * information. Floor 3 is the transport identifier which defines
1266 * how many floors are required at least.
1268 if (tower->num_floors < 4) {
1269 return NT_STATUS_INVALID_PARAMETER;
1272 status = dcerpc_parse_binding(mem_ctx, "", &b);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 return status;
1277 transport = dcerpc_transport_by_tower(tower);
1278 if (transport == NCA_UNKNOWN) {
1279 talloc_free(b);
1280 return NT_STATUS_NOT_SUPPORTED;
1283 status = dcerpc_binding_set_transport(b, transport);
1284 if (!NT_STATUS_IS_OK(status)) {
1285 talloc_free(b);
1286 return status;
1289 /* Set abstract syntax */
1290 status = dcerpc_floor_get_lhs_data(&tower->floors[0], &abstract_syntax);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 talloc_free(b);
1293 return status;
1296 status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
1297 if (!NT_STATUS_IS_OK(status)) {
1298 talloc_free(b);
1299 return status;
1302 /* Ignore floor 1, it contains the NDR version info */
1304 /* Set endpoint */
1305 errno = 0;
1306 if (tower->num_floors >= 4) {
1307 endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
1309 if (errno != 0) {
1310 int saved_errno = errno;
1311 talloc_free(b);
1312 return map_nt_error_from_unix_common(saved_errno);
1315 status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
1316 if (!NT_STATUS_IS_OK(status)) {
1317 talloc_free(b);
1318 return status;
1320 TALLOC_FREE(endpoint);
1322 /* Set network address */
1323 errno = 0;
1324 if (tower->num_floors >= 5) {
1325 host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
1327 if (errno != 0) {
1328 int saved_errno = errno;
1329 talloc_free(b);
1330 return map_nt_error_from_unix_common(saved_errno);
1333 status = dcerpc_binding_set_string_option(b, "host", host);
1334 if (!NT_STATUS_IS_OK(status)) {
1335 talloc_free(b);
1336 return status;
1338 status = dcerpc_binding_set_string_option(b, "target_hostname", host);
1339 if (!NT_STATUS_IS_OK(status)) {
1340 talloc_free(b);
1341 return status;
1343 TALLOC_FREE(host);
1345 *b_out = b;
1346 return NT_STATUS_OK;
1349 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1350 const struct dcerpc_binding *b)
1352 struct dcerpc_binding *n;
1353 uint32_t count;
1355 n = talloc_zero(mem_ctx, struct dcerpc_binding);
1356 if (n == NULL) {
1357 return NULL;
1360 n->transport = b->transport;
1361 n->object = b->object;
1362 n->flags = b->flags;
1363 n->assoc_group_id = b->assoc_group_id;
1365 if (b->object_string != NULL) {
1366 n->object_string = talloc_strdup(n, b->object_string);
1367 if (n->object_string == NULL) {
1368 talloc_free(n);
1369 return NULL;
1372 if (b->host != NULL) {
1373 n->host = talloc_strdup(n, b->host);
1374 if (n->host == NULL) {
1375 talloc_free(n);
1376 return NULL;
1380 if (b->target_hostname != NULL) {
1381 n->target_hostname = talloc_strdup(n, b->target_hostname);
1382 if (n->target_hostname == NULL) {
1383 talloc_free(n);
1384 return NULL;
1388 if (b->target_principal != NULL) {
1389 n->target_principal = talloc_strdup(n, b->target_principal);
1390 if (n->target_principal == NULL) {
1391 talloc_free(n);
1392 return NULL;
1396 if (b->endpoint != NULL) {
1397 n->endpoint = talloc_strdup(n, b->endpoint);
1398 if (n->endpoint == NULL) {
1399 talloc_free(n);
1400 return NULL;
1404 for (count = 0; b->options && b->options[count]; count++);
1406 if (count > 0) {
1407 uint32_t i;
1409 n->options = talloc_array(n, const char *, count + 1);
1410 if (n->options == NULL) {
1411 talloc_free(n);
1412 return NULL;
1415 for (i = 0; i < count; i++) {
1416 n->options[i] = talloc_strdup(n->options, b->options[i]);
1417 if (n->options[i] == NULL) {
1418 talloc_free(n);
1419 return NULL;
1422 n->options[count] = NULL;
1425 return n;
1428 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1429 const struct dcerpc_binding *binding,
1430 struct epm_tower *tower)
1432 const enum epm_protocol *protseq = NULL;
1433 int num_protocols = -1, i;
1434 struct ndr_syntax_id abstract_syntax;
1435 NTSTATUS status;
1437 /* Find transport */
1438 for (i=0;i<ARRAY_SIZE(transports);i++) {
1439 if (transports[i].transport == binding->transport) {
1440 protseq = transports[i].protseq;
1441 num_protocols = transports[i].num_protocols;
1442 break;
1446 if (num_protocols == -1) {
1447 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1448 return NT_STATUS_UNSUCCESSFUL;
1451 tower->num_floors = 2 + num_protocols;
1452 tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1454 /* Floor 0 */
1455 tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
1457 abstract_syntax = dcerpc_binding_get_abstract_syntax(binding);
1458 tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1459 &abstract_syntax);
1461 if (!dcerpc_floor_pack_rhs_if_version_data(
1462 tower->floors, &abstract_syntax,
1463 &tower->floors[0].rhs.uuid.unknown)) {
1464 return NT_STATUS_NO_MEMORY;
1467 /* Floor 1 */
1468 tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1470 tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1471 &ndr_transfer_syntax_ndr);
1473 tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
1475 /* Floor 2 to num_protocols */
1476 for (i = 0; i < num_protocols; i++) {
1477 tower->floors[2 + i].lhs.protocol = protseq[i];
1478 tower->floors[2 + i].lhs.lhs_data = data_blob_null;
1479 ZERO_STRUCT(tower->floors[2 + i].rhs);
1480 status = dcerpc_floor_set_rhs_data(tower->floors,
1481 &tower->floors[2 + i],
1482 NULL);
1483 if (!NT_STATUS_IS_OK(status)) {
1484 return status;
1488 /* The 4th floor contains the endpoint */
1489 if (num_protocols >= 2 && binding->endpoint) {
1490 status = dcerpc_floor_set_rhs_data(tower->floors,
1491 &tower->floors[3],
1492 binding->endpoint);
1493 if (!NT_STATUS_IS_OK(status)) {
1494 return status;
1498 /* The 5th contains the network address */
1499 if (num_protocols >= 3 && binding->host) {
1500 status = dcerpc_floor_set_rhs_data(tower->floors,
1501 &tower->floors[4],
1502 binding->host);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 return status;
1508 return NT_STATUS_OK;