wscript_build_embedded_heimdal: update to handle waf 2.0.4
[Samba.git] / librpc / rpc / binding.c
blobaa8cc6b46c6f151d5103098130c5d071b16bb183
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 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' */
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 {"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},
112 static const struct ncacn_option *ncacn_option_by_name(const char *name)
114 size_t i;
116 for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
117 int ret;
119 ret = strcasecmp(ncacn_options[i].name, name);
120 if (ret != 0) {
121 continue;
124 return &ncacn_options[i];
127 return NULL;
130 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
132 struct ndr_syntax_id syntax;
133 NTSTATUS status;
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;
142 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
143 return "NDR";
146 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
147 return "NDR64";
150 uuidstr = GUID_string(mem_ctx, &syntax.uuid);
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));
158 case EPM_PROTOCOL_NCACN:
159 return "RPC-C";
161 case EPM_PROTOCOL_NCADG:
162 return "RPC";
164 case EPM_PROTOCOL_NCALRPC:
165 return "NCALRPC";
167 case EPM_PROTOCOL_DNET_NSP:
168 return "DNET/NSP";
170 case EPM_PROTOCOL_IP:
171 return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
173 case EPM_PROTOCOL_NAMED_PIPE:
174 return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
176 case EPM_PROTOCOL_SMB:
177 return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
179 case EPM_PROTOCOL_UNIX_DS:
180 return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
182 case EPM_PROTOCOL_NETBIOS:
183 return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
185 case EPM_PROTOCOL_NETBEUI:
186 return "NETBeui";
188 case EPM_PROTOCOL_SPX:
189 return "SPX";
191 case EPM_PROTOCOL_NB_IPX:
192 return "NB_IPX";
194 case EPM_PROTOCOL_HTTP:
195 return talloc_asprintf(mem_ctx, "HTTP:%d", epm_floor->rhs.http.port);
197 case EPM_PROTOCOL_TCP:
198 return talloc_asprintf(mem_ctx, "TCP:%d", epm_floor->rhs.tcp.port);
200 case EPM_PROTOCOL_UDP:
201 return talloc_asprintf(mem_ctx, "UDP:%d", epm_floor->rhs.udp.port);
203 default:
204 return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
210 form a binding string from a binding structure
212 _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
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;
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;
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;
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;
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;
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;
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;
278 if (!option_section) {
279 return s;
282 o = s;
283 s = talloc_asprintf_append_buffer(s, "[");
284 if (s == NULL) {
285 talloc_free(o);
286 return NULL;
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;
298 for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
299 if (!(b->flags & ncacn_options[i].flag)) {
300 continue;
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;
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;
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;
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;
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;
350 o = s;
351 s = talloc_asprintf_append_buffer(s, "]");
352 if (s == NULL) {
353 talloc_free(o);
354 return NULL;
357 return s;
361 parse a binding string into a dcerpc_binding structure
363 _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
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;
373 b = talloc_zero(mem_ctx, struct dcerpc_binding);
374 if (!b) {
375 return NT_STATUS_NO_MEMORY;
378 _t = talloc_strdup(b, _s);
379 if (_t == NULL) {
380 talloc_free(b);
381 return NT_STATUS_NO_MEMORY;
384 s = _t;
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;
394 options[strlen(options)-1] = 0;
397 p = strchr(s, '@');
399 if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
400 *p = '\0';
402 status = dcerpc_binding_set_string_option(b, "object", s);
403 if (!NT_STATUS_IS_OK(status)) {
404 talloc_free(b);
405 return status;
408 s = p + 1;
411 p = strchr(s, ':');
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';
420 status = dcerpc_binding_set_string_option(b, "transport", s);
421 if (!NT_STATUS_IS_OK(status)) {
422 talloc_free(b);
423 return status;
426 s = p + 1;
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;
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;
443 for (i=0; options != NULL; i++) {
444 const char *name = options;
445 const char *value = NULL;
447 p = strchr(options, ',');
448 if (p != NULL) {
449 *p = '\0';
450 options = p+1;
451 } else {
452 options = NULL;
455 p = strchr(name, '=');
456 if (p != NULL) {
457 *p = '\0';
458 value = p + 1;
461 if (value == NULL) {
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.
468 const struct ncacn_option *no = NULL;
470 value = name;
472 no = ncacn_option_by_name(name);
473 if (no == NULL) {
474 if (i > 0) {
476 * we don't allow unknown options
478 return NT_STATUS_INVALID_PARAMETER_MIX;
482 * This is the endpoint
484 name = "endpoint";
485 if (strlen(value) == 0) {
486 value = NULL;
491 status = dcerpc_binding_set_string_option(b, name, value);
492 if (!NT_STATUS_IS_OK(status)) {
493 talloc_free(b);
494 return status;
498 talloc_free(_t);
499 *b_out = b;
500 return NT_STATUS_OK;
503 _PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
505 return b->object;
508 _PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
509 struct GUID object)
511 char *tmp = discard_const_p(char, b->object_string);
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;
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;
525 talloc_free(tmp);
527 b->object = object;
528 return NT_STATUS_OK;
531 _PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
533 return b->transport;
536 _PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
537 enum dcerpc_transport_t transport)
539 NTSTATUS status;
542 * TODO: we may want to check the transport value is
543 * wellknown.
545 if (b->transport == transport) {
546 return NT_STATUS_OK;
550 * This implicitly resets the endpoint
551 * as the endpoint is transport specific.
553 * It also resets the assoc group as it's
554 * also endpoint specific.
556 * TODO: in future we may reset more options
557 * here.
559 status = dcerpc_binding_set_string_option(b, "endpoint", NULL);
560 if (!NT_STATUS_IS_OK(status)) {
561 return status;
564 b->assoc_group_id = 0;
566 b->transport = transport;
567 return NT_STATUS_OK;
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)
574 enum dcerpc_AuthType auth_type;
575 enum dcerpc_AuthLevel auth_level;
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;
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;
603 if (_auth_type != NULL) {
604 *_auth_type = auth_type;
607 if (_auth_level != NULL) {
608 *_auth_level = auth_level;
612 _PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
614 return b->assoc_group_id;
617 _PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
618 uint32_t assoc_group_id)
620 b->assoc_group_id = assoc_group_id;
621 return NT_STATUS_OK;
624 _PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
626 const char *s = dcerpc_binding_get_string_option(b, "abstract_syntax");
627 bool ok;
628 struct ndr_syntax_id id;
630 if (s == NULL) {
631 return ndr_syntax_id_null;
634 ok = ndr_syntax_id_from_string(s, &id);
635 if (!ok) {
636 return ndr_syntax_id_null;
639 return id;
642 _PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
643 const struct ndr_syntax_id *syntax)
645 NTSTATUS status;
646 char *s = NULL;
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;
654 return NT_STATUS_OK;
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;
663 return NT_STATUS_OK;
666 s = ndr_syntax_id_to_string(b, syntax);
667 if (s == NULL) {
668 return NT_STATUS_NO_MEMORY;
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;
677 return NT_STATUS_OK;
680 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
681 const char *name)
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
695 const struct ncacn_option *no = NULL;
696 size_t name_len = strlen(name);
697 size_t i;
698 int ret;
700 ret = strcmp(name, "transport");
701 if (ret == 0) {
702 return derpc_transport_string_by_transport(b->transport);
705 ret = strcmp(name, "assoc_group_id");
706 if (ret == 0) {
707 char *tmp = discard_const_p(char, b->assoc_group_string);
709 if (b->assoc_group_id == 0) {
710 return NULL;
713 snprintf(tmp, sizeof(b->assoc_group_string),
714 "0x%08x", b->assoc_group_id);
715 return (const char *)b->assoc_group_string;
718 for (i=0; i < ARRAY_SIZE(specials); i++) {
719 ret = strcmp(specials[i].name, name);
720 if (ret != 0) {
721 continue;
724 return specials[i].value;
727 no = ncacn_option_by_name(name);
728 if (no != NULL) {
729 if (b->flags & no->flag) {
730 return no->name;
733 return NULL;
736 if (b->options == NULL) {
737 return NULL;
740 for (i=0; b->options[i]; i++) {
741 const char *o = b->options[i];
742 const char *vs = NULL;
744 ret = strncmp(name, o, name_len);
745 if (ret != 0) {
746 continue;
749 if (o[name_len] != '=') {
750 continue;
753 vs = &o[name_len + 1];
755 return vs;
758 return NULL;
761 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
762 const struct dcerpc_binding *b,
763 const char *name)
765 const char *c = dcerpc_binding_get_string_option(b, name);
766 char *v;
768 if (c == NULL) {
769 errno = ENOENT;
770 return NULL;
773 v = talloc_strdup(mem_ctx, c);
774 if (v == NULL) {
775 errno = ENOMEM;
776 return NULL;
779 return v;
782 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
783 const char *name,
784 const char *value)
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
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;
805 * Note: value == NULL, means delete it.
806 * value != NULL means add or reset.
809 ret = strcmp(name, "transport");
810 if (ret == 0) {
811 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
813 if (t == NCA_UNKNOWN && value != NULL) {
814 return NT_STATUS_INVALID_PARAMETER_MIX;
817 return dcerpc_binding_set_transport(b, t);
820 ret = strcmp(name, "object");
821 if (ret == 0) {
822 NTSTATUS status;
823 struct GUID uuid = GUID_zero();
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;
832 status = GUID_from_data_blob(&blob, &uuid);
833 if (!NT_STATUS_IS_OK(status)) {
834 return status;
838 return dcerpc_binding_set_object(b, uuid);
841 ret = strcmp(name, "assoc_group_id");
842 if (ret == 0) {
843 uint32_t assoc_group_id = 0;
845 if (value != NULL) {
846 char c;
848 ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
849 if (ret != 1) {
850 return NT_STATUS_INVALID_PARAMETER_MIX;
854 return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
857 for (i=0; i < ARRAY_SIZE(specials); i++) {
858 ret = strcmp(specials[i].name, name);
859 if (ret != 0) {
860 continue;
863 tmp = discard_const_p(char, *specials[i].ptr);
865 if (value == NULL) {
866 talloc_free(tmp);
867 *specials[i].ptr = NULL;
868 return NT_STATUS_OK;
871 if (value[0] == '\0') {
872 return NT_STATUS_INVALID_PARAMETER_MIX;
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;
880 talloc_free(tmp);
882 return NT_STATUS_OK;
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;
892 ret = strcasecmp(no->name, value);
893 if (ret != 0) {
894 return NT_STATUS_INVALID_PARAMETER_MIX;
897 b->flags |= no->flag;
898 return NT_STATUS_OK;
901 for (i=0; b->options && b->options[i]; i++) {
902 const char *o = b->options[i];
904 ret = strncmp(name, o, name_len);
905 if (ret != 0) {
906 continue;
909 if (o[name_len] != '=') {
910 continue;
913 opt = o;
914 break;
917 if (opt == NULL) {
918 const char **n;
920 if (value == NULL) {
921 return NT_STATUS_OK;
924 n = talloc_realloc(b, b->options, const char *, i + 2);
925 if (n == NULL) {
926 return NT_STATUS_NO_MEMORY;
928 n[i] = NULL;
929 n[i + 1] = NULL;
930 b->options = n;
933 tmp = discard_const_p(char, opt);
935 if (value == NULL) {
936 for (;b->options[i];i++) {
937 b->options[i] = b->options[i+1];
939 talloc_free(tmp);
940 return NT_STATUS_OK;
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;
950 return NT_STATUS_OK;
953 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
955 return b->flags;
958 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
959 uint32_t additional,
960 uint32_t clear)
963 * TODO: in future we may want to reject invalid combinations
965 b->flags &= ~clear;
966 b->flags |= additional;
968 return NT_STATUS_OK;
971 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
972 struct ndr_syntax_id *syntax)
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;
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;
984 ndr->flags |= LIBNDR_FLAG_NOALIGN;
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);
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);
998 syntax->if_version = if_version;
1000 talloc_free(mem_ctx);
1002 return NT_STATUS_OK;
1005 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
1007 DATA_BLOB blob;
1008 enum ndr_err_code ndr_err;
1009 struct ndr_push *ndr;
1011 ndr = ndr_push_init_ctx(mem_ctx);
1012 if (ndr == NULL) {
1013 return data_blob_null;
1016 ndr->flags |= LIBNDR_FLAG_NOALIGN;
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;
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;
1027 blob = ndr_push_blob(ndr);
1028 talloc_steal(mem_ctx, blob.data);
1029 talloc_free(ndr);
1030 return blob;
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)
1037 DATA_BLOB blob;
1038 struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
1039 enum ndr_err_code ndr_err;
1041 if (ndr == NULL) {
1042 return false;
1045 ndr->flags |= LIBNDR_FLAG_NOALIGN;
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;
1052 blob = ndr_push_blob(ndr);
1053 talloc_steal(mem_ctx, blob.data);
1054 talloc_free(ndr);
1055 *pblob = blob;
1056 return true;
1059 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
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);
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);
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);
1074 case EPM_PROTOCOL_IP:
1075 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
1077 case EPM_PROTOCOL_NCACN:
1078 return NULL;
1080 case EPM_PROTOCOL_NCADG:
1081 return NULL;
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);
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);
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);
1095 case EPM_PROTOCOL_NCALRPC:
1096 return NULL;
1098 case EPM_PROTOCOL_VINES_SPP:
1099 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
1101 case EPM_PROTOCOL_VINES_IPC:
1102 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
1104 case EPM_PROTOCOL_STREETTALK:
1105 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
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);
1111 case EPM_PROTOCOL_NULL:
1112 return NULL;
1114 default:
1115 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1116 break;
1119 return NULL;
1122 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx,
1123 struct epm_floor *epm_floor,
1124 const char *data)
1126 if (data == NULL) {
1127 data = "";
1130 switch (epm_floor->lhs.protocol) {
1131 case EPM_PROTOCOL_TCP:
1132 epm_floor->rhs.tcp.port = atoi(data);
1133 return NT_STATUS_OK;
1135 case EPM_PROTOCOL_UDP:
1136 epm_floor->rhs.udp.port = atoi(data);
1137 return NT_STATUS_OK;
1139 case EPM_PROTOCOL_HTTP:
1140 epm_floor->rhs.http.port = atoi(data);
1141 return NT_STATUS_OK;
1143 case EPM_PROTOCOL_IP:
1144 if (!is_ipaddress_v4(data)) {
1145 data = "0.0.0.0";
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;
1151 case EPM_PROTOCOL_NCACN:
1152 epm_floor->rhs.ncacn.minor_version = 0;
1153 return NT_STATUS_OK;
1155 case EPM_PROTOCOL_NCADG:
1156 epm_floor->rhs.ncadg.minor_version = 0;
1157 return NT_STATUS_OK;
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;
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;
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;
1174 case EPM_PROTOCOL_NCALRPC:
1175 return NT_STATUS_OK;
1177 case EPM_PROTOCOL_VINES_SPP:
1178 epm_floor->rhs.vines_spp.port = atoi(data);
1179 return NT_STATUS_OK;
1181 case EPM_PROTOCOL_VINES_IPC:
1182 epm_floor->rhs.vines_ipc.port = atoi(data);
1183 return NT_STATUS_OK;
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;
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;
1195 case EPM_PROTOCOL_NULL:
1196 return NT_STATUS_OK;
1198 default:
1199 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1200 break;
1203 return NT_STATUS_NOT_SUPPORTED;
1206 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
1208 int i;
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;
1218 /* Unknown transport */
1219 return (unsigned int)-1;
1222 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1224 int i;
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;
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;
1239 if (j == transports[i].num_protocols) {
1240 return transports[i].transport;
1244 /* Unknown transport */
1245 return (unsigned int)-1;
1248 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1250 int i;
1252 for (i=0; i<ARRAY_SIZE(transports); i++) {
1253 if (t == transports[i].transport) {
1254 return transports[i].name;
1257 return NULL;
1260 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1262 size_t i;
1264 if (name == NULL) {
1265 return NCA_UNKNOWN;
1268 for (i=0; i<ARRAY_SIZE(transports);i++) {
1269 if (strcasecmp(name, transports[i].name) == 0) {
1270 return transports[i].transport;
1274 return NCA_UNKNOWN;
1277 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1278 struct epm_tower *tower,
1279 struct dcerpc_binding **b_out)
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;
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.
1293 if (tower->num_floors < 4) {
1294 return NT_STATUS_INVALID_PARAMETER;
1297 status = dcerpc_parse_binding(mem_ctx, "", &b);
1298 if (!NT_STATUS_IS_OK(status)) {
1299 return status;
1302 transport = dcerpc_transport_by_tower(tower);
1303 if (transport == NCA_UNKNOWN) {
1304 talloc_free(b);
1305 return NT_STATUS_NOT_SUPPORTED;
1308 status = dcerpc_binding_set_transport(b, transport);
1309 if (!NT_STATUS_IS_OK(status)) {
1310 talloc_free(b);
1311 return status;
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;
1321 status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
1322 if (!NT_STATUS_IS_OK(status)) {
1323 talloc_free(b);
1324 return status;
1327 /* Ignore floor 1, it contains the NDR version info */
1329 /* Set endpoint */
1330 errno = 0;
1331 if (tower->num_floors >= 4) {
1332 endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
1334 if (errno != 0) {
1335 int saved_errno = errno;
1336 talloc_free(b);
1337 return map_nt_error_from_unix_common(saved_errno);
1340 status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
1341 if (!NT_STATUS_IS_OK(status)) {
1342 talloc_free(b);
1343 return status;
1345 TALLOC_FREE(endpoint);
1347 /* Set network address */
1348 errno = 0;
1349 if (tower->num_floors >= 5) {
1350 host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
1352 if (errno != 0) {
1353 int saved_errno = errno;
1354 talloc_free(b);
1355 return map_nt_error_from_unix_common(saved_errno);
1358 status = dcerpc_binding_set_string_option(b, "host", host);
1359 if (!NT_STATUS_IS_OK(status)) {
1360 talloc_free(b);
1361 return status;
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;
1368 TALLOC_FREE(host);
1370 *b_out = b;
1371 return NT_STATUS_OK;
1374 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1375 const struct dcerpc_binding *b)
1377 struct dcerpc_binding *n;
1378 uint32_t count;
1380 n = talloc_zero(mem_ctx, struct dcerpc_binding);
1381 if (n == NULL) {
1382 return NULL;
1385 n->transport = b->transport;
1386 n->object = b->object;
1387 n->flags = b->flags;
1388 n->assoc_group_id = b->assoc_group_id;
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;
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;
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;
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;
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;
1429 for (count = 0; b->options && b->options[count]; count++);
1431 if (count > 0) {
1432 uint32_t i;
1434 n->options = talloc_array(n, const char *, count + 1);
1435 if (n->options == NULL) {
1436 talloc_free(n);
1437 return NULL;
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;
1447 n->options[count] = NULL;
1450 return n;
1453 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1454 const struct dcerpc_binding *binding,
1455 struct epm_tower *tower)
1457 const enum epm_protocol *protseq = NULL;
1458 int num_protocols = -1, i;
1459 struct ndr_syntax_id abstract_syntax;
1460 NTSTATUS status;
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;
1471 if (num_protocols == -1) {
1472 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1473 return NT_STATUS_UNSUCCESSFUL;
1476 tower->num_floors = 2 + num_protocols;
1477 tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1479 /* Floor 0 */
1480 tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
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);
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;
1492 /* Floor 1 */
1493 tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1495 tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1496 &ndr_transfer_syntax_ndr);
1498 tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
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;
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;
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;
1533 return NT_STATUS_OK;