X-Git-Url: http://git.samba.org/?p=samba.git;a=blobdiff_plain;f=source4%2Flibrpc%2Frpc%2Fdcerpc_util.c;h=7b753d1b3070a9dfaf9b762d5bbdf5e8d793115b;hp=ccb7f126eabaee7cc0d0edaff149009ecff1b087;hb=4a3ca96fb44a62867ef565d1eeb6c0a16418e505;hpb=06fe5d6cd92bbf87f80c3df305d136760d0f91d8 diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index ccb7f126eab..7b753d1b307 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -22,124 +22,19 @@ */ #include "includes.h" - -/* - work out what TCP port to use for a given interface on a given host -*/ -NTSTATUS dcerpc_epm_map_tcp_port(const char *server, - const char *uuid, uint_t version, - uint32_t *port) -{ - struct dcerpc_pipe *p; - NTSTATUS status; - struct epm_Map r; - struct policy_handle handle; - struct GUID guid; - struct epm_twr_t twr, *twr_r; - - if (strcasecmp(uuid, DCERPC_EPMAPPER_UUID) == 0 || - strcasecmp(uuid, DCERPC_MGMT_UUID) == 0) { - /* don't lookup epmapper via epmapper! */ - *port = EPMAPPER_PORT; - return NT_STATUS_OK; - } - - status = dcerpc_pipe_open_tcp(&p, server, EPMAPPER_PORT, AF_UNSPEC ); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* we can use the pipes memory context here as we will have a short - lived connection */ - status = dcerpc_bind_byuuid(p, p, - DCERPC_EPMAPPER_UUID, - DCERPC_EPMAPPER_VERSION); - if (!NT_STATUS_IS_OK(status)) { - dcerpc_pipe_close(p); - return status; - } - - ZERO_STRUCT(handle); - ZERO_STRUCT(guid); - - twr.towers.num_floors = 5; - twr.towers.floors = talloc(p, sizeof(twr.towers.floors[0]) * 5); - - /* what I'd like for christmas ... */ - - /* an RPC interface ... */ - twr.towers.floors[0].lhs.protocol = EPM_PROTOCOL_UUID; - GUID_from_string(uuid, &twr.towers.floors[0].lhs.info.uuid.uuid); - twr.towers.floors[0].lhs.info.uuid.version = version; - twr.towers.floors[0].rhs.uuid.unknown = 0; - - /* encoded with NDR ... */ - twr.towers.floors[1].lhs.protocol = EPM_PROTOCOL_UUID; - GUID_from_string(NDR_GUID, &twr.towers.floors[1].lhs.info.uuid.uuid); - twr.towers.floors[1].lhs.info.uuid.version = NDR_GUID_VERSION; - twr.towers.floors[1].rhs.uuid.unknown = 0; - - /* on an RPC connection ... */ - twr.towers.floors[2].lhs.protocol = EPM_PROTOCOL_NCACN; - twr.towers.floors[2].lhs.info.lhs_data = data_blob(NULL, 0); - twr.towers.floors[2].rhs.ncacn.minor_version = 0; - - /* on a TCP port ... */ - twr.towers.floors[3].lhs.protocol = EPM_PROTOCOL_TCP; - twr.towers.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); - twr.towers.floors[3].rhs.tcp.port = 0; - - /* on an IP link ... */ - twr.towers.floors[4].lhs.protocol = EPM_PROTOCOL_IP; - twr.towers.floors[4].lhs.info.lhs_data = data_blob(NULL, 0); - twr.towers.floors[4].rhs.ip.address = 0; - - /* with some nice pretty paper around it of course */ - r.in.object = &guid; - r.in.map_tower = &twr; - r.in.entry_handle = &handle; - r.in.max_towers = 1; - r.out.entry_handle = &handle; - - status = dcerpc_epm_Map(p, p, &r); - if (!NT_STATUS_IS_OK(status)) { - dcerpc_pipe_close(p); - return status; - } - if (r.out.result != 0 || r.out.num_towers != 1) { - dcerpc_pipe_close(p); - return NT_STATUS_PORT_UNREACHABLE; - } - - twr_r = r.out.towers[0].twr; - if (!twr_r) { - dcerpc_pipe_close(p); - return NT_STATUS_PORT_UNREACHABLE; - } - - if (twr_r->towers.num_floors != 5 || - twr_r->towers.floors[3].lhs.protocol != twr.towers.floors[3].lhs.protocol) { - dcerpc_pipe_close(p); - return NT_STATUS_PORT_UNREACHABLE; - } - - *port = twr_r->towers.floors[3].rhs.tcp.port; - - dcerpc_pipe_close(p); - - return NT_STATUS_OK; -} +#include "system/network.h" +#include "librpc/gen_ndr/ndr_epmapper.h" /* find the pipe name for a local IDL interface */ const char *idl_pipe_name(const char *uuid, uint32_t if_version) { - int i; - for (i=0;dcerpc_pipes[i];i++) { - if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 && - dcerpc_pipes[i]->if_version == if_version) { - return dcerpc_pipes[i]->name; + const struct dcerpc_interface_list *l; + for (l=librpc_dcerpc_pipes();l;l=l->next) { + if (strcasecmp(l->table->uuid, uuid) == 0 && + l->table->if_version == if_version) { + return l->table->name; } } return "UNKNOWN"; @@ -150,11 +45,11 @@ const char *idl_pipe_name(const char *uuid, uint32_t if_version) */ int idl_num_calls(const char *uuid, uint32_t if_version) { - int i; - for (i=0;dcerpc_pipes[i];i++) { - if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 && - dcerpc_pipes[i]->if_version == if_version) { - return dcerpc_pipes[i]->num_calls; + const struct dcerpc_interface_list *l; + for (l=librpc_dcerpc_pipes();l;l=l->next){ + if (strcasecmp(l->table->uuid, uuid) == 0 && + l->table->if_version == if_version) { + return l->table->num_calls; } } return -1; @@ -166,10 +61,10 @@ int idl_num_calls(const char *uuid, uint32_t if_version) */ const struct dcerpc_interface_table *idl_iface_by_name(const char *name) { - int i; - for (i=0;dcerpc_pipes[i];i++) { - if (strcasecmp(dcerpc_pipes[i]->name, name) == 0) { - return dcerpc_pipes[i]; + const struct dcerpc_interface_list *l; + for (l=librpc_dcerpc_pipes();l;l=l->next) { + if (strcasecmp(l->table->name, name) == 0) { + return l->table; } } return NULL; @@ -180,17 +75,16 @@ const struct dcerpc_interface_table *idl_iface_by_name(const char *name) */ const struct dcerpc_interface_table *idl_iface_by_uuid(const char *uuid) { - int i; - for (i=0;dcerpc_pipes[i];i++) { - if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0) { - return dcerpc_pipes[i]; + const struct dcerpc_interface_list *l; + for (l=librpc_dcerpc_pipes();l;l=l->next) { + if (strcasecmp(l->table->uuid, uuid) == 0) { + return l->table; } } return NULL; } - /* push a dcerpc_packet into a blob, potentially with auth info */ @@ -210,6 +104,10 @@ NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, ndr->flags |= LIBNDR_FLAG_BIGENDIAN; } + if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) { + ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT; + } + if (auth_info) { pkt->auth_length = auth_info->credentials.length; } else { @@ -233,13 +131,42 @@ NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } +#define MAX_PROTSEQ 10 static const struct { const char *name; enum dcerpc_transport_t transport; -} ncacn_transports[] = { - {"ncacn_np", NCACN_NP}, - {"ncacn_ip_tcp", NCACN_IP_TCP} + 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_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, 2, + { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SPX }, + }, }; static const struct { @@ -249,54 +176,146 @@ static const struct { {"sign", DCERPC_SIGN}, {"seal", DCERPC_SEAL}, {"connect", DCERPC_CONNECT}, + {"spnego", DCERPC_AUTH_SPNEGO}, + {"krb5", DCERPC_AUTH_KRB5}, {"validate", DCERPC_DEBUG_VALIDATE_BOTH}, {"print", DCERPC_DEBUG_PRINT_BOTH}, {"padcheck", DCERPC_DEBUG_PAD_CHECK}, {"bigendian", DCERPC_PUSH_BIGENDIAN} }; +const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *fl) +{ + struct GUID uuid; + uint16_t if_version; + NTSTATUS status; + + switch(fl->lhs.protocol) { + case EPM_PROTOCOL_UUID: + status = dcerpc_floor_get_lhs_data(fl, &uuid, &if_version); + if (NT_STATUS_IS_OK(status)) { + /* lhs is used: UUID */ + char *uuidstr; + + uuidstr = GUID_string(mem_ctx, &uuid); + + if (strcasecmp(uuidstr, NDR_GUID) == 0) { + return "NDR"; + } + + return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, if_version); + } else { /* IPX */ + return talloc_asprintf(mem_ctx, "IPX:%s", + data_blob_hex_string(mem_ctx, &fl->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", fl->rhs.ip.ipaddr); + + case EPM_PROTOCOL_PIPE: + return talloc_asprintf(mem_ctx, "PIPE:%s", fl->rhs.pipe.path); + + case EPM_PROTOCOL_SMB: + return talloc_asprintf(mem_ctx, "SMB:%s", fl->rhs.smb.unc); + + case EPM_PROTOCOL_UNIX_DS: + return talloc_asprintf(mem_ctx, "Unix:%s", fl->rhs.unix_ds.path); + + case EPM_PROTOCOL_NETBIOS: + return talloc_asprintf(mem_ctx, "NetBIOS:%s", fl->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:%d", fl->rhs.http.port); + + case EPM_PROTOCOL_TCP: + return talloc_asprintf(mem_ctx, "TCP:%d", fl->rhs.tcp.port); + + case EPM_PROTOCOL_UDP: + return talloc_asprintf(mem_ctx, "UDP:%d", fl->rhs.udp.port); + + default: + return talloc_asprintf(mem_ctx, "UNK(%02x):", fl->lhs.protocol); + } +} + + /* form a binding string from a binding structure */ const char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b) { - char *s = NULL; + char *s = talloc_strdup(mem_ctx, ""); int i; const char *t_name=NULL; - for (i=0;itransport) { - t_name = ncacn_transports[i].name; + for (i=0;itransport) { + t_name = transports[i].name; } } if (!t_name) { return NULL; } - if (b->object) { - s = talloc_asprintf(mem_ctx, "%s@", GUID_string(mem_ctx, b->object)); + if (!GUID_all_zero(&b->object)) { + s = talloc_asprintf(s, "%s@", + GUID_string(mem_ctx, &b->object)); } - s = talloc_asprintf_append(s, "%s:%s[", t_name, b->host); + s = talloc_asprintf_append(s, "%s:", t_name); if (!s) return NULL; + if (b->host) { + s = talloc_asprintf_append(s, "%s", b->host); + } + + if (!b->endpoint && !b->options && !b->flags) { + return s; + } + + s = talloc_asprintf_append(s, "["); + + if (b->endpoint) { + s = talloc_asprintf_append(s, "%s", b->endpoint); + } + /* this is a *really* inefficent way of dealing with strings, but this is rarely called and the strings are always short, so I don't care */ for (i=0;b->options && b->options[i];i++) { - s = talloc_asprintf(mem_ctx, "%s%s,", s, b->options[i]); + s = talloc_asprintf_append(s, ",%s", b->options[i]); if (!s) return NULL; } + for (i=0;iflags & ncacn_options[i].flag) { - s = talloc_asprintf(mem_ctx, "%s%s,", s, ncacn_options[i].name); + s = talloc_asprintf_append(s, ",%s", ncacn_options[i].name); if (!s) return NULL; } } - if (s[strlen(s)-1] == ',') { - s[strlen(s)-1] = 0; - } - s = talloc_asprintf(mem_ctx, "%s]", s); + + s = talloc_asprintf_append(s, "]"); return s; } @@ -315,9 +334,7 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */ NTSTATUS status; - b->object = talloc_p(mem_ctx, struct GUID); - - status = GUID_from_string(s, b->object); + status = GUID_from_string(s, &b->object); if (NT_STATUS_IS_ERR(status)) { DEBUG(0, ("Failed parsing UUID\n")); @@ -326,9 +343,11 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ s = p + 1; } else { - b->object = NULL; + ZERO_STRUCT(b->object); } + b->object_version = 0; + p = strchr(s, ':'); if (!p) { return NT_STATUS_INVALID_PARAMETER; @@ -339,13 +358,13 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ return NT_STATUS_NO_MEMORY; } - for (i=0;itransport = ncacn_transports[i].transport; + for (i=0;itransport = transports[i].transport; break; } } - if (i==ARRAY_SIZE(ncacn_transports)) { + if (i==ARRAY_SIZE(transports)) { DEBUG(0,("Unknown dcerpc transport '%s'\n", type)); return NT_STATUS_INVALID_PARAMETER; } @@ -371,13 +390,15 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ b->options = NULL; b->flags = 0; + b->endpoint = NULL; if (!options) { return NT_STATUS_OK; } comma_count = count_chars(options, ','); - b->options = talloc_array_p(mem_ctx, const char *, comma_count+2); + + b->options = talloc_array(mem_ctx, const char *, comma_count+2); if (!b->options) { return NT_STATUS_NO_MEMORY; } @@ -406,14 +427,501 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ } } } + + if (b->options[0]) { + /* Endpoint is first option */ + b->endpoint = b->options[0]; + if (strlen(b->endpoint) == 0) b->endpoint = NULL; + + for (i=0;b->options[i];i++) { + b->options[i] = b->options[i+1]; + } + } + + if (b->options[0] == NULL) + b->options = NULL; + + return NT_STATUS_OK; +} + +NTSTATUS dcerpc_floor_get_lhs_data(struct epm_floor *floor, struct GUID *uuid, uint16_t *if_version) +{ + TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data"); + struct ndr_pull *ndr = ndr_pull_init_blob(&floor->lhs.lhs_data, mem_ctx); + NTSTATUS status; + + ndr->flags |= LIBNDR_FLAG_NOALIGN; + + status = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, uuid); + if (NT_STATUS_IS_ERR(status)) { + talloc_free(mem_ctx); + return status; + } + + status = ndr_pull_uint16(ndr, NDR_SCALARS, if_version); + + talloc_free(mem_ctx); + + return status; +} + +DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, struct GUID *uuid, uint32_t if_version) +{ + struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx); + + ndr->flags |= LIBNDR_FLAG_NOALIGN; + + ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, uuid); + ndr_push_uint16(ndr, NDR_SCALARS, if_version); + + return ndr_push_blob(ndr); +} + +const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor) +{ + switch (floor->lhs.protocol) { + case EPM_PROTOCOL_TCP: + if (floor->rhs.tcp.port == 0) return NULL; + return talloc_asprintf(mem_ctx, "%d", floor->rhs.tcp.port); + + case EPM_PROTOCOL_UDP: + if (floor->rhs.udp.port == 0) return NULL; + return talloc_asprintf(mem_ctx, "%d", floor->rhs.udp.port); + + case EPM_PROTOCOL_HTTP: + if (floor->rhs.http.port == 0) return NULL; + return talloc_asprintf(mem_ctx, "%d", floor->rhs.http.port); + + case EPM_PROTOCOL_IP: + return talloc_strdup(mem_ctx, floor->rhs.ip.ipaddr); + + case EPM_PROTOCOL_NCACN: + return NULL; + + case EPM_PROTOCOL_NCADG: + return NULL; + + case EPM_PROTOCOL_SMB: + if (strlen(floor->rhs.smb.unc) == 0) return NULL; + return talloc_strdup(mem_ctx, floor->rhs.smb.unc); + + case EPM_PROTOCOL_PIPE: + if (strlen(floor->rhs.pipe.path) == 0) return NULL; + return talloc_strdup(mem_ctx, floor->rhs.pipe.path); + + case EPM_PROTOCOL_NETBIOS: + if (strlen(floor->rhs.netbios.name) == 0) return NULL; + return talloc_strdup(mem_ctx, floor->rhs.netbios.name); + + case EPM_PROTOCOL_NCALRPC: + return NULL; + + case EPM_PROTOCOL_VINES_SPP: + return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_spp.port); + + case EPM_PROTOCOL_VINES_IPC: + return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_ipc.port); + + case EPM_PROTOCOL_STREETTALK: + return talloc_strdup(mem_ctx, floor->rhs.streettalk.streettalk); + + case EPM_PROTOCOL_UNIX_DS: + if (strlen(floor->rhs.unix_ds.path) == 0) return NULL; + return talloc_strdup(mem_ctx, floor->rhs.unix_ds.path); + + case EPM_PROTOCOL_NULL: + return NULL; + + default: + DEBUG(0,("Unsupported lhs protocol %d\n", floor->lhs.protocol)); + break; + } + + return NULL; +} + +static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor, const char *data) +{ + switch (floor->lhs.protocol) { + case EPM_PROTOCOL_TCP: + floor->rhs.tcp.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_UDP: + floor->rhs.udp.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_HTTP: + floor->rhs.http.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_IP: + floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data); + NT_STATUS_HAVE_NO_MEMORY(floor->rhs.ip.ipaddr); + return NT_STATUS_OK; + + case EPM_PROTOCOL_NCACN: + floor->rhs.ncacn.minor_version = 0; + return NT_STATUS_OK; + + case EPM_PROTOCOL_NCADG: + floor->rhs.ncadg.minor_version = 0; + return NT_STATUS_OK; + + case EPM_PROTOCOL_SMB: + floor->rhs.smb.unc = talloc_strdup(mem_ctx, data); + NT_STATUS_HAVE_NO_MEMORY(floor->rhs.smb.unc); + return NT_STATUS_OK; + + case EPM_PROTOCOL_PIPE: + floor->rhs.pipe.path = talloc_strdup(mem_ctx, data); + NT_STATUS_HAVE_NO_MEMORY(floor->rhs.pipe.path); + return NT_STATUS_OK; + + case EPM_PROTOCOL_NETBIOS: + floor->rhs.netbios.name = talloc_strdup(mem_ctx, data); + NT_STATUS_HAVE_NO_MEMORY(floor->rhs.netbios.name); + return NT_STATUS_OK; + + case EPM_PROTOCOL_NCALRPC: + return NT_STATUS_OK; + + case EPM_PROTOCOL_VINES_SPP: + floor->rhs.vines_spp.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_VINES_IPC: + floor->rhs.vines_ipc.port = atoi(data); + return NT_STATUS_OK; + + case EPM_PROTOCOL_STREETTALK: + floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data); + NT_STATUS_HAVE_NO_MEMORY(floor->rhs.streettalk.streettalk); + return NT_STATUS_OK; + + case EPM_PROTOCOL_UNIX_DS: + floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data); + NT_STATUS_HAVE_NO_MEMORY(floor->rhs.unix_ds.path); + return NT_STATUS_OK; + + case EPM_PROTOCOL_NULL: + return NT_STATUS_OK; + + default: + DEBUG(0,("Unsupported lhs protocol %d\n", floor->lhs.protocol)); + break; + } + + return NT_STATUS_NOT_SUPPORTED; +} + +enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot) +{ + int i; + + /* Find a transport that has 'prot' as 4th protocol */ + for (i=0;i= 2 && + transports[i].protseq[1] == prot) { + return transports[i].transport; + } + } + + /* Unknown transport */ + return -1; +} + +enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower) +{ + int i; + + /* Find a transport that matches this tower */ + for (i=0;inum_floors - 2) { + continue; + } + + for (j = 0; j < transports[i].num_protocols; j++) { + if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) { + break; + } + } + + if (j == transports[i].num_protocols) { + return transports[i].transport; + } + } + + /* Unknown transport */ + return -1; +} + +NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx, struct epm_tower *tower, struct dcerpc_binding *binding) +{ + NTSTATUS status; + + ZERO_STRUCT(binding->object); + binding->options = NULL; + binding->host = NULL; + binding->flags = 0; + + binding->transport = dcerpc_transport_by_tower(tower); + + if (binding->transport == -1) { + return NT_STATUS_NOT_SUPPORTED; + } + + if (tower->num_floors < 1) { + return NT_STATUS_OK; + } + + /* Set object uuid */ + status = dcerpc_floor_get_lhs_data(&tower->floors[0], &binding->object, &binding->object_version); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Error pulling object uuid and version: %s", nt_errstr(status))); + return status; + } + + /* Ignore floor 1, it contains the NDR version info */ + + binding->options = NULL; + + /* Set endpoint */ + if (tower->num_floors >= 4) { + binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]); + } else { + binding->endpoint = NULL; + } + + /* Set network address */ + if (tower->num_floors >= 5) { + binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]); + } + return NT_STATUS_OK; +} + +NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower) +{ + const enum epm_protocol *protseq = NULL; + int num_protocols = -1, i; + struct GUID ndr_guid; + NTSTATUS status; + + /* Find transport */ + for (i=0;itransport) { + protseq = transports[i].protseq; + num_protocols = transports[i].num_protocols; + break; + } + } + + if (num_protocols == -1) { + DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport)); + return NT_STATUS_UNSUCCESSFUL; + } + + tower->num_floors = 2 + num_protocols; + tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors); + + /* Floor 0 */ + tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID; + + tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &binding->object, binding->object_version); + + tower->floors[0].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2); + + /* Floor 1 */ + tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID; + + status = GUID_from_string(NDR_GUID, &ndr_guid); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &ndr_guid, NDR_GUID_VERSION); + + tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2); + + /* Floor 2 to num_protocols */ + for (i = 0; i < num_protocols; i++) { + tower->floors[2 + i].lhs.protocol = protseq[i]; + tower->floors[2 + i].lhs.lhs_data = data_blob_talloc(mem_ctx, NULL, 0); + ZERO_STRUCT(tower->floors[2 + i].rhs); + dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], ""); + } + + /* The 4th floor contains the endpoint */ + if (num_protocols >= 2 && binding->endpoint) { + status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + } + + /* The 5th contains the network address */ + if (num_protocols >= 3 && binding->host) { + status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4], binding->host); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + } + + return NT_STATUS_OK; +} + +NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, + const char *uuid, uint_t version) +{ + struct dcerpc_pipe *p; + NTSTATUS status; + struct epm_Map r; + struct policy_handle handle; + struct GUID guid; + struct epm_twr_t twr, *twr_r; + struct dcerpc_binding epmapper_binding; + const struct dcerpc_interface_table *table = idl_iface_by_uuid(uuid); + int i; + + /* First, check if there is a default endpoint specified in the IDL */ + + if (table) { + struct dcerpc_binding default_binding; + + binding->authservice = talloc_strdup(mem_ctx, table->authservices->names[0]); + + /* Find one of the default pipes for this interface */ + for (i = 0; i < table->endpoints->count; i++) { + status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding); + + if (NT_STATUS_IS_OK(status) && default_binding.transport == binding->transport && default_binding.endpoint) { + binding->endpoint = talloc_strdup(mem_ctx, default_binding.endpoint); + return NT_STATUS_OK; + } + } + } + + + ZERO_STRUCT(epmapper_binding); + epmapper_binding.transport = binding->transport; + epmapper_binding.host = binding->host; + epmapper_binding.options = NULL; + epmapper_binding.flags = 0; + epmapper_binding.endpoint = NULL; + epmapper_binding.authservice = NULL; + status = dcerpc_pipe_connect_b(&p, + &epmapper_binding, + DCERPC_EPMAPPER_UUID, + DCERPC_EPMAPPER_VERSION, + NULL, NULL, NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + ZERO_STRUCT(handle); + ZERO_STRUCT(guid); + + status = GUID_from_string(uuid, &binding->object); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + binding->object_version = version; + + status = dcerpc_binding_build_tower(p, binding, &twr.tower); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + /* with some nice pretty paper around it of course */ + r.in.object = &guid; + r.in.map_tower = &twr; + r.in.entry_handle = &handle; + r.in.max_towers = 1; + r.out.entry_handle = &handle; + + status = dcerpc_epm_Map(p, p, &r); + if (!NT_STATUS_IS_OK(status)) { + dcerpc_pipe_close(p); + return status; + } + if (r.out.result != 0 || r.out.num_towers != 1) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + twr_r = r.out.towers[0].twr; + if (!twr_r) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + if (twr_r->tower.num_floors != twr.tower.num_floors || + twr_r->tower.floors[3].lhs.protocol != twr.tower.floors[3].lhs.protocol) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &twr_r->tower.floors[3]); + + dcerpc_pipe_close(p); + return NT_STATUS_OK; } +/* + perform an authenticated bind if needed +*/ +static NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, + struct dcerpc_binding *binding, + const char *pipe_uuid, + uint32_t pipe_version, + const char *domain, + const char *username, + const char *password) +{ + NTSTATUS status; + p->conn->flags = binding->flags; + + /* remember the binding string for possible secondary connections */ + p->conn->binding_string = dcerpc_binding_string(p, binding); + + if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { + status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, + domain, username, password); + } else if (username && username[0]) { + uint8_t auth_type; + if (binding->flags & DCERPC_AUTH_SPNEGO) { + auth_type = DCERPC_AUTH_TYPE_SPNEGO; + } else if (binding->flags & DCERPC_AUTH_KRB5) { + auth_type = DCERPC_AUTH_TYPE_KRB5; + } else { + auth_type = DCERPC_AUTH_TYPE_NTLMSSP; + } + + status = dcerpc_bind_auth_password(p, pipe_uuid, pipe_version, + domain, username, password, + auth_type, + binding->authservice); + } else { + status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version); + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); + } + return status; +} + + /* open a rpc connection to a rpc pipe on SMB using the binding structure to determine the endpoint and options */ -static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, +static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **pp, struct dcerpc_binding *binding, const char *pipe_uuid, uint32_t pipe_version, @@ -421,109 +929,188 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, const char *username, const char *password) { + struct dcerpc_pipe *p; NTSTATUS status; - BOOL retry; struct smbcli_state *cli; - const char *pipe_name; - TALLOC_CTX *mem_ctx = talloc_init("dcerpc_pipe_connect_ncacn_np"); - - if (!binding->options || !binding->options[0] || !strlen(binding->options[0])) { - const struct dcerpc_interface_table *table = idl_iface_by_uuid(pipe_uuid); - struct dcerpc_binding default_binding; - int i; + const char *pipe_name = NULL; + TALLOC_CTX *tmp_ctx; - if (!table) { - DEBUG(0,("Unknown interface endpoint '%s'\n", pipe_uuid)); - talloc_destroy(mem_ctx); - return NT_STATUS_INVALID_PARAMETER; - } + *pp = NULL; - /* Find one of the default pipes for this interface */ - for (i = 0; i < table->endpoints->count; i++) { - status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding); - - if (NT_STATUS_IS_OK(status) && default_binding.transport == ENDPOINT_SMB) { - pipe_name = default_binding.options[0]; - break; - - } + p = dcerpc_pipe_init(NULL); + if (p == NULL) { + return NT_STATUS_NO_MEMORY; + } + tmp_ctx = talloc_new(p); + + /* Look up identifier using the epmapper */ + if (!binding->endpoint) { + status = dcerpc_epm_map_binding(tmp_ctx, binding, pipe_uuid, pipe_version); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n", + pipe_uuid, nt_errstr(status))); + talloc_free(p); + return status; } - } else { - pipe_name = binding->options[0]; + DEBUG(1,("Mapped to DCERPC/NP pipe %s\n", binding->endpoint)); } + pipe_name = binding->endpoint; + if (!strncasecmp(pipe_name, "/pipe/", 6) || - !strncasecmp(pipe_name, "\\pipe\\", 6)) { - pipe_name+=6; + !strncasecmp(pipe_name, "\\pipe\\", 6)) { + pipe_name += 6; } if (pipe_name[0] != '\\') { - pipe_name = talloc_asprintf(mem_ctx, "\\%s", pipe_name); + pipe_name = talloc_asprintf(tmp_ctx, "\\%s", pipe_name); } - if (!username || !username[0]) { - status = smbcli_full_connection(NULL, &cli, lp_netbios_name(), - binding->host, NULL, - "ipc$", "?????", - "", "", NULL, 0, &retry); + if (!username || !username[0] || + (binding->flags & DCERPC_SCHANNEL_ANY)) { + status = smbcli_full_connection(p->conn, &cli, lp_netbios_name(), + binding->host, + "ipc$", NULL, + "", "", NULL); } else { - status = smbcli_full_connection(NULL, &cli, lp_netbios_name(), - binding->host, NULL, - "ipc$", "?????", - username, domain, - password, 0, &retry); + status = smbcli_full_connection(p->conn, &cli, lp_netbios_name(), + binding->host, + "ipc$", NULL, + username, domain, + password); } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to connect to %s - %s\n", binding->host, nt_errstr(status))); - talloc_destroy(mem_ctx); + talloc_free(p); return status; } - status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name); + status = dcerpc_pipe_open_smb(p->conn, cli->tree, pipe_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to open pipe %s - %s\n", pipe_name, nt_errstr(status))); - smbcli_tdis(cli); - smbcli_shutdown(cli); - talloc_destroy(mem_ctx); - return status; - } + talloc_free(p); + return status; + } - talloc_destroy(mem_ctx); + if (!(binding->flags & DCERPC_AUTH_OPTIONS)) { + username = NULL; + } - /* this ensures that the reference count is decremented so - a pipe close will really close the link */ - talloc_steal(*p, cli); + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(p); + return status; + } - (*p)->flags = binding->flags; + (*pp) = p; + talloc_free(tmp_ctx); - /* remember the binding string for possible secondary connections */ - (*p)->binding_string = dcerpc_binding_string((*p), binding); + return NT_STATUS_OK; +} - if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { - status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version, - domain, username, password); - } else if (username && username[0] && - (binding->flags & (DCERPC_CONNECT|DCERPC_SIGN|DCERPC_SEAL))) { - status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password); - } else { - status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version); +/* open a rpc connection to a rpc pipe on SMP using the binding + structure to determine the endpoint and options */ +static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **pp, + struct dcerpc_binding *binding, + const char *pipe_uuid, + uint32_t pipe_version, + const char *domain, + const char *username, + const char *password) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + TALLOC_CTX *tmp_ctx; + + (*pp) = NULL; + p = dcerpc_pipe_init(NULL); + if (p == NULL) { + return NT_STATUS_NO_MEMORY; + } + tmp_ctx = talloc_new(p); + + /* Look up identifier using the epmapper */ + if (!binding->endpoint) { + status = dcerpc_epm_map_binding(tmp_ctx, binding, pipe_uuid, pipe_version); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to map DCERPC/TCP NCALRPC identifier for '%s' - %s\n", + pipe_uuid, nt_errstr(status))); + talloc_free(p); + return status; + } + DEBUG(1,("Mapped to DCERPC/LRPC identifier %s\n", binding->endpoint)); } + status = dcerpc_pipe_open_pipe(p->conn, binding->endpoint); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); - dcerpc_pipe_close(*p); - *p = NULL; + DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", + binding->endpoint, nt_errstr(status))); + talloc_free(p); + return status; + } + + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(p); return status; } - return NT_STATUS_OK; + (*pp) = p; + talloc_free(tmp_ctx); + + return status; } + /* open a rpc connection to a rpc pipe on SMP using the binding structure to determine the endpoint and options */ -static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, +static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **pp, + struct dcerpc_binding *binding, + const char *pipe_uuid, + uint32_t pipe_version, + const char *domain, + const char *username, + const char *password) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + + (*pp) = NULL; + + if (!binding->endpoint) { + DEBUG(0, ("Path to unix socket not specified\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + p = dcerpc_pipe_init(NULL); + if (p == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = dcerpc_pipe_open_unix_stream(p->conn, binding->endpoint); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to open unix socket %s - %s\n", + binding->endpoint, nt_errstr(status))); + talloc_free(p); + return status; + } + + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(p); + return status; + } + + (*pp) = p; + + return status; +} + +/* open a rpc connection to a rpc pipe on SMP using the binding + structure to determine the endpoint and options */ +static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **pp, struct dcerpc_binding *binding, const char *pipe_uuid, uint32_t pipe_version, @@ -533,50 +1120,47 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, { NTSTATUS status; uint32_t port = 0; + struct dcerpc_pipe *p; + TALLOC_CTX *tmp_ctx; - if (binding->options && binding->options[0] && strlen(binding->options[0])) { - port = atoi(binding->options[0]); + (*pp) = NULL; + + p = dcerpc_pipe_init(NULL); + if (p == NULL) { + return NT_STATUS_NO_MEMORY; } + tmp_ctx = talloc_new(p); - if (port == 0) { - status = dcerpc_epm_map_tcp_port(binding->host, - pipe_uuid, pipe_version, - &port); + if (!binding->endpoint) { + status = dcerpc_epm_map_binding(tmp_ctx, binding, + pipe_uuid, pipe_version); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n", pipe_uuid, nt_errstr(status))); + talloc_free(p); return status; } - DEBUG(1,("Mapped to DCERPC/TCP port %u\n", port)); + DEBUG(1,("Mapped to DCERPC/TCP port %s\n", binding->endpoint)); } - status = dcerpc_pipe_open_tcp(p, binding->host, port, AF_UNSPEC); + port = atoi(binding->endpoint); + + status = dcerpc_pipe_open_tcp(p->conn, binding->host, port); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to connect to %s:%d\n", binding->host, port)); + DEBUG(0,("Failed to connect to %s:%d - %s\n", + binding->host, port, nt_errstr(status))); + talloc_free(p); return status; } - (*p)->flags = binding->flags; - - /* remember the binding string for possible secondary connections */ - (*p)->binding_string = dcerpc_binding_string((*p), binding); - - if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { - status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version, - domain, username, password); - } else if (username && username[0]) { - status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password); - } else { - status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version); - } - + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to uuid %s - %s\n", - pipe_uuid, nt_errstr(status))); - dcerpc_pipe_close(*p); - *p = NULL; + talloc_free(p); return status; } + + (*pp) = p; + talloc_free(tmp_ctx); return status; } @@ -584,7 +1168,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, /* open a rpc connection to a rpc pipe, using the specified binding structure to determine the endpoint and options */ -NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p, +NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **pp, struct dcerpc_binding *binding, const char *pipe_uuid, uint32_t pipe_version, @@ -596,13 +1180,23 @@ NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p, switch (binding->transport) { case NCACN_NP: - status = dcerpc_pipe_connect_ncacn_np(p, binding, pipe_uuid, pipe_version, + status = dcerpc_pipe_connect_ncacn_np(pp, binding, pipe_uuid, pipe_version, domain, username, password); break; case NCACN_IP_TCP: - status = dcerpc_pipe_connect_ncacn_ip_tcp(p, binding, pipe_uuid, pipe_version, + status = dcerpc_pipe_connect_ncacn_ip_tcp(pp, binding, pipe_uuid, pipe_version, domain, username, password); break; + case NCACN_UNIX_STREAM: + status = dcerpc_pipe_connect_ncacn_unix_stream(pp, binding, pipe_uuid, pipe_version, + domain, username, password); + break; + case NCALRPC: + status = dcerpc_pipe_connect_ncalrpc(pp, binding, pipe_uuid, pipe_version, + domain, username, password); + break; + default: + return NT_STATUS_NOT_SUPPORTED; } return status; @@ -611,7 +1205,7 @@ NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p, /* open a rpc connection to a rpc pipe, using the specified string binding to determine the endpoint and options */ -NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p, +NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **pp, const char *binding, const char *pipe_uuid, uint32_t pipe_version, @@ -621,23 +1215,23 @@ NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p, { struct dcerpc_binding b; NTSTATUS status; - TALLOC_CTX *mem_ctx; + TALLOC_CTX *tmp_ctx; - mem_ctx = talloc_init("dcerpc_pipe_connect"); - if (!mem_ctx) return NT_STATUS_NO_MEMORY; + tmp_ctx = talloc_new(NULL); - status = dcerpc_parse_binding(mem_ctx, binding, &b); + status = dcerpc_parse_binding(tmp_ctx, binding, &b); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding)); - talloc_destroy(mem_ctx); + talloc_free(tmp_ctx); return status; } - DEBUG(3,("Using binding %s\n", dcerpc_binding_string(mem_ctx, &b))); + DEBUG(3,("Using binding %s\n", dcerpc_binding_string(tmp_ctx, &b))); - status = dcerpc_pipe_connect_b(p, &b, pipe_uuid, pipe_version, domain, username, password); + status = dcerpc_pipe_connect_b(pp, &b, pipe_uuid, pipe_version, domain, username, password); + + talloc_free(tmp_ctx); - talloc_destroy(mem_ctx); return status; } @@ -657,47 +1251,61 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe * NTSTATUS status = NT_STATUS_INVALID_PARAMETER; struct dcerpc_binding b; - switch (p->transport.transport) { + (*p2) = dcerpc_pipe_init(p); + if (*p2 == NULL) { + return NT_STATUS_NO_MEMORY; + } + + switch (p->conn->transport.transport) { case NCACN_NP: - tree = dcerpc_smb_tree(p); + tree = dcerpc_smb_tree(p->conn); if (!tree) { return NT_STATUS_INVALID_PARAMETER; } - - status = dcerpc_pipe_open_smb(p2, tree, pipe_name); + status = dcerpc_pipe_open_smb((*p2)->conn, tree, pipe_name); break; case NCACN_IP_TCP: - status = dcerpc_parse_binding(p, p->binding_string, &b); + status = dcerpc_parse_binding(p, p->conn->binding_string, &b); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = dcerpc_pipe_open_tcp((*p2)->conn, b.host, atoi(b.endpoint)); + break; + + case NCALRPC: + status = dcerpc_parse_binding(p, p->conn->binding_string, &b); if (!NT_STATUS_IS_OK(status)) { return status; } - b.flags &= ~DCERPC_AUTH_OPTIONS; - status = dcerpc_pipe_connect_ncacn_ip_tcp(p2, &b, pipe_uuid, - pipe_version, NULL, - NULL, NULL); + status = dcerpc_pipe_open_pipe((*p2)->conn, b.endpoint); break; + + default: + return NT_STATUS_NOT_SUPPORTED; } if (!NT_STATUS_IS_OK(status)) { + talloc_free(*p2); return status; } - (*p2)->flags = p->flags; + (*p2)->conn->flags = p->conn->flags; status = dcerpc_bind_auth_none(*p2, pipe_uuid, pipe_version); if (!NT_STATUS_IS_OK(status)) { + talloc_free(*p2); return status; } return NT_STATUS_OK; } -NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p, +NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key) { /* this took quite a few CPU cycles to find ... */ - session_key->data = discard_const_p(char, "SystemLibraryDTC"); + session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC"); session_key->length = 16; return NT_STATUS_OK; } @@ -708,7 +1316,7 @@ NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p, NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key) { - return p->security_state.session_key(p, session_key); + return p->conn->security_state.session_key(p->conn, session_key); } @@ -734,7 +1342,7 @@ void dcerpc_log_packet(const struct dcerpc_interface_table *ndr, if (name == NULL) { return; } - if (!file_exist(name, NULL)) { + if (!file_exist(name)) { if (file_save(name, pkt->data, pkt->length)) { DEBUG(10,("Logged rpc packet to %s\n", name)); } @@ -745,3 +1353,50 @@ void dcerpc_log_packet(const struct dcerpc_interface_table *ndr, } } + + +/* + create a secondary context from a primary connection + + this uses dcerpc_alter_context() to create a new dcerpc context_id +*/ +NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p, + struct dcerpc_pipe **pp2, + const char *pipe_uuid, + uint32_t pipe_version) +{ + NTSTATUS status; + struct dcerpc_pipe *p2; + + p2 = talloc_zero(p, struct dcerpc_pipe); + if (p2 == NULL) { + return NT_STATUS_NO_MEMORY; + } + p2->conn = talloc_reference(p2, p->conn); + + p2->context_id = ++p->conn->next_context_id; + + status = GUID_from_string(pipe_uuid, &p2->syntax.uuid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(p2); + return status; + } + p2->syntax.if_version = pipe_version; + + status = GUID_from_string(NDR_GUID, &p2->transfer_syntax.uuid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(p2); + return status; + } + p2->transfer_syntax.if_version = NDR_GUID_VERSION; + + status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(p2); + return status; + } + + *pp2 = p2; + + return status; +}