Ethereal-dev: [ethereal-dev] ldap dissector
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: nazard@xxxxxxxxxxxxxxx
Date: Tue, 21 Mar 2000 04:19:50 -0500 (EST)
I finally got fed up with the current ldap dissector (it doesn't dissect <g>). I've spent the evening getting up to speed on how to write a dissector, and have produced a first pass at handling the ldap messages. It only handles to following right now bind request bind response search request (partially) search result response but adding the others is fairly easy now. Before I go any further, I'd like to ask for comments on the code. -- Doug Nazar Dragon Computer Consultants Inc. Tel: (416) 708-1578 Fax: (416) 708-8081
/* packet-ldap.c * Routines for ldap packet dissection * * $Id: packet-ldap.c,v 1.2 2000/01/07 22:05:32 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@xxxxxxxx> * 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 <stdio.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif #include <string.h> #include <glib.h> #include "packet.h" #include "packet-ldap.h" static int proto_ldap = -1; static int hf_ldap_length = -1; static int hf_ldap_message_id = -1; static int hf_ldap_message_type = -1; static int hf_ldap_message_length = -1; static int hf_ldap_message_result = -1; static int hf_ldap_message_result_matcheddn = -1; static int hf_ldap_message_result_errormsg = -1; static int hf_ldap_message_result_referral = -1; static int hf_ldap_message_bind_version = -1; static int hf_ldap_message_bind_dn = -1; static int hf_ldap_message_bind_auth = -1; static int hf_ldap_message_bind_auth_password = -1; static int hf_ldap_message_search_base = -1; static int hf_ldap_message_search_scope = -1; static int hf_ldap_message_search_deref = -1; static int hf_ldap_message_search_sizeLimit = -1; static int hf_ldap_message_search_timeLimit = -1; static int hf_ldap_message_search_typesOnly = -1; static gint ett_ldap = -1; static gint ett_ldap_message = -1; static gint ett_ldap_referrals = -1; static value_string msgTypes [] = { {LDAP_REQ_BIND, "Bind Request"}, {LDAP_REQ_UNBIND, "Unbind Request"}, {LDAP_REQ_UNBIND_30, "Unbind Request"}, {LDAP_REQ_SEARCH, "Search Request"}, {LDAP_REQ_MODIFY, "Modify Request"}, {LDAP_REQ_ADD, "Add Request"}, {LDAP_REQ_DELETE, "Delete Request"}, {LDAP_REQ_DELETE_30, "Delete Request"}, {LDAP_REQ_MODRDN, "Modify RDN Request"}, {LDAP_REQ_COMPARE, "Compare Request"}, {LDAP_REQ_ABANDON, "Abandon Request"}, {LDAP_REQ_ABANDON_30, "Abandon Request"}, {LDAP_RES_BIND, "Bind Result"}, {LDAP_RES_SEARCH_ENTRY, "Search Entry"}, {LDAP_RES_SEARCH_RESULT, "Search Result"}, {LDAP_RES_MODIFY, "Modify Result"}, {LDAP_RES_ADD, "Add Result"}, {LDAP_RES_DELETE, "Delete Result"}, {LDAP_RES_MODRDN, "Modify RDN Result"}, {LDAP_RES_COMPARE, "Compare Result"} }; static const char *message_type_str(long messageType) { int count = sizeof(msgTypes) / sizeof(value_string); while (count--) { if (msgTypes[count].value == messageType) return msgTypes[count].strptr; } return "Unknown"; } static int read_length(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf_id, long *len) { long t = 0; const u_char *p = pd + offset; long length = 0; int item_length; length = t = *p++; if (t & 0x80) { t &= 0x7f; length = 0; while (t--) { length <<= 8; length |= *p++; } } if (len) *len = length; item_length = (p - pd) - offset; if (tree) proto_tree_add_item(tree, hf_id, offset, item_length, length); return item_length; } static int read_integer(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf_id, long *i, gboolean override) { int l = 0; const u_char *p = pd + offset; long integer = 0; int item_length; if (*p != LBER_INTEGER && !override) return 0; p++; l = *p++; integer = 0; while (l--) { integer <<= 8; integer |= *p++; } if (i) *i = integer; item_length = (p - pd) - offset; if (tree) proto_tree_add_item(tree, hf_id, offset, item_length, integer); return item_length; } static int read_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hf_id, char **s, gboolean override_type) { int l = 0; const u_char *p = pd + offset; int item_length; char *string; if (*p != LBER_OCTETSTRING && !override_type) return 0; p++; l = *p++; item_length = l + 2; if (l) { string = g_malloc(l + 1); if (string) { memcpy(string, p, l); string[l] = '\0'; if (tree) proto_tree_add_item(tree, hf_id, offset, item_length, string); if (s) *s = string; else g_free(string); } } else { if (tree) proto_tree_add_item(tree, hf_id, offset, item_length, "(null)"); } return item_length; } static int dissect_ldap_result(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { int i = offset; long resultCode = 0; i += read_length(pd, i, fd, tree, hf_ldap_message_length, 0); i += read_integer(pd, i, fd, tree, hf_ldap_message_result, &resultCode, TRUE); i += read_string(pd, i, fd, tree, hf_ldap_message_result_matcheddn, 0, FALSE); i += read_string(pd, i, fd, tree, hf_ldap_message_result_errormsg, 0, FALSE); if (resultCode == 10) /* Referral */ { int start = i; long length; proto_tree *t, *referralTree; i++; i += read_length(pd, i, fd, 0, -1, &length); t = proto_tree_add_text(tree, start, length, "Referral URLs"); referralTree = proto_item_add_subtree(t, ett_ldap_referrals); while (i < (start + length)) { i += read_string(pd, i, fd, referralTree, hf_ldap_message_result_referral, 0, FALSE); } } return i - offset; } static int dissect_ldap_request_bind(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { int i = offset; i += read_length(pd, i, fd, tree, hf_ldap_message_length, 0); i += read_integer(pd, i, fd, tree, hf_ldap_message_bind_version, 0, FALSE); i += read_string(pd, i, fd, tree, hf_ldap_message_bind_dn, 0, FALSE); switch (pd[i]) { case LDAP_AUTH_SIMPLE: case LDAP_AUTH_SIMPLE_30: proto_tree_add_item(tree, hf_ldap_message_bind_auth, i, 1, pd[i]); i += read_string(pd, i, fd, tree, hf_ldap_message_bind_auth_password, 0, TRUE); }; return i - offset; } static int dissect_ldap_response_bind(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { int i = offset; i += dissect_ldap_result(pd, i, fd, tree); return i - offset; } static int dissect_ldap_request_search(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { int i = offset; i += read_length(pd, i, fd, tree, hf_ldap_message_length, 0); i += read_string(pd, i, fd, tree, hf_ldap_message_search_base, 0, FALSE); i += read_integer(pd, i, fd, tree, hf_ldap_message_search_scope, 0, TRUE); i += read_integer(pd, i, fd, tree, hf_ldap_message_search_deref, 0, TRUE); i += read_integer(pd, i, fd, tree, hf_ldap_message_search_sizeLimit, 0, FALSE); i += read_integer(pd, i, fd, tree, hf_ldap_message_search_timeLimit, 0, FALSE); i += read_integer(pd, i, fd, tree, hf_ldap_message_search_typesOnly, 0, TRUE); return i - offset; } static int dissect_ldap_response_search(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { int i = offset; i += dissect_ldap_result(pd, i, fd, tree); return i - offset; } void dissect_ldap(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { proto_tree *ldap_tree = 0, *ti, *msg_tree; long messageLength; long messageId; long messageType; int i = offset; if (tree) { ti = proto_tree_add_item(tree, proto_ldap, offset, END_OF_FRAME, NULL); ldap_tree = proto_item_add_subtree(ti, ett_ldap); } if (pd[i] != LBER_SEQUENCE) { if (tree) proto_tree_add_text(tree, i, 1, "Invalid LDAP packet"); return; } i++; i += read_length(pd, i, fd, ldap_tree, hf_ldap_length, &messageLength); if (messageLength > (pi.captured_len - offset)) { if (tree) proto_tree_add_text(tree, i, END_OF_FRAME, "Sequence length: %li, LDAP packet data length = %i\n", messageLength, pi.captured_len - offset); return; } i += read_integer(pd, i, fd, ldap_tree, hf_ldap_message_id, &messageId, FALSE); messageType = pd[i++]; if (check_col(fd, COL_PROTOCOL)) col_add_str(fd, COL_PROTOCOL, "LDAP"); if (check_col(fd, COL_INFO)) col_add_fstr(fd, COL_INFO, "MsgId=%li MsgType=%s", messageId, message_type_str(messageType)); if (tree) { ti = proto_tree_add_item(ldap_tree, hf_ldap_message_type, i - 1, 1, messageType); msg_tree = proto_item_add_subtree(ti, ett_ldap_message); switch (messageType) { case LDAP_REQ_BIND: dissect_ldap_request_bind(pd, i, fd, msg_tree); break; case LDAP_REQ_SEARCH: dissect_ldap_request_search(pd, i, fd, msg_tree); break; case LDAP_RES_BIND: dissect_ldap_response_bind(pd, i, fd, msg_tree); break; case LDAP_RES_SEARCH_RESULT: dissect_ldap_response_search(pd, i, fd, msg_tree); break; } } } void proto_register_ldap(void) { static value_string result_codes[] = { {0, "Success"}, {1, "Operations error"}, {2, "Protocol error"}, {3, "Time limit exceeded"}, {4, "Size limit exceeded"}, {5, "Compare false"}, {6, "Compare true"}, {7, "Authentication method not supported"}, {8, "Strong authentication required"}, {10, "Referral"}, {11, "Administrative limit exceeded"}, {12, "Unavailable critical extension"}, {13, "Confidentiality required"}, {14, "SASL bind in progress"}, {16, "No such attribute"}, {17, "Undefined attribute type"}, {18, "Inappropriate matching"}, {19, "Constraint violation"}, {20, "Attribute or value exists"}, {21, "Invalid attribute syntax"}, {32, "No such object"}, {33, "Alias problem"}, {34, "Invalid DN syntax"}, {36, "Alias derefetencing problem"}, {48, "Inappropriate authentication"}, {49, "Invalid credentials"}, {50, "Insufficient access rights"}, {51, "Busy"}, {52, "Unavailable"}, {53, "Unwilling to perform"}, {54, "Loop detected"}, {64, "Naming violation"}, {65, "Objectclass violation"}, {66, "Not allowed on non-leaf"}, {67, "Not allowed on RDN"}, {68, "Entry already exists"}, {69, "Objectclass modification prohibited"}, {71, "Affects multiple DSAs"}, {80, "Other"}, }; static value_string auth_types[] = { {LDAP_AUTH_NONE, "None"}, {LDAP_AUTH_SIMPLE, "Simple"}, {LDAP_AUTH_SIMPLE_30, "Simple"}, {LDAP_AUTH_KRBV4, "Kerberos"}, {LDAP_AUTH_KRBV41, "Kerberos V4.1"}, {LDAP_AUTH_KRBV41_30, "Kerberos V4.1"}, {LDAP_AUTH_KRBV42, "Kerberos V4.2"}, {LDAP_AUTH_KRBV42_30, "Kerberos V4.2"}, }; static value_string search_scope[] = { {0x00, "Base"}, {0x01, "Single"}, {0x02, "Subtree"}, }; static value_string search_dereference[] = { {0x00, "Never"}, {0x01, "Searching"}, {0x02, "Base Object"}, {0x03, "Always"}, }; static hf_register_info hf[] = { { &hf_ldap_length, { "Length", "ldap.length", FT_INT32, BASE_DEC, NULL, 0x0, "LDAP Length" }}, { &hf_ldap_message_id, { "Message Id", "ldap.message_id", FT_INT32, BASE_DEC, NULL, 0x0, "LDAP Message Id" }}, { &hf_ldap_message_type, { "Message Type", "ldap.message_type", FT_UINT8, BASE_HEX, &msgTypes, 0x0, "LDAP Message Type" }}, { &hf_ldap_message_length, { "Message Length", "ldap.message_length", FT_INT32, BASE_DEC, NULL, 0x0, "LDAP Message Length" }}, { &hf_ldap_message_result, { "Result Code", "ldap.result.code", FT_INT8, BASE_HEX, result_codes, 0x0, "LDAP Result Code" }}, { &hf_ldap_message_result_matcheddn, { "Matched DN", "ldap.result.matcheddn", FT_STRING, BASE_NONE, NULL, 0x0, "LDAP Result Matched DN" }}, { &hf_ldap_message_result_errormsg, { "Error Message", "ldap.result.errormsg", FT_STRING, BASE_NONE, NULL, 0x0, "LDAP Result Error Message" }}, { &hf_ldap_message_result_referral, { "Referral", "ldap.result.referral", FT_STRING, BASE_NONE, NULL, 0x0, "LDAP Result Referral URL" }}, { &hf_ldap_message_bind_version, { "Version", "ldap.bind.version", FT_INT32, BASE_DEC, NULL, 0x0, "LDAP Bind Version" }}, { &hf_ldap_message_bind_dn, { "DN", "ldap.bind.dn", FT_STRING, BASE_NONE, NULL, 0x0, "LDAP Bind Distinguished Name" }}, { &hf_ldap_message_bind_auth, { "Auth Type", "ldap.bind.auth_type", FT_INT8, BASE_HEX, auth_types, 0x0, "LDAP Bind Auth Type" }}, { &hf_ldap_message_bind_auth_password, { "Password", "ldap.bind.password", FT_STRING, BASE_NONE, NULL, 0x0, "LDAP Bind Password" }}, { &hf_ldap_message_search_base, { "Base DN", "ldap.search.basedn", FT_STRING, BASE_NONE, NULL, 0x0, "LDAP Search Base Distinguished Name" }}, { &hf_ldap_message_search_scope, { "Scope", "ldap.search.scope", FT_UINT8, BASE_HEX, search_scope, 0x0, "LDAP Search Scope" }}, { &hf_ldap_message_search_deref, { "Dereference", "ldap.search.dereference", FT_UINT8, BASE_HEX, search_dereference, 0x0, "LDAP Search Dereference" }}, { &hf_ldap_message_search_sizeLimit, { "Size Limit", "ldap.search.sizelimit", FT_INT32, BASE_DEC, NULL, 0x0, "LDAP Search Size Limit" }}, { &hf_ldap_message_search_timeLimit, { "Time Limit", "ldap.search.timelimit", FT_INT32, BASE_DEC, NULL, 0x0, "LDAP Search Time Limit" }}, { &hf_ldap_message_search_typesOnly, { "Attributes Only", "ldap.search.typesonly", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "LDAP Search Attributes Only" }}, }; static gint *ett[] = { &ett_ldap, &ett_ldap_message, &ett_ldap_referrals, }; proto_ldap = proto_register_protocol("Lightweight Directory Access Protocol", "ldap"); proto_register_field_array(proto_ldap, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); }
/* packet-ldap.h * * $Id: packet-ldap.h,v 1.1 2000/02/15 21:02:32 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@xxxxxxxx> * 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. */ #define LBER_BOOLEAN 0x01L #define LBER_INTEGER 0x02L #define LBER_BITSTRING 0x03L #define LBER_OCTETSTRING 0x04L #define LBER_NULL 0x05L #define LBER_ENUMERATED 0x0aL #define LBER_SEQUENCE 0x30L /* constructed */ #define LBER_SET 0x31L /* constructed */ #define OLD_LBER_SEQUENCE 0x10L /* w/o constructed bit - broken */ #define OLD_LBER_SET 0x11L /* w/o constructed bit - broken */ #define LDAP_REQ_BIND 0x60L /* application + constructed */ #define LDAP_REQ_UNBIND 0x42L /* application + primitive */ #define LDAP_REQ_SEARCH 0x63L /* application + constructed */ #define LDAP_REQ_MODIFY 0x66L /* application + constructed */ #define LDAP_REQ_ADD 0x68L /* application + constructed */ #define LDAP_REQ_DELETE 0x4aL /* application + primitive */ #define LDAP_REQ_MODRDN 0x6cL /* application + constructed */ #define LDAP_REQ_COMPARE 0x6eL /* application + constructed */ #define LDAP_REQ_ABANDON 0x50L /* application + primitive */ #define LDAP_REQ_UNBIND_30 0x62L #define LDAP_REQ_DELETE_30 0x6aL #define LDAP_REQ_ABANDON_30 0x70L #define OLD_LDAP_REQ_BIND 0x00L #define OLD_LDAP_REQ_UNBIND 0x02L #define OLD_LDAP_REQ_SEARCH 0x03L #define OLD_LDAP_REQ_MODIFY 0x06L #define OLD_LDAP_REQ_ADD 0x08L #define OLD_LDAP_REQ_DELETE 0x0aL #define OLD_LDAP_REQ_MODRDN 0x0cL #define OLD_LDAP_REQ_COMPARE 0x0eL #define OLD_LDAP_REQ_ABANDON 0x10L #define LDAP_RES_BIND 0x61L /* application + constructed */ #define LDAP_RES_SEARCH_ENTRY 0x64L /* application + constructed */ #define LDAP_RES_SEARCH_RESULT 0x65L /* application + constructed */ #define LDAP_RES_MODIFY 0x67L /* application + constructed */ #define LDAP_RES_ADD 0x69L /* application + constructed */ #define LDAP_RES_DELETE 0x6bL /* application + constructed */ #define LDAP_RES_MODRDN 0x6dL /* application + constructed */ #define LDAP_RES_COMPARE 0x6fL /* application + constructed */ #define OLD_LDAP_RES_BIND 0x01L #define OLD_LDAP_RES_SEARCH_ENTRY 0x04L #define OLD_LDAP_RES_SEARCH_RESULT 0x05L #define OLD_LDAP_RES_MODIFY 0x07L #define OLD_LDAP_RES_ADD 0x09L #define OLD_LDAP_RES_DELETE 0x0bL #define OLD_LDAP_RES_MODRDN 0x0dL #define OLD_LDAP_RES_COMPARE 0x0fL #define LDAP_AUTH_NONE 0x00L /* no authentication */ #define LDAP_AUTH_SIMPLE 0x80L /* context specific + primitive */ #define LDAP_AUTH_KRBV4 0xffL /* means do both of the following */ #define LDAP_AUTH_KRBV41 0x81L /* context specific + primitive */ #define LDAP_AUTH_KRBV42 0x82L /* context specific + primitive */ #define LDAP_AUTH_SIMPLE_30 0xa0L /* context specific + constructed */ #define LDAP_AUTH_KRBV41_30 0xa1L /* context specific + constructed */ #define LDAP_AUTH_KRBV42_30 0xa2L /* context specific + constructed */ #define OLD_LDAP_AUTH_SIMPLE 0x00L #define OLD_LDAP_AUTH_KRBV4 0x01L #define OLD_LDAP_AUTH_KRBV42 0x02L void dissect_ldap(const u_char *, int, frame_data *, proto_tree *);
- Follow-Ups:
- Re: [ethereal-dev] ldap dissector
- From: Guy Harris
- Re: [ethereal-dev] ldap dissector
- Prev by Date: Re: [ethereal-dev] TCP/UDP protcol dissector lookups
- Next by Date: Re: [ethereal-dev] 0.8.4 this week
- Previous by thread: Re: [ethereal-dev] WIN32 interface list and packet capture patch
- Next by thread: Re: [ethereal-dev] ldap dissector
- Index(es):