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/>.
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"
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
;
43 const char *target_hostname
;
44 const char *target_principal
;
48 uint32_t assoc_group_id
;
49 char assoc_group_string
[11]; /* 0x3456789a + '\0' */
54 enum dcerpc_transport_t transport
;
56 enum epm_protocol protseq
[MAX_PROTSEQ
];
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
{
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
)
113 for (i
=0; i
<ARRAY_SIZE(ncacn_options
); i
++) {
116 ret
= strcasecmp(ncacn_options
[i
].name
, name
);
121 return &ncacn_options
[i
];
127 const char *epm_floor_string(TALLOC_CTX
*mem_ctx
, struct epm_floor
*epm_floor
)
129 struct ndr_syntax_id syntax
;
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 */
139 if (GUID_equal(&syntax
.uuid
, &ndr_transfer_syntax_ndr
.uuid
)) {
143 if (GUID_equal(&syntax
.uuid
, &ndr_transfer_syntax_ndr64
.uuid
)) {
147 uuidstr
= GUID_string(mem_ctx
, &syntax
.uuid
);
149 return talloc_asprintf(mem_ctx
, " uuid %s/0x%02x", uuidstr
, syntax
.if_version
);
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
:
158 case EPM_PROTOCOL_NCADG
:
161 case EPM_PROTOCOL_NCALRPC
:
164 case EPM_PROTOCOL_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
:
185 case EPM_PROTOCOL_SPX
:
188 case EPM_PROTOCOL_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
);
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
, "");
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
);
226 if (!GUID_all_zero(&b
->object
.uuid
)) {
228 s
= talloc_asprintf_append_buffer(s
, "%s@",
229 GUID_string(mem_ctx
, &b
->object
.uuid
));
236 if (t_name
!= NULL
) {
238 s
= talloc_asprintf_append_buffer(s
, "%s:", t_name
);
247 s
= talloc_asprintf_append_buffer(s
, "%s", b
->host
);
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
;
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
) {
280 s
= talloc_asprintf_append_buffer(s
, "[");
288 s
= talloc_asprintf_append_buffer(s
, "%s", b
->endpoint
);
295 for (i
=0;i
<ARRAY_SIZE(ncacn_options
);i
++) {
296 if (!(b
->flags
& ncacn_options
[i
].flag
)) {
301 s
= talloc_asprintf_append_buffer(s
, ",%s", ncacn_options
[i
].name
);
308 if (target_hostname
) {
310 s
= talloc_asprintf_append_buffer(s
, ",target_hostname=%s",
318 if (b
->target_principal
) {
320 s
= talloc_asprintf_append_buffer(s
, ",target_principal=%s",
321 b
->target_principal
);
328 if (b
->assoc_group_id
!= 0) {
330 s
= talloc_asprintf_append_buffer(s
, ",assoc_group_id=0x%08x",
338 for (i
=0;b
->options
&& b
->options
[i
];i
++) {
340 s
= talloc_asprintf_append_buffer(s
, ",%s", b
->options
[i
]);
348 s
= talloc_asprintf_append_buffer(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
)
363 struct dcerpc_binding
*b
;
365 char *options
= NULL
;
370 b
= talloc_zero(mem_ctx
, struct dcerpc_binding
);
372 return NT_STATUS_NO_MEMORY
;
375 _t
= talloc_strdup(b
, _s
);
378 return NT_STATUS_NO_MEMORY
;
387 if (options
[strlen(options
)-1] != ']') {
389 return NT_STATUS_INVALID_PARAMETER_MIX
;
391 options
[strlen(options
)-1] = 0;
396 if (p
&& PTR_DIFF(p
, s
) == 36) { /* 36 is the length of a UUID */
399 status
= dcerpc_binding_set_string_option(b
, "object", s
);
400 if (!NT_STATUS_IS_OK(status
)) {
411 b
->transport
= NCA_UNKNOWN
;
415 status
= dcerpc_binding_set_string_option(b
, "transport", s
);
416 if (!NT_STATUS_IS_OK(status
)) {
425 status
= dcerpc_binding_set_string_option(b
, "host", s
);
426 if (!NT_STATUS_IS_OK(status
)) {
431 b
->target_hostname
= talloc_strdup(b
, b
->host
);
432 if (b
->target_hostname
== NULL
) {
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
, ',');
450 p
= strchr(name
, '=');
458 * If it's not a key=value pair
459 * it might be a ncacn_option
460 * or if it's the first option
463 const struct ncacn_option
*no
= NULL
;
467 no
= ncacn_option_by_name(name
);
471 * we don't allow unknown options
473 return NT_STATUS_INVALID_PARAMETER_MIX
;
477 * This is the endpoint
480 if (strlen(value
) == 0) {
486 status
= dcerpc_binding_set_string_option(b
, name
, value
);
487 if (!NT_STATUS_IS_OK(status
)) {
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
,
506 char *tmp
= discard_const_p(char, b
->object_string
);
508 if (GUID_all_zero(&object
)) {
510 b
->object_string
= NULL
;
511 ZERO_STRUCT(b
->object
);
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
;
522 ZERO_STRUCT(b
->object
);
523 b
->object
.uuid
= object
;
527 _PUBLIC_
enum dcerpc_transport_t
dcerpc_binding_get_transport(const struct dcerpc_binding
*b
)
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
541 if (b
->transport
== transport
) {
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
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
;
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
;
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
;
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.
620 _PUBLIC_ NTSTATUS
dcerpc_binding_set_abstract_syntax(struct dcerpc_binding
*b
,
621 const struct ndr_syntax_id
*syntax
)
627 * For now we just use object, until all callers are fixed.
630 if (syntax
!= NULL
) {
631 object
= syntax
->uuid
;
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
)) {
644 if (syntax
!= NULL
) {
646 * Here we need to reset the whole ndr_syntax_id
647 * structure including the .if_version
655 _PUBLIC_
const char *dcerpc_binding_get_string_option(const struct dcerpc_binding
*b
,
661 #define _SPECIAL(x) { .name = #x, .value = b->x, }
663 { .name
= "object", .value
= b
->object_string
, },
666 _SPECIAL(target_hostname
),
667 _SPECIAL(target_principal
),
670 const struct ncacn_option
*no
= NULL
;
671 size_t name_len
= strlen(name
);
675 ret
= strcmp(name
, "transport");
677 return derpc_transport_string_by_transport(b
->transport
);
680 ret
= strcmp(name
, "assoc_group_id");
682 char *tmp
= discard_const_p(char, b
->assoc_group_string
);
684 if (b
->assoc_group_id
== 0) {
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
);
699 return specials
[i
].value
;
702 no
= ncacn_option_by_name(name
);
704 if (b
->flags
& no
->flag
) {
711 if (b
->options
== 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
);
724 if (o
[name_len
] != '=') {
728 vs
= &o
[name_len
+ 1];
736 _PUBLIC_
char *dcerpc_binding_copy_string_option(TALLOC_CTX
*mem_ctx
,
737 const struct dcerpc_binding
*b
,
740 const char *c
= dcerpc_binding_get_string_option(b
, name
);
748 v
= talloc_strdup(mem_ctx
, c
);
757 _PUBLIC_ NTSTATUS
dcerpc_binding_set_string_option(struct dcerpc_binding
*b
,
764 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
768 _SPECIAL(target_hostname
),
769 _SPECIAL(target_principal
),
772 const struct ncacn_option
*no
= NULL
;
773 size_t name_len
= strlen(name
);
774 const char *opt
= NULL
;
780 * Note: value == NULL, means delete it.
781 * value != NULL means add or reset.
784 ret
= strcmp(name
, "transport");
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");
798 struct GUID uuid
= GUID_zero();
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
)) {
813 return dcerpc_binding_set_object(b
, uuid
);
816 ret
= strcmp(name
, "assoc_group_id");
818 uint32_t assoc_group_id
= 0;
823 ret
= sscanf(value
, "0x%08x%c", &assoc_group_id
, &c
);
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
);
838 tmp
= discard_const_p(char, *specials
[i
].ptr
);
842 *specials
[i
].ptr
= NULL
;
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
;
860 no
= ncacn_option_by_name(name
);
863 b
->flags
&= ~no
->flag
;
867 ret
= strcasecmp(no
->name
, value
);
869 return NT_STATUS_INVALID_PARAMETER_MIX
;
872 b
->flags
|= no
->flag
;
876 for (i
=0; b
->options
&& b
->options
[i
]; i
++) {
877 const char *o
= b
->options
[i
];
879 ret
= strncmp(name
, o
, name_len
);
884 if (o
[name_len
] != '=') {
899 n
= talloc_realloc(b
, b
->options
, const char *, i
+ 2);
901 return NT_STATUS_NO_MEMORY
;
908 tmp
= discard_const_p(char, opt
);
911 for (;b
->options
[i
];i
++) {
912 b
->options
[i
] = b
->options
[i
+1];
918 b
->options
[i
] = talloc_asprintf(b
->options
, "%s=%s",
920 if (b
->options
[i
] == NULL
) {
922 return NT_STATUS_NO_MEMORY
;
928 _PUBLIC_
uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding
*b
)
933 _PUBLIC_ NTSTATUS
dcerpc_binding_set_flags(struct dcerpc_binding
*b
,
938 * TODO: in future we may want to reject invalid combinations
941 b
->flags
|= additional
;
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
);
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
);
980 static DATA_BLOB
dcerpc_floor_pack_lhs_data(TALLOC_CTX
*mem_ctx
, const struct ndr_syntax_id
*syntax
)
983 enum ndr_err_code ndr_err
;
984 struct ndr_push
*ndr
;
986 ndr
= ndr_push_init_ctx(mem_ctx
);
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
);
1008 static bool dcerpc_floor_pack_rhs_if_version_data(
1009 TALLOC_CTX
*mem_ctx
, const struct ndr_syntax_id
*syntax
,
1013 struct ndr_push
*ndr
= ndr_push_init_ctx(mem_ctx
);
1014 enum ndr_err_code ndr_err
;
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
)) {
1027 blob
= ndr_push_blob(ndr
);
1028 talloc_steal(mem_ctx
, blob
.data
);
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
:
1055 case EPM_PROTOCOL_NCADG
:
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
:
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
:
1090 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor
->lhs
.protocol
));
1097 static NTSTATUS
dcerpc_floor_set_rhs_data(TALLOC_CTX
*mem_ctx
,
1098 struct epm_floor
*epm_floor
,
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
)) {
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
;
1174 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor
->lhs
.protocol
));
1178 return NT_STATUS_NOT_SUPPORTED
;
1181 enum dcerpc_transport_t
dcerpc_transport_by_endpoint_protocol(int prot
)
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
)
1201 /* Find a transport that matches this tower */
1202 for (i
=0;i
<ARRAY_SIZE(transports
);i
++) {
1204 if (transports
[i
].num_protocols
!= tower
->num_floors
- 2) {
1208 for (j
= 0; j
< transports
[i
].num_protocols
; j
++) {
1209 if (transports
[i
].protseq
[j
] != tower
->floors
[j
+2].lhs
.protocol
) {
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
)
1227 for (i
=0; i
<ARRAY_SIZE(transports
); i
++) {
1228 if (t
== transports
[i
].transport
) {
1229 return transports
[i
].name
;
1235 _PUBLIC_
enum dcerpc_transport_t
dcerpc_transport_by_name(const char *name
)
1243 for (i
=0; i
<ARRAY_SIZE(transports
);i
++) {
1244 if (strcasecmp(name
, transports
[i
].name
) == 0) {
1245 return transports
[i
].transport
;
1252 _PUBLIC_ NTSTATUS
dcerpc_binding_from_tower(TALLOC_CTX
*mem_ctx
,
1253 struct epm_tower
*tower
,
1254 struct dcerpc_binding
**b_out
)
1257 struct dcerpc_binding
*b
;
1258 enum dcerpc_transport_t transport
;
1259 struct ndr_syntax_id abstract_syntax
;
1260 char *endpoint
= 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
)) {
1277 transport
= dcerpc_transport_by_tower(tower
);
1278 if (transport
== NCA_UNKNOWN
) {
1280 return NT_STATUS_NOT_SUPPORTED
;
1283 status
= dcerpc_binding_set_transport(b
, transport
);
1284 if (!NT_STATUS_IS_OK(status
)) {
1289 /* Set abstract syntax */
1290 status
= dcerpc_floor_get_lhs_data(&tower
->floors
[0], &abstract_syntax
);
1291 if (!NT_STATUS_IS_OK(status
)) {
1296 status
= dcerpc_binding_set_abstract_syntax(b
, &abstract_syntax
);
1297 if (!NT_STATUS_IS_OK(status
)) {
1302 /* Ignore floor 1, it contains the NDR version info */
1306 if (tower
->num_floors
>= 4) {
1307 endpoint
= dcerpc_floor_get_rhs_data(b
, &tower
->floors
[3]);
1310 int saved_errno
= errno
;
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
)) {
1320 TALLOC_FREE(endpoint
);
1322 /* Set network address */
1324 if (tower
->num_floors
>= 5) {
1325 host
= dcerpc_floor_get_rhs_data(b
, &tower
->floors
[4]);
1328 int saved_errno
= errno
;
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
)) {
1338 status
= dcerpc_binding_set_string_option(b
, "target_hostname", host
);
1339 if (!NT_STATUS_IS_OK(status
)) {
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
;
1355 n
= talloc_zero(mem_ctx
, struct dcerpc_binding
);
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
) {
1372 if (b
->host
!= NULL
) {
1373 n
->host
= talloc_strdup(n
, b
->host
);
1374 if (n
->host
== NULL
) {
1380 if (b
->target_hostname
!= NULL
) {
1381 n
->target_hostname
= talloc_strdup(n
, b
->target_hostname
);
1382 if (n
->target_hostname
== NULL
) {
1388 if (b
->target_principal
!= NULL
) {
1389 n
->target_principal
= talloc_strdup(n
, b
->target_principal
);
1390 if (n
->target_principal
== NULL
) {
1396 if (b
->endpoint
!= NULL
) {
1397 n
->endpoint
= talloc_strdup(n
, b
->endpoint
);
1398 if (n
->endpoint
== NULL
) {
1404 for (count
= 0; b
->options
&& b
->options
[count
]; count
++);
1409 n
->options
= talloc_array(n
, const char *, count
+ 1);
1410 if (n
->options
== 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
) {
1422 n
->options
[count
] = NULL
;
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
;
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
;
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
);
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
,
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
;
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
],
1483 if (!NT_STATUS_IS_OK(status
)) {
1488 /* The 4th floor contains the endpoint */
1489 if (num_protocols
>= 2 && binding
->endpoint
) {
1490 status
= dcerpc_floor_set_rhs_data(tower
->floors
,
1493 if (!NT_STATUS_IS_OK(status
)) {
1498 /* The 5th contains the network address */
1499 if (num_protocols
>= 3 && binding
->host
) {
1500 status
= dcerpc_floor_set_rhs_data(tower
->floors
,
1503 if (!NT_STATUS_IS_OK(status
)) {
1508 return NT_STATUS_OK
;