/*
Unix SMB/CIFS implementation.
dcerpc utility functions
Copyright (C) Andrew Tridgell 2003
Copyright (C) Jelmer Vernooij 2004
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
Copyright (C) Rafal Szczesniak 2006
Copyright (C) Stefan Metzmacher 2014
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "../../lib/util/util_net.h"
#include "librpc/gen_ndr/ndr_epmapper.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/rpc/dcerpc.h"
#include "rpc_common.h"
#undef strcasecmp
#undef strncasecmp
#define MAX_PROTSEQ 10
struct dcerpc_binding {
enum dcerpc_transport_t transport;
struct GUID object;
const char *object_string;
const char *host;
const char *target_hostname;
const char *target_principal;
const char *endpoint;
const char **options;
uint32_t flags;
uint32_t assoc_group_id;
char assoc_group_string[11]; /* 0x3456789a + '\0' */
};
static const struct {
const char *name;
enum dcerpc_transport_t transport;
int num_protocols;
enum epm_protocol protseq[MAX_PROTSEQ];
} transports[] = {
{ "ncacn_np", NCACN_NP, 3,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
{ "ncacn_ip_tcp", NCACN_IP_TCP, 3,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } },
{ "ncacn_http", NCACN_HTTP, 3,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } },
{ "ncadg_ip_udp", NCACN_IP_UDP, 3,
{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
{ "ncalrpc", NCALRPC, 2,
{ EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_NAMED_PIPE } },
{ "ncacn_unix_stream", NCACN_UNIX_STREAM, 2,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
{ "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2,
{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
{ "ncacn_at_dsp", NCACN_AT_DSP, 3,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
{ "ncadg_at_ddp", NCADG_AT_DDP, 3,
{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
{ "ncacn_vns_ssp", NCACN_VNS_SPP, 3,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
{ "ncacn_vns_ipc", NCACN_VNS_IPC, 3,
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
{ "ncadg_ipx", NCADG_IPX, 2,
{ EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
},
{ "ncacn_spx", NCACN_SPX, 3,
/* I guess some MS programmer confused the identifier for
* EPM_PROTOCOL_UUID (0x0D or 13) with the one for
* EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
},
};
static const struct ncacn_option {
const char *name;
uint32_t flag;
} ncacn_options[] = {
{"sign", DCERPC_SIGN},
{"seal", DCERPC_SEAL},
{"connect", DCERPC_CONNECT},
{"spnego", DCERPC_AUTH_SPNEGO},
{"ntlm", DCERPC_AUTH_NTLM},
{"krb5", DCERPC_AUTH_KRB5},
{"schannel", DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO},
{"validate", DCERPC_DEBUG_VALIDATE_BOTH},
{"print", DCERPC_DEBUG_PRINT_BOTH},
{"padcheck", DCERPC_DEBUG_PAD_CHECK},
{"bigendian", DCERPC_PUSH_BIGENDIAN},
{"smb1", DCERPC_SMB1},
{"smb2", DCERPC_SMB2},
{"ndr64", DCERPC_NDR64},
{"packet", DCERPC_PACKET},
};
static const struct ncacn_option *ncacn_option_by_name(const char *name)
{
size_t i;
for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
int ret;
ret = strcasecmp(ncacn_options[i].name, name);
if (ret != 0) {
continue;
}
return &ncacn_options[i];
}
return NULL;
}
const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
{
struct ndr_syntax_id syntax;
NTSTATUS status;
switch(epm_floor->lhs.protocol) {
case EPM_PROTOCOL_UUID:
status = dcerpc_floor_get_uuid_full(epm_floor, &syntax);
if (NT_STATUS_IS_OK(status)) {
/* lhs is used: UUID */
struct GUID_txt_buf buf;
if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
return "NDR";
}
if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
return "NDR64";
}
return talloc_asprintf(
mem_ctx,
" uuid %s/0x%02x",
GUID_buf_string(&syntax.uuid, &buf),
syntax.if_version);
} else { /* IPX */
return talloc_asprintf(mem_ctx, "IPX:%s",
data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
}
case EPM_PROTOCOL_NCACN:
return "RPC-C";
case EPM_PROTOCOL_NCADG:
return "RPC";
case EPM_PROTOCOL_NCALRPC:
return "NCALRPC";
case EPM_PROTOCOL_DNET_NSP:
return "DNET/NSP";
case EPM_PROTOCOL_IP:
return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
case EPM_PROTOCOL_NAMED_PIPE:
return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
case EPM_PROTOCOL_SMB:
return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
case EPM_PROTOCOL_UNIX_DS:
return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
case EPM_PROTOCOL_NETBIOS:
return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
case EPM_PROTOCOL_NETBEUI:
return "NETBeui";
case EPM_PROTOCOL_SPX:
return "SPX";
case EPM_PROTOCOL_NB_IPX:
return "NB_IPX";
case EPM_PROTOCOL_HTTP:
return talloc_asprintf(mem_ctx, "HTTP:%"PRIu16, epm_floor->rhs.http.port);
case EPM_PROTOCOL_TCP:
return talloc_asprintf(mem_ctx, "TCP:%"PRIu16, epm_floor->rhs.tcp.port);
case EPM_PROTOCOL_UDP:
return talloc_asprintf(mem_ctx, "UDP:%"PRIu16, epm_floor->rhs.udp.port);
default:
return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
}
}
/*
form a binding string from a binding structure
*/
_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
{
char *s = NULL;
size_t i;
const char *t_name = NULL;
bool option_section = false;
const char *target_hostname = NULL;
if (b->transport != NCA_UNKNOWN) {
t_name = derpc_transport_string_by_transport(b->transport);
if (!t_name) {
return NULL;
}
}
s = talloc_strdup(mem_ctx, "");
if (!GUID_all_zero(&b->object)) {
struct GUID_txt_buf buf;
talloc_asprintf_addbuf(
&s, "%s@", GUID_buf_string(&b->object, &buf));
}
if (t_name != NULL) {
talloc_asprintf_addbuf(&s, "%s:", t_name);
}
if (b->host) {
talloc_asprintf_addbuf(&s, "%s", b->host);
}
target_hostname = b->target_hostname;
if (target_hostname != NULL && b->host != NULL) {
if (strcmp(target_hostname, b->host) == 0) {
target_hostname = NULL;
}
}
option_section =
(b->endpoint != NULL) ||
(target_hostname != NULL) ||
(b->target_principal != NULL) ||
(b->assoc_group_id != 0) ||
(b->options != NULL) ||
(b->flags != 0);
if (!option_section) {
return s;
}
talloc_asprintf_addbuf(&s, "[");
if (b->endpoint) {
talloc_asprintf_addbuf(&s, "%s", b->endpoint);
}
for (i=0;i<ARRAY_SIZE(ncacn_options);i+
|