From 60d9b40ba4fec876b7288bd51340d6b302af00e3 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 4 Feb 2005 01:32:19 +0000 Subject: r5209: Fix the endpoint mapper to work with IPX endpoints (which accidently have the same protocol id as UUID's) Before this, Samba would give NDR errors when contacting a remote server that has IPX support enabled. This one was on my long due bugs list. (This used to be commit 7b847de64f35b8e897b64ad047d8aea3813214f8) --- source4/gtk/tools/gepdump.c | 5 +- source4/librpc/idl/epmapper.idl | 16 +--- source4/librpc/idl/mgmt.idl | 2 +- source4/librpc/rpc/dcerpc.h | 2 +- source4/librpc/rpc/dcerpc_util.c | 137 +++++++++++++++++++++++++++-- source4/rpc_server/epmapper/rpc_epmapper.c | 17 ++-- source4/torture/rpc/epmapper.c | 104 +++------------------- 7 files changed, 160 insertions(+), 123 deletions(-) (limited to 'source4') diff --git a/source4/gtk/tools/gepdump.c b/source4/gtk/tools/gepdump.c index 4c8595f87c..88cd9ff8b7 100644 --- a/source4/gtk/tools/gepdump.c +++ b/source4/gtk/tools/gepdump.c @@ -96,11 +96,14 @@ static void add_epm_entry(TALLOC_CTX *mem_ctx, const char *annotation, struct ep for (i = 0; i < t->num_floors; i++) { const char *data; + struct GUID if_uuid; + uint16_t if_version; GtkTreeIter iter; gtk_tree_store_append(store_eps, &iter, &toweriter); + dcerpc_floor_get_lhs_data(&t->floors[i], &if_uuid, &if_version); if (t->floors[i].lhs.protocol == EPM_PROTOCOL_UUID) { - data = GUID_string(mem_ctx, &t->floors[i].lhs.info.uuid.uuid); + data = GUID_string(mem_ctx, &if_uuid); } else { data = dcerpc_floor_get_rhs_data(mem_ctx, &t->floors[i]); } diff --git a/source4/librpc/idl/epmapper.idl b/source4/librpc/idl/epmapper.idl index 89c4e246f9..a35b9c47a3 100644 --- a/source4/librpc/idl/epmapper.idl +++ b/source4/librpc/idl/epmapper.idl @@ -36,11 +36,6 @@ interface epmapper const string NDR_GUID = "8a885d04-1ceb-11c9-9fe8-08002b104860"; const string NDR_GUID_VERSION = 2; - typedef struct { - GUID uuid; - uint16 version; - } epm_prot_uuid; - typedef [enum8bit] enum { /* Level 4 and higher */ @@ -73,11 +68,6 @@ interface epmapper EPM_PROTOCOL_NULL = 0x21 } epm_protocol; - typedef [nodiscriminant] union { - [case(EPM_PROTOCOL_UUID)] epm_prot_uuid uuid; - [default] [flag(NDR_REMAINING)] DATA_BLOB lhs_data; - } epm_protocol_info; - typedef struct { /*FIXME */ } epm_rhs_dnet_nsp; @@ -111,7 +101,7 @@ interface epmapper } epm_rhs_ncacn; typedef struct { - uint16 unknown; + [flag(NDR_REMAINING)] DATA_BLOB unknown; } epm_rhs_uuid; typedef struct { @@ -206,8 +196,8 @@ interface epmapper } epm_rhs; typedef struct { - epm_protocol protocol; - [switch_is(protocol)] epm_protocol_info info; + epm_protocol protocol; + [flag(NDR_REMAINING)] DATA_BLOB lhs_data; } epm_lhs; typedef struct { diff --git a/source4/librpc/idl/mgmt.idl b/source4/librpc/idl/mgmt.idl index ac41ff1864..95d39a05a8 100644 --- a/source4/librpc/idl/mgmt.idl +++ b/source4/librpc/idl/mgmt.idl @@ -7,7 +7,7 @@ [ uuid("afa8bd80-7d8a-11c9-bef4-08002b102989"), version(1.0), - endpoint("ncalrpc:", "ncacn_ip_tcp:[135]", "ncacn_np:[\\pipe\\epmapper]"), + endpoint("ncalrpc:[EPMAPPER]", "ncacn_ip_tcp:[135]", "ncacn_np:[\\pipe\\epmapper]"), helpstring("DCE/RPC Remote Management") ] interface mgmt diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 4e0172b6f3..32a03d71a7 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -172,7 +172,7 @@ struct dcerpc_interface_list { struct dcerpc_binding { enum dcerpc_transport_t transport; struct GUID object; - int object_version; + uint16_t object_version; const char *host; const char *endpoint; const char **options; diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index ddc9386c02..2dc9d712b4 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -184,6 +184,80 @@ static const struct { {"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); + } +} /* @@ -370,6 +444,39 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ 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, if_version); + + talloc_free(mem_ctx); + + return status; +} + +DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, struct GUID *uuid, uint32 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, 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) { @@ -552,6 +659,8 @@ enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower) 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; @@ -568,8 +677,12 @@ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx, struct epm_tower *tower, } /* Set object uuid */ - binding->object = tower->floors[0].lhs.info.uuid.uuid; - binding->object_version = tower->floors[0].lhs.info.uuid.version; + 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 */ @@ -593,6 +706,7 @@ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding * { const enum epm_protocol *protseq = NULL; int num_protocols = -1, i; + struct GUID ndr_guid; NTSTATUS status; /* Find transport */ @@ -614,23 +728,28 @@ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding * /* Floor 0 */ tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID; - tower->floors[0].lhs.info.uuid.uuid = binding->object; - tower->floors[0].lhs.info.uuid.version = binding->object_version; - tower->floors[0].rhs.uuid.unknown = 0; + + 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(mem_ctx, NULL, 0); + /* Floor 1 */ tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID; - tower->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION; - tower->floors[1].rhs.uuid.unknown = 0; - status = GUID_from_string(NDR_GUID, &tower->floors[1].lhs.info.uuid.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(mem_ctx, NULL, 0); + /* 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.info.lhs_data = data_blob_talloc(mem_ctx, NULL, 0); + 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], ""); } diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c index eb9598b6be..8a61fc6428 100644 --- a/source4/rpc_server/epmapper/rpc_epmapper.c +++ b/source4/rpc_server/epmapper/rpc_epmapper.c @@ -187,6 +187,8 @@ static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *me struct dcesrv_ep_iface *eps; struct epm_floor *floors; enum dcerpc_transport_t transport; + struct GUID ndr_uuid; + uint16_t ndr_version; count = build_ep_list(mem_ctx, dce_call->conn->dce_ctx->endpoint_list, &eps); @@ -208,9 +210,11 @@ static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *me floors = r->in.map_tower->tower.floors; + dcerpc_floor_get_lhs_data(&r->in.map_tower->tower.floors[1], &ndr_uuid, &ndr_version); + if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID || - guid_cmp(mem_ctx, &floors[1].lhs.info.uuid.uuid, NDR_GUID) != 0 || - floors[1].lhs.info.uuid.version != NDR_GUID_VERSION) { + guid_cmp(mem_ctx, &ndr_uuid, NDR_GUID) != 0 || + ndr_version != NDR_GUID_VERSION) { goto failed; } @@ -226,11 +230,10 @@ static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *me } for (i=0;iin.map_tower->tower.floors[0].lhs.info.uuid.uuid, - &eps[i].ep.floors[0].lhs.info.uuid.uuid) || - r->in.map_tower->tower.floors[0].lhs.info.uuid.version != - eps[i].ep.floors[0].lhs.info.uuid.version || - transport != dcerpc_transport_by_tower(&eps[i].ep)) { + if ( + !data_blob_equal(&r->in.map_tower->tower.floors[0].lhs.lhs_data, + &eps[i].ep.floors[0].lhs.lhs_data) + || transport != dcerpc_transport_by_tower(&eps[i].ep)) { continue; } diff --git a/source4/torture/rpc/epmapper.c b/source4/torture/rpc/epmapper.c index b8cd93a4db..eecfdb3f89 100644 --- a/source4/torture/rpc/epmapper.c +++ b/source4/torture/rpc/epmapper.c @@ -30,90 +30,9 @@ static void display_tower(TALLOC_CTX *mem_ctx, struct epm_tower *twr) { int i; - const char *uuid; for (i=0;inum_floors;i++) { - struct epm_lhs *lhs = &twr->floors[i].lhs; - union epm_rhs *rhs = &twr->floors[i].rhs; - - switch(lhs->protocol) { - case EPM_PROTOCOL_UUID: - uuid = GUID_string(mem_ctx, &lhs->info.uuid.uuid); - if (strcasecmp(uuid, NDR_GUID) == 0) { - printf(" NDR"); - } else { - printf(" uuid %s/0x%02x", uuid, lhs->info.uuid.version); - } - break; - - case EPM_PROTOCOL_NCACN: - printf(" RPC-C"); - break; - - case EPM_PROTOCOL_NCADG: - printf(" RPC"); - break; - - case EPM_PROTOCOL_NCALRPC: - printf(" NCALRPC"); - break; - - case EPM_PROTOCOL_DNET_NSP: - printf(" DNET/NSP"); - break; - - case EPM_PROTOCOL_IP: - printf(" IP:%s", rhs->ip.ipaddr); - break; - - case EPM_PROTOCOL_PIPE: - printf(" PIPE:%s", rhs->pipe.path); - break; - - case EPM_PROTOCOL_SMB: - printf(" SMB:%s", rhs->smb.unc); - break; - - case EPM_PROTOCOL_UNIX_DS: - printf(" Unix:%s", rhs->unix_ds.path); - break; - - case EPM_PROTOCOL_NETBIOS: - printf(" NetBIOS:%s", rhs->netbios.name); - break; - - case EPM_PROTOCOL_NETBEUI: - printf(" NETBeui"); - break; - - case EPM_PROTOCOL_SPX: - printf(" SPX"); - break; - - case EPM_PROTOCOL_NB_IPX: - printf(" NB_IPX"); - break; - - case EPM_PROTOCOL_HTTP: - printf(" HTTP:%d", rhs->http.port); - break; - - case EPM_PROTOCOL_TCP: - /* what is the difference between this and 0x1f? */ - printf(" TCP:%d", rhs->tcp.port); - break; - - case EPM_PROTOCOL_UDP: - printf(" UDP:%d", rhs->udp.port); - break; - - default: - printf(" UNK(%02x):", lhs->protocol); - if (rhs->unknown.length == 2) { - printf("%d", RSVAL(rhs->unknown.data, 0)); - } - break; - } + printf(" %s", epm_floor_string(mem_ctx, &twr->floors[i])); } printf("\n"); } @@ -128,6 +47,8 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *uuid_str; struct policy_handle handle; int i; + struct GUID if_uuid; + uint16_t if_version; ZERO_STRUCT(uuid); ZERO_STRUCT(handle); @@ -138,21 +59,22 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.out.entry_handle = &handle; r.in.max_towers = 100; - uuid_str = GUID_string(mem_ctx, &twr->tower.floors[0].lhs.info.uuid.uuid); + dcerpc_floor_get_lhs_data(&twr->tower.floors[0], &if_uuid, &if_version); + uuid_str = GUID_string(mem_ctx, &if_uuid); printf("epm_Map results for '%s':\n", - idl_pipe_name(uuid_str, twr->tower.floors[0].lhs.info.uuid.version)); + idl_pipe_name(uuid_str, if_version)); twr->tower.floors[2].lhs.protocol = EPM_PROTOCOL_NCACN; - twr->tower.floors[2].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[2].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[2].rhs.ncacn.minor_version = 0; twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_TCP; - twr->tower.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[3].rhs.tcp.port = 0; twr->tower.floors[4].lhs.protocol = EPM_PROTOCOL_IP; - twr->tower.floors[4].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[4].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[4].rhs.ip.ipaddr = "0.0.0.0"; status = dcerpc_epm_Map(p, mem_ctx, &r); @@ -165,7 +87,7 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_HTTP; - twr->tower.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[3].rhs.http.port = 0; status = dcerpc_epm_Map(p, mem_ctx, &r); @@ -178,7 +100,7 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_UDP; - twr->tower.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[3].rhs.http.port = 0; status = dcerpc_epm_Map(p, mem_ctx, &r); @@ -191,11 +113,11 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_SMB; - twr->tower.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[3].rhs.smb.unc = ""; twr->tower.floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS; - twr->tower.floors[4].lhs.info.lhs_data = data_blob(NULL, 0); + twr->tower.floors[4].lhs.lhs_data = data_blob(NULL, 0); twr->tower.floors[4].rhs.netbios.name = ""; status = dcerpc_epm_Map(p, mem_ctx, &r); -- cgit