aboutsummaryrefslogtreecommitdiffstats
path: root/packet-ldap.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2002-09-09 23:41:12 +0000
committerGuy Harris <guy@alum.mit.edu>2002-09-09 23:41:12 +0000
commit8b5beb78170d368f910acda6fb96f8751bea3147 (patch)
tree3e7d207763cc9ac840fa919dd473867476a57eda /packet-ldap.c
parent3b0ab19194d89376a306cbd6b89e4d0b264fcf25 (diff)
If we see SASL authentication in a bind request, attach to the
conversation a data structure containing the authentication type and mechanism, and use that to dissect the credentials in subsequent bind responses. Call the bind request and response dissectors regardless of whether we're building a protocol tree or not, so that we call the authentication subdissectors. "read_string()" doesn't return anything through the string-pointer argument if the string is zero-length; handle those cases. svn path=/trunk/; revision=6241
Diffstat (limited to 'packet-ldap.c')
-rw-r--r--packet-ldap.c295
1 files changed, 242 insertions, 53 deletions
diff --git a/packet-ldap.c b/packet-ldap.c
index a2f075b3cd..147d4f2552 100644
--- a/packet-ldap.c
+++ b/packet-ldap.c
@@ -1,7 +1,7 @@
/* packet-ldap.c
* Routines for ldap packet dissection
*
- * $Id: packet-ldap.c,v 1.46 2002/08/28 21:00:19 jmayer Exp $
+ * $Id: packet-ldap.c,v 1.47 2002/09/09 23:41:12 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -56,6 +56,7 @@
#include "packet-ldap.h"
#include "asn1.h"
#include "prefs.h"
+#include <epan/conversation.h>
static int proto_ldap = -1;
static int hf_ldap_length = -1;
@@ -114,6 +115,24 @@ static gboolean ldap_desegment = TRUE;
static dissector_handle_t gssapi_handle;
+/*
+ * Data structure attached to a conversation, giving authentication
+ * information from a bind request.
+ * We keep a linked list of them, so that we can free up all the
+ * authentication mechanism strings.
+ */
+typedef struct ldap_auth_info_t {
+ guint auth_type; /* authentication type */
+ char *auth_mech; /* authentication mechanism */
+ struct ldap_auth_info_t *next;
+} ldap_auth_info_t;
+
+static GMemChunk *ldap_auth_info_chunk = NULL;
+
+static guint ldap_auth_info_chunk_count = 200;
+
+static ldap_auth_info_t *auth_info_items;
+
static value_string msgTypes [] = {
{LDAP_REQ_BIND, "Bind Request"},
{LDAP_REQ_UNBIND, "Unbind Request"},
@@ -801,6 +820,8 @@ static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
int start;
int end;
int ret;
+ conversation_t *conversation;
+ ldap_auth_info_t *auth_info;
char *mechanism;
int token_offset;
gint available_length, reported_length;
@@ -842,11 +863,61 @@ static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
/* For Kerberos V4, dissect it as a ticket. */
case LDAP_AUTH_SASL:
+ mechanism = NULL;
if (read_string(a, tree, hf_ldap_message_bind_auth_mechanism, NULL,
&mechanism, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
return;
+
+ /*
+ * We need to remember the authentication type and mechanism for this
+ * conversation.
+ *
+ * XXX - actually, we might need to remember more than one
+ * type and mechanism, if you can unbind and rebind with a
+ * different type and/or mechanism.
+ */
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ if (conversation == NULL) {
+ /* We don't yet have a conversation, so create one. */
+ conversation = conversation_new(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ }
+
+ /*
+ * Do we already have a type and mechanism?
+ */
+ auth_info = conversation_get_proto_data(conversation, proto_ldap);
+ if (auth_info == NULL) {
+ /* No. Attach that information to the conversation, and add
+ it to the list of information structures. */
+ auth_info = g_mem_chunk_alloc(ldap_auth_info_chunk);
+ auth_info->auth_type = tag;
+ auth_info->auth_mech = mechanism;
+ conversation_add_proto_data(conversation, proto_ldap, auth_info);
+ auth_info->next = auth_info_items;
+ auth_info_items = auth_info;
+ } else {
+ /*
+ * Yes.
+ *
+ * If the mechanism in this request is an empty string (which is
+ * returned as a null pointer), use the saved mechanism instead.
+ * Otherwise, if the saved mechanism is an empty string (null),
+ * save this mechanism.
+ */
+ if (mechanism == NULL)
+ mechanism = auth_info->auth_mech;
+ else {
+ if (auth_info->auth_mech == NULL)
+ auth_info->auth_mech = mechanism;
+ }
+ }
+
if (a->offset < end) {
- if (strcmp(mechanism, "GSS-SPNEGO") == 0) {
+ if (mechanism != NULL && strcmp(mechanism, "GSS-SPNEGO") == 0) {
/*
* This is a GSS-API token.
* Find out how big it is by parsing the ASN.1 header for the
@@ -890,16 +961,93 @@ static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
}
static void dissect_ldap_response_bind(ASN1_SCK *a, proto_tree *tree,
- int start, guint length)
+ int start, guint length, tvbuff_t *tvb, packet_info *pinfo)
{
+ guint cls, con, tag;
+ gboolean def;
+ guint cred_length;
int end;
+ int ret;
+ conversation_t *conversation;
+ ldap_auth_info_t *auth_info;
+ int token_offset;
+ gint available_length, reported_length;
+ tvbuff_t *new_tvb;
+ proto_item *gitem;
+ proto_tree *gtree = NULL;
end = start + length;
dissect_ldap_result(a, tree);
if (a->offset < end) {
- if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
- NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
- return;
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport,
+ pinfo->destport, 0);
+ if (conversation != NULL) {
+ auth_info = conversation_get_proto_data(conversation, proto_ldap);
+ if (auth_info != NULL) {
+ switch (auth_info->auth_type) {
+
+ /* For Kerberos V4, dissect it as a ticket. */
+ /* XXX - what about LDAP_AUTH_SIMPLE? */
+
+ case LDAP_AUTH_SASL:
+ if (auth_info->auth_mech != NULL &&
+ strcmp(auth_info->auth_mech, "GSS-SPNEGO") == 0) {
+ /*
+ * This is a GSS-API token.
+ * Find out how big it is by parsing the ASN.1 header for the
+ * OCTET STREAM that contains it.
+ */
+ token_offset = a->offset;
+ ret = asn1_header_decode(a, &cls, &con, &tag, &def, &cred_length);
+ if (ret != ASN1_ERR_NOERROR) {
+ proto_tree_add_text(tree, a->tvb, token_offset, 0,
+ "%s: ERROR: Couldn't parse header: %s",
+ proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
+ asn1_err_to_str(ret));
+ return;
+ }
+ if (tree) {
+ gitem = proto_tree_add_text(tree, tvb, token_offset,
+ (a->offset + cred_length) - token_offset, "GSS-API Token");
+ gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
+ }
+ available_length = tvb_length_remaining(tvb, token_offset);
+ reported_length = tvb_reported_length_remaining(tvb, token_offset);
+ g_assert(available_length >= 0);
+ g_assert(reported_length >= 0);
+ if (available_length > reported_length)
+ available_length = reported_length;
+ if ((guint)available_length > cred_length)
+ available_length = cred_length;
+ if ((guint)reported_length > cred_length)
+ reported_length = cred_length;
+ new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
+ call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
+ a->offset += cred_length;
+ } else {
+ if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
+ NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
+ return;
+ }
+ break;
+
+ default:
+ if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
+ NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
+ return;
+ break;
+ }
+ } else {
+ if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
+ NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
+ return;
+ }
+ } else {
+ if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
+ NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
+ return;
+ }
}
}
@@ -1084,8 +1232,9 @@ static void dissect_ldap_request_compare(ASN1_SCK *a, proto_tree *tree)
{
int start;
int length;
- char *string1 = 0;
- char *string2 = 0;
+ char *string1 = NULL;
+ char *string2 = NULL;
+ char *s1, *s2;
char *compare;
int ret;
@@ -1119,9 +1268,11 @@ static void dissect_ldap_request_compare(ASN1_SCK *a, proto_tree *tree)
return;
}
- length = 2 + strlen(string1) + strlen(string2);
+ s1 = (string1 == NULL) ? "(null)" : string1;
+ s2 = (string2 == NULL) ? "(null)" : string2;
+ length = 2 + strlen(s1) + strlen(s2);
compare = g_malloc0(length);
- snprintf(compare, length, "%s=%s", string1, string2);
+ snprintf(compare, length, "%s=%s", s1, s2);
proto_tree_add_string(tree, hf_ldap_message_compare, a->tvb, start,
a->offset-start, compare);
@@ -1241,7 +1392,7 @@ static void dissect_ldap_request_abandon(ASN1_SCK *a, proto_tree *tree,
static void
dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- proto_tree *ldap_tree = 0, *ti, *msg_tree;
+ proto_tree *ldap_tree = NULL, *ti, *msg_tree = NULL;
guint messageLength;
guint messageId;
int next_offset;
@@ -1366,65 +1517,80 @@ dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
start, a.offset - start, protocolOpTag);
ti = proto_tree_add_text(ldap_tree, tvb, message_id_start, messageLength, "Message: Id=%u %s", messageId, typestr);
msg_tree = proto_item_add_subtree(ti, ett_ldap_message);
- start = a.offset;
- if (read_length(&a, msg_tree, hf_ldap_message_length, &opLen) != ASN1_ERR_NOERROR)
- return;
+ }
+ start = a.offset;
+ if (read_length(&a, msg_tree, hf_ldap_message_length, &opLen) != ASN1_ERR_NOERROR)
+ return;
- if (protocolOpCls != ASN1_APL)
+ if (protocolOpCls != ASN1_APL)
+ {
+ if (ldap_tree)
{
proto_tree_add_text(msg_tree, a.tvb, a.offset, opLen,
"%s", typestr);
}
- else
+ }
+ else
+ {
+ switch (protocolOpTag)
{
- switch (protocolOpTag)
- {
- case LDAP_REQ_BIND:
- dissect_ldap_request_bind(&a, msg_tree, tvb, pinfo);
- break;
- case LDAP_REQ_UNBIND:
- /* Nothing to dissect */
- break;
- case LDAP_REQ_SEARCH:
+ case LDAP_REQ_BIND:
+ dissect_ldap_request_bind(&a, msg_tree, tvb, pinfo);
+ break;
+ case LDAP_REQ_UNBIND:
+ /* Nothing to dissect */
+ break;
+ case LDAP_REQ_SEARCH:
+ if (ldap_tree)
dissect_ldap_request_search(&a, msg_tree);
- break;
- case LDAP_REQ_MODIFY:
+ break;
+ case LDAP_REQ_MODIFY:
+ if (ldap_tree)
dissect_ldap_request_modify(&a, msg_tree);
- break;
- case LDAP_REQ_ADD:
+ break;
+ case LDAP_REQ_ADD:
+ if (ldap_tree)
dissect_ldap_request_add(&a, msg_tree);
- break;
- case LDAP_REQ_DELETE:
+ break;
+ case LDAP_REQ_DELETE:
+ if (ldap_tree)
dissect_ldap_request_delete(&a, msg_tree, start, opLen);
- break;
- case LDAP_REQ_MODRDN:
+ break;
+ case LDAP_REQ_MODRDN:
+ if (ldap_tree)
dissect_ldap_request_modifyrdn(&a, msg_tree, opLen);
- break;
- case LDAP_REQ_COMPARE:
+ break;
+ case LDAP_REQ_COMPARE:
+ if (ldap_tree)
dissect_ldap_request_compare(&a, msg_tree);
- break;
- case LDAP_REQ_ABANDON:
+ break;
+ case LDAP_REQ_ABANDON:
+ if (ldap_tree)
dissect_ldap_request_abandon(&a, msg_tree, start, opLen);
- break;
- case LDAP_RES_BIND:
- dissect_ldap_response_bind(&a, msg_tree, start, opLen);
- break;
- case LDAP_RES_SEARCH_ENTRY:
+ break;
+ case LDAP_RES_BIND:
+ dissect_ldap_response_bind(&a, msg_tree, start, opLen, tvb, pinfo);
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ if (ldap_tree)
dissect_ldap_response_search_entry(&a, msg_tree);
- break;
- case LDAP_RES_SEARCH_RESULT:
- case LDAP_RES_MODIFY:
- case LDAP_RES_ADD:
- case LDAP_RES_DELETE:
- case LDAP_RES_MODRDN:
- case LDAP_RES_COMPARE:
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ case LDAP_RES_MODIFY:
+ case LDAP_RES_ADD:
+ case LDAP_RES_DELETE:
+ case LDAP_RES_MODRDN:
+ case LDAP_RES_COMPARE:
+ if (ldap_tree)
dissect_ldap_result(&a, msg_tree);
- break;
- default:
+ break;
+ default:
+ if (ldap_tree)
+ {
proto_tree_add_text(msg_tree, a.tvb, a.offset, opLen,
- "Unknown LDAP operation (%u)", protocolOpTag);
- break;
+ "Unknown LDAP operation (%u)", protocolOpTag);
}
+ break;
}
}
@@ -1436,6 +1602,27 @@ dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
+static void
+ldap_reinit(void)
+{
+ ldap_auth_info_t *auth_info;
+
+ /* Free up saved authentication mechanism strings */
+ for (auth_info = auth_info_items; auth_info != NULL;
+ auth_info = auth_info->next) {
+ if (auth_info->auth_mech != NULL)
+ g_free(auth_info->auth_mech);
+ }
+
+ if (ldap_auth_info_chunk != NULL)
+ g_mem_chunk_destroy(ldap_auth_info_chunk);
+
+ ldap_auth_info_chunk = g_mem_chunk_new("ldap_auth_info_chunk",
+ sizeof(ldap_auth_info_t),
+ ldap_auth_info_chunk_count * sizeof(ldap_auth_info_t),
+ G_ALLOC_ONLY);
+}
+
void
proto_register_ldap(void)
{
@@ -1679,6 +1866,8 @@ proto_register_ldap(void)
"Desegment all LDAP messages spanning multiple TCP segments",
"Whether the LDAP dissector should desegment all messages spanning multiple TCP segments",
&ldap_desegment);
+
+ register_init_routine(ldap_reinit);
}
void