From Emanuele Caratti:
add support for multiple encryption keys, one per conversation, in a single capture; add some fields in the accounting dissection. svn path=/trunk/; revision=8734
This commit is contained in:
parent
ec14e0e013
commit
770604ccfa
250
packet-tacacs.c
250
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 ) {
|
||||
|
@ -853,6 +1002,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)
|
||||
{
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue