/* packet-dcerpc-epm.c * Routines for dcerpc endpoint mapper dissection * Copyright 2001, Todd Sabin * * $Id: packet-dcerpc-epm.c,v 1.12 2002/08/02 23:35:48 jmayer Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "packet-dcerpc.h" static int proto_epm = -1; static int hf_epm_opnum = -1; static int hf_epm_inquiry_type = -1; static int hf_epm_object_p = -1; static int hf_epm_object = -1; static int hf_epm_if_id_p = -1; static int hf_epm_if_id = -1; static int hf_epm_ver_maj = -1; static int hf_epm_ver_min = -1; static int hf_epm_ver_opt = -1; static int hf_epm_hnd = -1; static int hf_epm_max_ents = -1; static int hf_epm_num_ents = -1; static int hf_epm_uuid = -1; static int hf_epm_tower_length = -1; static int hf_epm_tower_data = -1; static int hf_epm_max_towers = -1; static int hf_epm_num_towers = -1; static int hf_epm_rc = -1; static int hf_epm_tower_num_floors = -1; static int hf_epm_tower_rhs_len = -1; static int hf_epm_tower_lhs_len = -1; static int hf_epm_tower_proto_id = -1; static gint ett_epm = -1; static gint ett_epm_tower_floor = -1; static e_uuid_t uuid_epm = { 0xe1af8308, 0x5d1f, 0x11c9, { 0x91, 0xa4, 0x08, 0x00, 0x2b, 0x14, 0xa0, 0xfa } }; static guint16 ver_epm = 3; static int epm_dissect_ept_lookup_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { guint32 dummy; offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_inquiry_type, NULL); offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_object_p, &dummy); if (dummy) { offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep, hf_epm_object, NULL); } offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_if_id_p, &dummy); if (dummy) { offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep, hf_epm_if_id, NULL); offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep, hf_epm_ver_maj, NULL); offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep, hf_epm_ver_min, NULL); } offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_ver_opt, NULL); if (tree) { proto_tree_add_bytes (tree, hf_epm_hnd, tvb, offset, 20, tvb_get_ptr (tvb, offset, 20)); } offset += 20; offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_max_ents, NULL); return offset; } static int epm_dissect_ept_lookup_resp (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep, hf_epm_hnd, NULL); offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_num_ents, NULL); /* FIXME: more to do here */ return offset; } #if 0 static int epm_dissect_uuid (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep, hf_epm_uuid, NULL); return offset; } #endif static const value_string proto_id_vals[] = { { 0x00, "OSI OID"}, { 0x0d, "UUID"}, { 0x05, "OSI TP4"}, { 0x06, "OSI CLNS or DNA Routing"}, { 0x07, "DOD TCP"}, { 0x08, "DOD UDP"}, { 0x09, "DOD IP"}, { 0x0a, "RPC connectionless protocol"}, { 0x0b, "RPC connection-oriented protocol"}, { 0x02, "DNA Session Control"}, { 0x03, "DNA Session Control V3"}, { 0x04, "DNA NSP Transport"}, { 0x10, "Named Pipes"}, { 0x11, "NetBIOS"}, { 0x12, "NetBEUI"}, { 0x13, "Netware SPX"}, { 0x14, "Netware IPX"}, { 0x16, "Appletalk Stream"}, { 0x17, "Appletalk Datagram"}, { 0x18, "Appletalk"}, { 0x19, "NetBIOS"}, { 0x1a, "Vines SPP"}, { 0x1b, "Vines IPC"}, { 0x1c, "StreetTalk"}, { 0x20, "Unix Domain Socket"}, { 0x21, "null"}, { 0x22, "NetBIOS"}, { 0, NULL}, }; /* XXX this function assumes LE encoding. can not use the NDR routines since they assume padding. */ static int epm_dissect_tower_data (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { guint16 num_floors, i; dcerpc_info *di; di=pinfo->private_data; if(di->conformant_run){ return offset; } num_floors = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_epm_tower_num_floors, tvb, offset, 2, num_floors); offset += 2; for(i=1;i<=num_floors;i++){ proto_item *it = NULL; proto_tree *tr = NULL; int old_offset = offset; guint16 len; guint8 proto_id; e_uuid_t uuid; it = proto_tree_add_text(tree, tvb, offset, 0, "Floor %d", i); tr = proto_item_add_subtree(it, ett_epm_tower_floor); len = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tr, hf_epm_tower_lhs_len, tvb, offset, 2, len); offset += 2; proto_id = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tr, hf_epm_tower_proto_id, tvb, offset, 1, proto_id); switch(proto_id){ case 0x0d: /* UUID */ dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid); proto_tree_add_string_format (tr, hf_epm_uuid, tvb, offset, 16, "", "UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid.Data1, uuid.Data2, uuid.Data3, uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3], uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]); proto_tree_add_text(tr, tvb, offset+16, 2, "Version %d.%d", tvb_get_guint8(tvb, offset+17), tvb_get_guint8(tvb, offset+16)); break; } offset += len; len = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tr, hf_epm_tower_rhs_len, tvb, offset, 2, len); offset += 2; switch(proto_id){ case 0x07: /* TCP this one is always big endian */ proto_tree_add_text(tr, tvb, offset, 2, "TCP Port: %d", tvb_get_ntohs(tvb, offset)); break; case 0x08: /* UDP this one is always big endian */ proto_tree_add_text(tr, tvb, offset, 2, "UDP Port: %d", tvb_get_ntohs(tvb, offset)); break; case 0x09: /* IP this one is always big endian */ proto_tree_add_text(tr, tvb, offset, 4, "IP address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4))); break; default: if(len){ proto_tree_add_text(tr, tvb, offset, len, "not decoded yet"); } } offset += len; proto_item_set_len(it, offset-old_offset); } return offset; } /* typedef struct { unsigned int tower_len, [size_is(tower_len)] char tower[]; } twr_t, *twr_p_t; */ static int epm_dissect_tower (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { guint32 len; dcerpc_info *di; di=pinfo->private_data; if(di->conformant_run){ return offset; } /* first one is the header of the conformant array, second one is the length field */ offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_tower_length, &len); offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_tower_length, NULL); offset = epm_dissect_tower_data(tvb, offset, pinfo, tree, drep); return offset; } static int epm_dissect_tower_pointer (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, epm_dissect_tower, NDR_POINTER_PTR, "Tower pointer:", -1, 1); return offset; } static int epm_dissect_tower_array (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, drep, epm_dissect_tower_pointer); return offset; } static int epm_dissect_ept_map_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { /* [in] handle_t h */ offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep, hf_epm_hnd, NULL); #if 0 /* according to opengroup we should have an uuid pointer here. in my w2k captures i can not see any such thing */ /* [in, ptr] uuid_p_t object */ offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, epm_dissect_uuid, NDR_POINTER_PTR, "UUID pointer:", -1, 1); #endif /* [in, ptr] twr_p_t map_tower */ offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, epm_dissect_tower, NDR_POINTER_PTR, "Tower pointer:", -1, 1); /* [in, out] ept_lookup_handle_t *entry_handle */ offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep, hf_epm_hnd, NULL); /* [in] unsigned32 max_towers */ offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_max_towers, NULL); return offset; } static int epm_dissect_ept_map_resp (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep) { /* [in, out] ept_lookup_handle_t *entry_handle */ offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep, hf_epm_hnd, NULL); /* [out, ptr] unsigned32 *num_towers */ offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_num_towers, NULL); /* [out, length_is(*num_towers), size_is(max_towers), ptr] twr_p_t towers[] */ offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, epm_dissect_tower_array, NDR_POINTER_REF, "Tower array:", -1, 1); /* [out] error_status_t *status */ offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep, hf_epm_rc, NULL); return offset; } static dcerpc_sub_dissector epm_dissectors[] = { { 0, "ept_insert", NULL, NULL }, { 1, "ept_delete", NULL, NULL }, { 2, "ept_lookup", epm_dissect_ept_lookup_rqst, epm_dissect_ept_lookup_resp }, { 3, "Map", epm_dissect_ept_map_rqst, epm_dissect_ept_map_resp }, { 4, "ept_lookup_handle_free", NULL, NULL }, { 5, "ept_inq_object", NULL, NULL }, { 6, "ept_mgmt_delete", NULL, NULL }, { 0, NULL, NULL, NULL } }; static const value_string epm_opnum_vals[] = { { 0, "insert" }, { 1, "delete" }, { 2, "lookup" }, { 3, "map" }, { 4, "lookup_handle_free" }, { 5, "inq_object" }, { 6, "mgmt_delete" }, { 0, NULL } }; void proto_register_epm (void) { static hf_register_info hf[] = { { &hf_epm_opnum, { "Operation", "epm.opnum", FT_UINT16, BASE_DEC, VALS(epm_opnum_vals), 0x0, "Operation", HFILL }}, { &hf_epm_inquiry_type, { "Inquiry type", "epm.inq_type", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_object_p, { "Object pointer", "epm.object_p", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_object, { "Object", "epm.object", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_epm_if_id_p, { "Interface pointer", "epm.if_id_p", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_if_id, { "Interface", "epm.if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_epm_ver_maj, { "Version Major", "epm.ver_maj", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_ver_min, { "Version Minor", "epm.ver_min", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_ver_opt, { "Version Option", "epm.ver_opt", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_hnd, { "Handle", "epm.hnd", FT_BYTES, BASE_NONE, NULL, 0x0, "Context handle", HFILL }}, { &hf_epm_max_ents, { "Max entries", "epm.max_ents", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_num_ents, { "Num entries", "epm.num_ents", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_epm_uuid, { "UUID", "epm.uuid", FT_STRING, BASE_NONE, NULL, 0x0, "UUID", HFILL }}, { &hf_epm_tower_length, { "Length", "epm.tower.len", FT_UINT32, BASE_DEC, NULL, 0x0, "Length of tower data", HFILL }}, { &hf_epm_tower_data, { "Tower", "epm.tower", FT_BYTES, BASE_HEX, NULL, 0x0, "Tower data", HFILL }}, { &hf_epm_max_towers, { "Max Towers", "epm.max_towers", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum number of towers to return", HFILL }}, { &hf_epm_num_towers, { "Num Towers", "epm.num_towers", FT_UINT32, BASE_DEC, NULL, 0x0, "Number number of towers to return", HFILL }}, { &hf_epm_rc, { "Return code", "epm.rc", FT_UINT32, BASE_HEX, NULL, 0x0, "EPM return value", HFILL }}, { &hf_epm_tower_num_floors, { "Number of floors", "epm.tower.num_floors", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of floors in tower", HFILL }}, { &hf_epm_tower_rhs_len, { "RHS Length", "epm.tower.rhs.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of RHS data", HFILL }}, { &hf_epm_tower_lhs_len, { "LHS Length", "epm.tower.lhs.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of LHS data", HFILL }}, { &hf_epm_tower_proto_id, { "Protocol", "epm.tower.proto_id", FT_UINT8, BASE_HEX, VALS(proto_id_vals), 0x0, "Protocol identifier", HFILL }} }; static gint *ett[] = { &ett_epm, &ett_epm_tower_floor }; proto_epm = proto_register_protocol ("DCE/RPC Endpoint Mapper", "EPM", "epm"); proto_register_field_array (proto_epm, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); } void proto_reg_handoff_epm (void) { /* Register the protocol as dcerpc */ dcerpc_init_uuid (proto_epm, ett_epm, &uuid_epm, ver_epm, epm_dissectors, hf_epm_opnum); }