summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packet-tacacs.c250
-rw-r--r--packet-tacacs.h7
2 files changed, 211 insertions, 46 deletions
diff --git a/packet-tacacs.c b/packet-tacacs.c
index f552b701d3..369f3644e6 100644
--- a/packet-tacacs.c
+++ b/packet-tacacs.c
@@ -5,7 +5,7 @@
* Full Tacacs+ parsing with decryption by
* Emanuele Caratti <wiz@iol.it>
*
- * $Id: packet-tacacs.c,v 1.29 2003/09/29 18:50:47 guy Exp $
+ * $Id: packet-tacacs.c,v 1.30 2003/10/19 17:30:43 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -66,7 +66,8 @@ static int hf_tacacs_result3 = -1;
static gint ett_tacacs = -1;
-static char *tacplus_key;
+static char *tacplus_opt_key;
+static GSList *tacplus_keys = NULL;
#define VERSION_TACACS 0x00
#define VERSION_XTACACS 0x80
@@ -303,6 +304,7 @@ static int hf_tacplus_seqno = -1;
static int hf_tacplus_flags = -1;
static int hf_tacplus_flags_payload_type = -1;
static int hf_tacplus_flags_connection_type = -1;
+static int hf_tacplus_acct_flags = -1;
static int hf_tacplus_session_id = -1;
static int hf_tacplus_packet_len = -1;
@@ -310,27 +312,21 @@ static gint ett_tacplus = -1;
static gint ett_tacplus_body = -1;
static gint ett_tacplus_body_chap = -1;
static gint ett_tacplus_flags = -1;
+static gint ett_tacplus_acct_flags = -1;
-#define FLAGS_UNENCRYPTED 0x01
-
-static const true_false_string payload_type = {
- "Unencrypted",
- "Encrypted"
-};
-
-#define FLAGS_SINGLE 0x04
-
-static const true_false_string connection_type = {
- "Single",
- "Multiple"
-};
+typedef struct _tacplus_key_entry {
+ address *s; /* Server address */
+ address *c; /* client address */
+ char *k; /* Key */
+} tacplus_key_entry;
static gint
-tacplus_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, guint32 len, guint8 version )
+tacplus_decrypted_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, guint32 len, guint8 version, char *key )
{
guint8 *buff;
u_char session_id[4];
+ /* TODO Check the possibility to use pinfo->decrypted_data */
/* session_id is in NETWORK Byte Order, and is used as byte array in the md5_xor */
tvb_memcpy(tvb, (guint8*)session_id, 4,4);
@@ -338,7 +334,7 @@ tacplus_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, guint3
buff = tvb_memdup(tvb, TAC_PLUS_HDR_SIZE, len);
- md5_xor( buff, tacplus_key, len, session_id,version, tvb_get_guint8(tvb,2) );
+ md5_xor( buff, key, len, session_id,version, tvb_get_guint8(tvb,2) );
/* Allocate a new tvbuff, referring to the decrypted data. */
*dst_tvb = tvb_new_real_data( buff, len, len );
@@ -364,9 +360,9 @@ dissect_tacplus_args_list( tvbuff_t *tvb, proto_tree *tree, int data_off, int le
guint8 buff[257];
for(i=0;i<arg_cnt;i++){
int len=tvb_get_guint8(tvb,len_off+i);
- proto_tree_add_text( tree, tvb, len_off+i, 1, "Arg(%d) length: %d", i, len );
+ proto_tree_add_text( tree, tvb, len_off+i, 1, "Arg[%d] length: %d", i, len );
tvb_get_nstringz0(tvb, data_off, len+1, buff);
- proto_tree_add_text( tree, tvb, data_off, len, "Arg(%d) value: %s", i, buff );
+ proto_tree_add_text( tree, tvb, data_off, len, "Arg[%d] value: %s", i, buff );
data_off+=len;
}
}
@@ -385,15 +381,15 @@ proto_tree_add_tacplus_common_fields( tvbuff_t *tvb, proto_tree *tree, int offs
/* authen_type */
val=tvb_get_guint8(tvb,offset);
proto_tree_add_text( tree, tvb, offset, 1,
- "Authentication type: 0x%01x (%s)",
- val, val_to_str( val, tacplus_authen_type_vals, "Unknown Packet" ) );
+ "Authentication type: %s",
+ val_to_str( val, tacplus_authen_type_vals, "Unknown Packet" ) );
offset++;
/* service */
val=tvb_get_guint8(tvb,offset);
proto_tree_add_text( tree, tvb, offset, 1,
- "Service: 0x%01x (%s)",
- val, val_to_str( val, tacplus_authen_service_vals, "Unknown Packet" ) );
+ "Service: %s",
+ val_to_str( val, tacplus_authen_service_vals, "Unknown Packet" ) );
offset++;
/* user_len && user */
@@ -525,7 +521,7 @@ dissect_tacplus_body_authen_req( tvbuff_t* tvb, proto_tree *tree )
val=tvb_get_guint8( tvb, AUTHEN_S_ACTION_OFF );
proto_tree_add_text( tree, tvb,
AUTHEN_S_ACTION_OFF, 1,
- "Action: 0x%01x (%s)", val,
+ "Action: %s",
val_to_str( val, tacplus_authen_action_vals, "Unknown Packet" ) );
var_off=proto_tree_add_tacplus_common_fields( tvb, tree , AUTHEN_S_PRIV_LVL_OFF, AUTHEN_S_VARDATA_OFF );
@@ -616,8 +612,7 @@ dissect_tacplus_body_author_req( tvbuff_t* tvb, proto_tree *tree )
val=tvb_get_guint8( tvb, AUTHOR_Q_AUTH_METH_OFF ) ;
proto_tree_add_text( tree, tvb, AUTHOR_Q_AUTH_METH_OFF, 1,
- "Auth Method: 0x%01x (%s)", val,
- val_to_str( val, tacplus_authen_method, "Unknown Authen Method" ) );
+ "Auth Method: %s", val_to_str( val, tacplus_authen_method, "Unknown Authen Method" ) );
val=tvb_get_guint8( tvb, AUTHOR_Q_ARGC_OFF );
var_off=proto_tree_add_tacplus_common_fields( tvb, tree ,
@@ -662,13 +657,30 @@ dissect_tacplus_body_acct_req( tvbuff_t* tvb, proto_tree *tree )
{
int val, var_off;
+ proto_item *tf;
+ proto_tree *flags_tree;
+
val=tvb_get_guint8( tvb, ACCT_Q_FLAGS_OFF );
- proto_tree_add_text( tree, tvb, ACCT_Q_FLAGS_OFF, 1, "Flags: 0x%04x", val );
+ tf = proto_tree_add_uint( tree, hf_tacplus_acct_flags, tvb, ACCT_Q_FLAGS_OFF, 1, val );
+
+ flags_tree = proto_item_add_subtree( tf, ett_tacplus_acct_flags );
+ proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s",
+ decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_MORE, 8,
+ "More: Set", "More: Not set" ) );
+ proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s",
+ decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_START, 8,
+ "Start: Set", "Start: Not set" ) );
+ proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s",
+ decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_STOP, 8,
+ "Stop: Set", "Stop: Not set" ) );
+ proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s",
+ decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_WATCHDOG, 8,
+ "Watchdog: Set", "Watchdog: Not set" ) );
val=tvb_get_guint8( tvb, ACCT_Q_METHOD_OFF );
proto_tree_add_text( tree, tvb, ACCT_Q_METHOD_OFF, 1,
- "Authen Method: 0x%04x (%s)",
- val, val_to_str( val, tacplus_authen_type_vals, "Unknown Packet" ) );
+ "Authen Method: 0x%01x (%s)",
+ val, val_to_str( val, tacplus_authen_method, "Unknown Authen Method" ) );
val=tvb_get_guint8( tvb, ACCT_Q_ARG_CNT_OFF );
@@ -760,6 +772,137 @@ dissect_tacplus_body(tvbuff_t * hdr_tvb, tvbuff_t * tvb, proto_tree * tree )
proto_tree_add_text( tree, tvb, 0, tvb_length( tvb ), "Bogus..");
}
+#ifdef DEB_TACPLUS
+static void
+tacplus_print_key_entry( gpointer data, gpointer user_data )
+{
+ tacplus_key_entry *tacplus_data=(tacplus_key_entry *)data;
+ if( user_data ) {
+ printf("%s:%s=%s\n", address_to_str( tacplus_data->s ),
+ address_to_str( tacplus_data->c ), tacplus_data->k );
+ } else {
+ printf("%s:%s\n", address_to_str( tacplus_data->s ),
+ address_to_str( tacplus_data->c ) );
+ }
+}
+#endif
+static int
+cmp_conv_address( gconstpointer p1, gconstpointer p2 )
+{
+ tacplus_key_entry *a1=(tacplus_key_entry*)p1;
+ tacplus_key_entry *a2=(tacplus_key_entry*)p2;
+ gint32 ret;
+ /*
+ printf("p1=>");
+ tacplus_print_key_entry( p1, NULL );
+ printf("p2=>");
+ tacplus_print_key_entry( p2, NULL );
+ */
+ ret=CMP_ADDRESS( a1->s, a2->s );
+ if( !ret ) {
+ ret=CMP_ADDRESS( a1->c, a2->c );
+ /*
+ if(ret)
+ printf("No Client found!"); */
+ } else {
+ /* printf("No Server found!"); */
+ }
+ return ret;
+}
+
+static char*
+find_key( address *srv, address *cln )
+{
+ tacplus_key_entry data;
+ GSList *match;
+
+ data.s=srv;
+ data.c=cln;
+/* printf("Looking for: ");
+ tacplus_print_key_entry( (gconstpointer)&data, NULL ); */
+ match=g_slist_find_custom( tacplus_keys, (gpointer)&data, cmp_conv_address );
+/* printf("Finished (%p)\n", match); */
+ if( match )
+ return ((tacplus_key_entry*)match->data)->k;
+
+ return (tacplus_keys?NULL:tacplus_opt_key);
+}
+#define AF_INET 2
+int inet_pton(int , const char*, void*);
+
+static void
+mkipv4_address( address **addr, char *str_addr )
+{
+ *addr=g_malloc( sizeof(address) );
+ (*addr)->type=AT_IPv4;
+ (*addr)->len=4;
+ (*addr)->data=g_malloc( 4 );
+ inet_pton( AF_INET, (const char*)str_addr, (void*)(*addr)->data );
+}
+static void
+parse_tuple( char *key_from_option )
+{
+ char *client,*key;
+ tacplus_key_entry *tacplus_data=g_malloc( sizeof(tacplus_key_entry) );
+ /*
+ printf("keys: %s\n", key_from_option );
+ */
+ client=strchr(key_from_option,'/');
+ if(!client)
+ return;
+ *client++='\0';
+ key=strchr(client,'=');
+ if(!key)
+ return;
+ *key++='\0';
+ /*
+ printf("%s %s => %s\n", key_from_option, client, key );
+ */
+ mkipv4_address( &tacplus_data->s, key_from_option );
+ mkipv4_address( &tacplus_data->c, client );
+ tacplus_data->k=strdup( key );
+ tacplus_keys = g_slist_prepend( tacplus_keys, tacplus_data );
+}
+
+static
+void
+free_tacplus_keys( gpointer data, gpointer user_data _U_ )
+{
+ g_free( ((tacplus_key_entry *)data)->k );
+}
+
+static
+void
+parse_tacplus_keys( char *keys_from_option )
+{
+ char *s1,*s;
+
+ /* Drop old keys */
+ if( tacplus_keys ) {
+ g_slist_foreach( tacplus_keys, free_tacplus_keys, NULL );
+ g_slist_free( tacplus_keys );
+ tacplus_keys=NULL;
+ }
+
+ if( !strchr( keys_from_option, '/' ) ){
+ /* option not in client/server=key format */
+ return ;
+ }
+ s=strdup(keys_from_option);
+ s1=s;
+ keys_from_option = s;
+ while(keys_from_option){
+ if( (s=strchr( keys_from_option, ' ' )) != NULL )
+ *s++='\0';
+ parse_tuple( keys_from_option );
+ keys_from_option=s;
+ }
+ g_free( s1 );
+#ifdef DEB_TACPLUS
+ g_slist_foreach( tacplus_keys, tacplus_print_key_entry, GINT_TO_POINTER(1) );
+#endif
+}
+
static void
dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@@ -771,8 +914,14 @@ dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *tf;
proto_item *tmp_pi;
guint32 len;
- gboolean request=(pinfo->match_port == pinfo->destport);
+ gboolean request=( pinfo->destport == TCP_PORT_TACACS );
+ char *key=NULL;
+ if( request ) {
+ key=find_key( &pinfo->dst, &pinfo->src );
+ } else {
+ key=find_key( &pinfo->src, &pinfo->dst );
+ }
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TACACS+");
@@ -814,12 +963,12 @@ dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
flags = tvb_get_guint8(tvb,3);
tf = proto_tree_add_uint_format(tacplus_tree, hf_tacplus_flags,
tvb, 3, 1, flags,
- "Flags: %s, %s (0x%02x)",
- (flags&FLAGS_UNENCRYPTED) ? "Unencrypted payload" :
- "Encrypted payload",
+ "Flags: 0x%02x (%s payload, %s)",
+ flags,
+ (flags&FLAGS_UNENCRYPTED) ? "Unencrypted" :
+ "Encrypted",
(flags&FLAGS_SINGLE) ? "Single connection" :
- "Multiple Connections",
- flags);
+ "Multiple Connections" );
flags_tree = proto_item_add_subtree(tf, ett_tacplus_flags);
proto_tree_add_boolean(flags_tree, hf_tacplus_flags_payload_type,
tvb, 3, 1, flags);
@@ -838,8 +987,8 @@ dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
new_tvb = tvb_new_subset( tvb, TAC_PLUS_HDR_SIZE, len, len );
} else {
new_tvb=NULL;
- if( tacplus_key && *tacplus_key ){
- tacplus_tvb_setup(tvb,&new_tvb,pinfo,len,version);
+ if( key && *key ){
+ tacplus_decrypted_tvb_setup( tvb, &new_tvb, pinfo, len, version, key );
}
}
if( new_tvb ) {
@@ -854,6 +1003,12 @@ dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
void
+tacplus_pref_cb()
+{
+ parse_tacplus_keys( tacplus_opt_key );
+}
+
+void
proto_register_tacplus(void)
{
static hf_register_info hf[] = {
@@ -886,13 +1041,17 @@ proto_register_tacplus(void)
FT_UINT8, BASE_HEX, NULL, 0x0,
"Flags", HFILL }},
{ &hf_tacplus_flags_payload_type,
- { "Payload type", "tacplus.flags.payload_type",
- FT_BOOLEAN, 8, TFS(&payload_type), FLAGS_UNENCRYPTED,
- "Payload type (unencrypted or encrypted)", HFILL }},
+ { "Unencrypted", "tacplus.flags.unencrypted",
+ FT_BOOLEAN, 8, TFS(&flags_set_truth), FLAGS_UNENCRYPTED,
+ "Is payload unencrypted?", HFILL }},
{ &hf_tacplus_flags_connection_type,
- { "Connection type", "tacplus.flags.connection_type",
- FT_BOOLEAN, 8, TFS(&connection_type), FLAGS_SINGLE,
- "Connection type (single or multiple)", HFILL }},
+ { "Single Connection", "tacplus.flags.singleconn",
+ FT_BOOLEAN, 8, TFS(&flags_set_truth), FLAGS_SINGLE,
+ "Is this a single connection?", HFILL }},
+ { &hf_tacplus_acct_flags,
+ { "Flags", "tacplus.acct.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Flags", HFILL }},
{ &hf_tacplus_session_id,
{ "Session ID", "tacplus.session_id",
FT_UINT32, BASE_DEC, NULL, 0x0,
@@ -905,6 +1064,7 @@ proto_register_tacplus(void)
static gint *ett[] = {
&ett_tacplus,
&ett_tacplus_flags,
+ &ett_tacplus_acct_flags,
&ett_tacplus_body,
&ett_tacplus_body_chap,
};
@@ -913,9 +1073,9 @@ proto_register_tacplus(void)
proto_tacplus = proto_register_protocol("TACACS+", "TACACS+", "tacplus");
proto_register_field_array(proto_tacplus, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- tacplus_module = prefs_register_protocol (proto_tacplus, NULL);
+ tacplus_module = prefs_register_protocol (proto_tacplus, tacplus_pref_cb );
prefs_register_string_preference ( tacplus_module, "key",
- "TACACS+ Encryption Key", "TACACS+ Encryption Key", &tacplus_key );
+ "TACACS+ Encryption Key", "TACACS+ Encryption Key", &tacplus_opt_key );
}
void
diff --git a/packet-tacacs.h b/packet-tacacs.h
index 4525d8b3b1..9f4b8c6120 100644
--- a/packet-tacacs.h
+++ b/packet-tacacs.h
@@ -2,7 +2,7 @@
* Routines for cisco tacplus packet dissection
* Copyright 2000, Emanuele Caratti <wiz@iol.it>
*
- * $Id: packet-tacacs.h,v 1.4 2003/09/29 18:50:47 guy Exp $
+ * $Id: packet-tacacs.h,v 1.5 2003/10/19 17:30:43 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -30,6 +30,11 @@
#define MD5_LEN 16
#define MSCHAP_DIGEST_LEN 49
+enum
+{
+ FLAGS_UNENCRYPTED = 0x01,
+ FLAGS_SINGLE = 0x04
+};
/* Tacacs+ packet type */
enum