From Emanuele Caratti: full TACACS+ dissection.

svn path=/trunk/; revision=8506
This commit is contained in:
Guy Harris 2003-09-20 09:41:48 +00:00
parent 211d446ce2
commit 537cce5c82
5 changed files with 952 additions and 20 deletions

View File

@ -1845,6 +1845,10 @@ Kevin A. Noll <knoll [AT] poss.com> {
RFC 2833 RTP Events support
}
Emanuele Caratti <wiz [AT] libero.it> {
Full TACACS+ dissection
}
And assorted fixes and enhancements by the people listed above and by:
Pavel Roskin <proski [AT] gnu.org>

View File

@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
# $Id: Makefile.am,v 1.627 2003/09/20 08:56:56 guy Exp $
# $Id: Makefile.am,v 1.628 2003/09/20 09:41:48 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@ -683,6 +683,7 @@ noinst_HEADERS = \
packet-spray.h \
packet-stat-notify.h \
packet-stat.h \
packet-tacacs.h \
packet-tcp.h \
packet-tns.h \
packet-tpkt.h \

View File

@ -2099,6 +2099,7 @@ B<http://www.ethereal.com>.
Nathan Jennings <njen [AT] bellsouth.net>
Hans Viens <hviens [AT] mediatrix.com>
Kevin A. Noll <knoll [AT] poss.com>
Emanuele Caratti <wiz [AT] libero.it>
Pavel Roskin <proski [AT] gnu.org>
Georgi Guninski <guninski [AT] guninski.com>
Jason Copenhaver <jcopenha [AT] typedef.org>

View File

@ -1,8 +1,11 @@
/* packet-tacacs.c
* Routines for cisco tacacs/xtacacs/tacacs+ packet dissection
* Copyright 2001, Paul Ionescu <paul@acorp.ro>
*
* Full Tacacs+ parsing with decryption by
* Emanuele Caratti <wiz@iol.it>
*
* $Id: packet-tacacs.c,v 1.24 2003/05/15 05:18:17 guy Exp $
* $Id: packet-tacacs.c,v 1.25 2003/09/20 09:41:48 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -27,7 +30,7 @@
/* rfc-1492 for tacacs and xtacacs
* draft-grant-tacacs-00.txt for tacacs+ (tacplus)
* draft-grant-tacacs-02.txt for tacacs+ (tacplus)
*/
#ifdef HAVE_CONFIG_H
@ -40,6 +43,12 @@
#include <glib.h>
#include <epan/packet.h>
#include "prefs.h"
#include "crypt-md5.h"
#include "packet-tacacs.h"
static int md5_xor( u_char *data, char *key, int data_len, guint32 session_id, u_char version, u_char seq_no );
static int proto_tacacs = -1;
static int hf_tacacs_version = -1;
static int hf_tacacs_type = -1;
@ -57,6 +66,8 @@ static int hf_tacacs_result3 = -1;
static gint ett_tacacs = -1;
static char *tacplus_key;
#define VERSION_TACACS 0x00
#define VERSION_XTACACS 0x80
@ -110,10 +121,6 @@ static const value_string tacacs_resp_vals[] = {
{ 0 , NULL }
};
#define TAC_PLUS_AUTHEN 1
#define TAC_PLUS_AUTHOR 2
#define TAC_PLUS_ACCT 3
#define UDP_PORT_TACACS 49
#define TCP_PORT_TACACS 49
@ -300,14 +307,10 @@ static int hf_tacplus_session_id = -1;
static int hf_tacplus_packet_len = -1;
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 const value_string tacplus_type_vals[] = {
{ TAC_PLUS_AUTHEN , "Authentication" },
{ TAC_PLUS_AUTHOR , "Authorization" },
{ TAC_PLUS_ACCT , "Accounting" },
{ 0 , NULL }};
#define FLAGS_UNENCRYPTED 0x01
static const true_false_string payload_type = {
@ -322,14 +325,443 @@ static const true_false_string connection_type = {
"Multiple"
};
static gint
tacplus_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, guint32 len, guint8 version )
{
guint8 *buff;
guint32 tmp_sess;
buff=g_malloc(len);
tvb_memcpy(tvb,(guint8*)&tmp_sess,4,4);
tvb_memcpy(tvb, buff, TAC_PLUS_HDR_SIZE, len);
md5_xor( buff, tacplus_key, len, tmp_sess,version, tvb_get_guint8(tvb,2) );
*dst_tvb = tvb_new_real_data( buff, len, len );
tvb_set_child_real_data_tvbuff( tvb, *dst_tvb );
add_new_data_source(pinfo, *dst_tvb, "TACACS+ Decrypted");
return 0;
}
static void
dissect_tacplus_args_list( tvbuff_t *tvb, proto_tree *tree, int data_off, int len_off, int arg_cnt )
{
int i;
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 );
tvb_get_nstringz0(tvb, data_off, len+1, buff);
proto_tree_add_text( tree, tvb, data_off, len, "Arg(%d) value: %s", i, buff );
data_off+=len;
}
}
static int
proto_tree_add_tacplus_common_fields( tvbuff_t *tvb, proto_tree *tree, int offset, int var_off )
{
int val;
guint8 buff[257];
/* priv_lvl */
proto_tree_add_text( tree, tvb, offset, 1,
"Privilege Level: %d", tvb_get_guint8(tvb,offset) );
offset++;
/* 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" ) );
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" ) );
offset++;
/* user_len && user */
val=tvb_get_guint8(tvb,offset);
proto_tree_add_text( tree, tvb, offset, 1, "User len: %d", val );
if( val ){
tvb_get_nstringz0(tvb, var_off, val+1, buff);
proto_tree_add_text( tree, tvb, var_off, val, "User: %s", buff );
var_off+=val;
}
offset++;
/* port_len && port */
val=tvb_get_guint8(tvb,offset);
proto_tree_add_text( tree, tvb, offset, 1, "Port len: %d", val );
if( val ){
tvb_get_nstringz0(tvb, var_off, val+1, buff);
proto_tree_add_text( tree, tvb, var_off, val, "Port: %s", buff );
var_off+=val;
}
offset++;
/* rem_addr_len && rem_addr */
val=tvb_get_guint8(tvb,offset);
proto_tree_add_text( tree, tvb, offset, 1, "Remaddr len: %d", val );
if( val ){
tvb_get_nstringz0(tvb, var_off, val+1, buff);
proto_tree_add_text( tree, tvb, var_off, val, "Remote Address: %s", buff );
var_off+=val;
}
return var_off;
}
static void
dissect_tacplus_body_authen_req_login( tvbuff_t* tvb, proto_tree *tree, int var_off )
{
guint8 buff[257];
guint8 val;
val=tvb_get_guint8( tvb, AUTHEN_S_DATA_LEN_OFF );
switch ( tvb_get_guint8(tvb, AUTHEN_S_AUTHEN_TYPE_OFF ) ) { /* authen_type */
case TAC_PLUS_AUTHEN_TYPE_ASCII:
proto_tree_add_text( tree, tvb, AUTHEN_S_DATA_LEN_OFF, 1, "Data: %d (not used)", val );
if( val )
proto_tree_add_text( tree, tvb, var_off, val, "Data" );
break;
case TAC_PLUS_AUTHEN_TYPE_PAP:
proto_tree_add_text( tree, tvb, AUTHEN_S_DATA_LEN_OFF, 1, "Password Length %d", val );
if( val ) {
tvb_get_nstringz0( tvb, var_off, val+1, buff );
proto_tree_add_text( tree, tvb, var_off, val, "Password: %s", buff );
}
break;
case TAC_PLUS_AUTHEN_TYPE_CHAP:
proto_tree_add_text( tree, tvb, AUTHEN_S_DATA_LEN_OFF, 1, "CHAP Data Length %d", val );
if( val ) {
proto_item *pi;
proto_tree *pt;
guint8 chal_len=val-(1+16); /* Response field alwayes 16 octets */
pi = proto_tree_add_text(tree, tvb, var_off, val, "CHAP Data" );
pt = proto_item_add_subtree( pi, ett_tacplus_body_chap );
val= tvb_get_guint8( tvb, var_off );
proto_tree_add_text( pt, tvb, var_off, 1, "ID: %d", val );
var_off++;
tvb_get_nstringz0( tvb, var_off, chal_len+1, buff );
proto_tree_add_text( pt, tvb, var_off, chal_len, "Challenge: %s", buff );
var_off+=chal_len;
tvb_get_nstringz0( tvb, var_off, 16+1, buff );
proto_tree_add_text( pt, tvb, var_off, 16 , "Response: %s", buff );
}
break;
case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
proto_tree_add_text( tree, tvb, AUTHEN_S_DATA_LEN_OFF, 1, "MSCHAP Data Length %d", val );
if( val ) {
proto_item *pi;
proto_tree *pt;
guint8 chal_len=val-(1+49); /* Response field alwayes 49 octets */
pi = proto_tree_add_text(tree, tvb, var_off, val, "MSCHAP Data" );
pt = proto_item_add_subtree( pi, ett_tacplus_body_chap );
val= tvb_get_guint8( tvb, var_off );
proto_tree_add_text( pt, tvb, var_off, 1, "ID: %d", val );
var_off++;
tvb_get_nstringz0( tvb, var_off, chal_len+1, buff );
proto_tree_add_text( pt, tvb, var_off, chal_len, "Challenge: %s", buff );
var_off+=chal_len;
tvb_get_nstringz0( tvb, var_off, 49+1, buff );
proto_tree_add_text( pt, tvb, var_off, 49 , "Response: %s", buff );
}
break;
case TAC_PLUS_AUTHEN_TYPE_ARAP:
proto_tree_add_text( tree, tvb, AUTHEN_S_DATA_LEN_OFF, 1, "ARAP Data Length %d", val );
if( val ) {
proto_item *pi;
proto_tree *pt;
pi = proto_tree_add_text(tree, tvb, var_off, val, "ARAP Data" );
pt = proto_item_add_subtree( pi, ett_tacplus_body_chap );
tvb_get_nstringz0( tvb, var_off, 8+1, buff );
proto_tree_add_text( pt, tvb, var_off, 8, "Nas Challenge: %s", buff );
var_off+=8;
tvb_get_nstringz0( tvb, var_off, 8+1, buff );
proto_tree_add_text( pt, tvb, var_off, 8, "Remote Challenge: %s", buff );
var_off+=8;
tvb_get_nstringz0( tvb, var_off, 8+1, buff );
proto_tree_add_text( pt, tvb, var_off, 8, "Remote Response: %s", buff );
var_off+=8;
}
break;
default: /* Should not be reached */
proto_tree_add_text( tree, tvb, AUTHEN_S_DATA_LEN_OFF, 1, "Data: %d", val );
if( val ){
proto_tree_add_text( tree, tvb, var_off, val, "Data" );
}
}
}
static void
dissect_tacplus_body_authen_req( tvbuff_t* tvb, proto_tree *tree )
{
guint8 val;
int var_off=AUTHEN_S_VARDATA_OFF;
/* Action */
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,
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 );
switch( val ) {
case TAC_PLUS_AUTHEN_LOGIN:
dissect_tacplus_body_authen_req_login( tvb, tree, var_off );
break;
case TAC_PLUS_AUTHEN_SENDAUTH:
break;
}
}
static void
dissect_tacplus_body_authen_req_cont( tvbuff_t *tvb, proto_tree *tree )
{
int val;
int var_off=AUTHEN_C_VARDATA_OFF;
guint8 *buff=NULL;
val=tvb_get_guint8( tvb, AUTHEN_C_FLAGS_OFF );
proto_tree_add_text( tree, tvb,
AUTHEN_R_FLAGS_OFF, 1, "Flags: 0x%02x %s",
val,
(val&TAC_PLUS_CONTINUE_FLAG_ABORT?"(Abort)":"") );
val=tvb_get_ntohs( tvb, AUTHEN_C_USER_LEN_OFF );
proto_tree_add_text( tree, tvb, AUTHEN_C_USER_LEN_OFF, 2 , "User length: %d", val );
if( val ){
buff=g_malloc(val+1);
tvb_get_nstringz0( tvb, var_off, val+1, buff );
proto_tree_add_text( tree, tvb, var_off, val, "User: %s", buff );
var_off+=val;
g_free(buff);
}
val=tvb_get_ntohs( tvb, AUTHEN_C_DATA_LEN_OFF );
proto_tree_add_text( tree, tvb, AUTHEN_C_DATA_LEN_OFF, 2 ,
"Data length: %d", val );
if( val ){
proto_tree_add_text( tree, tvb, var_off, val, "Data" );
}
}
/* Server REPLY */
static void
dissect_tacplus_body_authen_rep( tvbuff_t *tvb, proto_tree *tree )
{
int val;
int var_off=AUTHEN_R_VARDATA_OFF;
guint8 *buff=NULL;
val=tvb_get_guint8( tvb, AUTHEN_R_STATUS_OFF );
proto_tree_add_text(tree, tvb,
AUTHEN_R_STATUS_OFF, 1, "Status: 0x%01x (%s)", val,
val_to_str( val, tacplus_reply_status_vals, "Unknown Packet" ) );
val=tvb_get_guint8( tvb, AUTHEN_R_FLAGS_OFF );
proto_tree_add_text(tree, tvb,
AUTHEN_R_FLAGS_OFF, 1, "Flags: 0x%02x %s",
val, (val&TAC_PLUS_REPLY_FLAG_NOECHO?"(NoEcho)":"") );
val=tvb_get_ntohs(tvb, AUTHEN_R_SRV_MSG_LEN_OFF );
proto_tree_add_text( tree, tvb, AUTHEN_R_SRV_MSG_LEN_OFF, 2 ,
"Server message length: %d", val );
if( val ) {
buff=g_malloc(val+1);
tvb_get_nstringz0(tvb, var_off, val+1, buff);
proto_tree_add_text(tree, tvb, var_off, val, "Server message: %s", buff );
var_off+=val;
g_free(buff);
}
val=tvb_get_ntohs(tvb, AUTHEN_R_DATA_LEN_OFF );
proto_tree_add_text( tree, tvb, AUTHEN_R_DATA_LEN_OFF, 2 ,
"Data length: %d", val );
if( val ){
proto_tree_add_text(tree, tvb, var_off, val, "Data" );
}
}
static void
dissect_tacplus_body_author_req( tvbuff_t* tvb, proto_tree *tree )
{
int val;
int var_off;
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" ) );
val=tvb_get_guint8( tvb, AUTHOR_Q_ARGC_OFF );
var_off=proto_tree_add_tacplus_common_fields( tvb, tree ,
AUTHOR_Q_PRIV_LVL_OFF,
AUTHOR_Q_VARDATA_OFF + val );
proto_tree_add_text( tree, tvb, AUTHOR_Q_ARGC_OFF, 1, "Arg count: %d", val );
/* var_off points after rem_addr */
dissect_tacplus_args_list( tvb, tree, var_off, AUTHOR_Q_VARDATA_OFF, val );
}
static void
dissect_tacplus_body_author_rep( tvbuff_t* tvb, proto_tree *tree )
{
int offset=AUTHOR_R_VARDATA_OFF;
int val=tvb_get_guint8( tvb, AUTHOR_R_STATUS_OFF ) ;
proto_tree_add_text( tree, tvb, AUTHOR_R_STATUS_OFF , 1,
"Auth Status: 0x%01x (%s)", val,
val_to_str( val, tacplus_author_status, "Unknown Authorization Status" ));
val=tvb_get_ntohs( tvb, AUTHOR_R_SRV_MSG_LEN_OFF );
offset+=val;
proto_tree_add_text( tree, tvb, AUTHOR_R_SRV_MSG_LEN_OFF, 2, "Server Msg length: %d", val );
val=tvb_get_ntohs( tvb, AUTHOR_R_DATA_LEN_OFF );
offset+=val;
proto_tree_add_text( tree, tvb, AUTHOR_R_DATA_LEN_OFF, 2, "Data length: %d", val );
val=tvb_get_guint8( tvb, AUTHOR_R_ARGC_OFF);
offset+=val;
proto_tree_add_text( tree, tvb, AUTHOR_R_ARGC_OFF, 1, "Arg count: %d", val );
dissect_tacplus_args_list( tvb, tree, offset, AUTHOR_R_VARDATA_OFF, val );
}
static void
dissect_tacplus_body_acct_req( tvbuff_t* tvb, proto_tree *tree )
{
int val, var_off;
val=tvb_get_guint8( tvb, ACCT_Q_FLAGS_OFF );
proto_tree_add_text( tree, tvb, ACCT_Q_FLAGS_OFF, 1, "Flags: 0x%04x", val );
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" ) );
val=tvb_get_guint8( tvb, ACCT_Q_ARG_CNT_OFF );
/* authen_type */
var_off=proto_tree_add_tacplus_common_fields( tvb, tree ,
ACCT_Q_PRIV_LVL_OFF,
ACCT_Q_VARDATA_OFF+val
);
proto_tree_add_text( tree, tvb, ACCT_Q_ARG_CNT_OFF, 1,
"Arg Cnt: %d", val );
dissect_tacplus_args_list( tvb, tree, var_off, ACCT_Q_VARDATA_OFF, val );
}
static void
dissect_tacplus_body_acct_rep( tvbuff_t* tvb, proto_tree *tree )
{
int val, var_off=ACCT_Q_VARDATA_OFF;
guint8 *buff=NULL;
/* Status */
val=tvb_get_guint8( tvb, ACCT_R_STATUS_OFF );
proto_tree_add_text( tree, tvb, ACCT_R_STATUS_OFF, 1, "Status: 0x%02x (%s)", val,
val_to_str( val, tacplus_acct_status, "Bogus status..") );
/* Server Message */
val=tvb_get_ntohs( tvb, ACCT_R_SRV_MSG_LEN_OFF );
proto_tree_add_text( tree, tvb, ACCT_R_SRV_MSG_LEN_OFF, 2 ,
"Server message length: %d", val );
if( val ) {
buff=(guint8*)g_malloc(val+1);
tvb_get_nstringz0( tvb, var_off, val+1, buff );
proto_tree_add_text( tree, tvb, var_off,
val, "Server message: %s", buff );
var_off+=val;
g_free(buff);
}
/* Data */
val=tvb_get_ntohs( tvb, ACCT_R_DATA_LEN_OFF );
proto_tree_add_text( tree, tvb, ACCT_R_DATA_LEN_OFF, 2 ,
"Data length: %d", val );
if( val ) {
buff=(guint8*)g_malloc(val+1);
tvb_get_nstringz0( tvb, var_off, val+1, buff );
proto_tree_add_text( tree, tvb, var_off,
val, "Data: %s", buff );
g_free(buff);
}
}
static void
dissect_tacplus_body(tvbuff_t * hdr_tvb, tvbuff_t * tvb, proto_tree * tree )
{
int type = tvb_get_guint8( hdr_tvb, H_TYPE_OFF );
int seq_no = tvb_get_guint8( hdr_tvb, H_SEQ_NO_OFF );
switch (type) {
case TAC_PLUS_AUTHEN:
if ( seq_no & 0x01) {
if ( seq_no == 1 )
dissect_tacplus_body_authen_req( tvb, tree );
else
dissect_tacplus_body_authen_req_cont( tvb, tree );
} else {
dissect_tacplus_body_authen_rep( tvb, tree );
}
return;
break;
case TAC_PLUS_AUTHOR:
if ( seq_no & 0x01)
dissect_tacplus_body_author_req( tvb, tree );
else
dissect_tacplus_body_author_rep( tvb, tree );
return;
break;
case TAC_PLUS_ACCT:
if ( seq_no & 0x01)
dissect_tacplus_body_acct_req( tvb, tree );
else
dissect_tacplus_body_acct_rep( tvb, tree );
return;
break;
}
proto_tree_add_text( tree, tvb, 0, tvb_length( tvb ), "Bogus..");
}
static void
dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
tvbuff_t *new_tvb=NULL;
proto_tree *tacplus_tree;
proto_item *ti;
guint8 version,flags;
proto_tree *flags_tree;
proto_item *tf;
proto_item *tmp_pi;
guint32 len;
gboolean request=(pinfo->match_port == pinfo->destport);
@ -338,8 +770,10 @@ dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (check_col(pinfo->cinfo, COL_INFO))
{
col_set_str(pinfo->cinfo, COL_INFO,
request ? "Request" : "Response");
int type = tvb_get_guint8(tvb,1);
col_add_fstr( pinfo->cinfo, COL_INFO, "%s: %s",
request ? "Q" : "R",
val_to_str(type, tacplus_type_vals, "Unknown (0x%02x)"));
}
if (tree)
@ -389,10 +823,25 @@ dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_uint(tacplus_tree, hf_tacplus_packet_len, tvb, 8, 4,
len);
if (flags&FLAGS_UNENCRYPTED)
proto_tree_add_text(tacplus_tree, tvb, 12, len, "Payload");
else
proto_tree_add_text(tacplus_tree, tvb, 12, len, "Encrypted payload");
tmp_pi = proto_tree_add_text(tacplus_tree, tvb, TAC_PLUS_HDR_SIZE, len, "%s%s",
((flags&FLAGS_UNENCRYPTED)?"":"Encrypted "), request?"Request":"Reply" );
if( flags&FLAGS_UNENCRYPTED ) {
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( new_tvb ) {
/* Check to see if I've a decrypted tacacs packet */
if( !(flags&FLAGS_UNENCRYPTED) ){
tmp_pi = proto_tree_add_text(tacplus_tree, new_tvb, 0, len, "Decrypted %s",
request?"Request":"Reply" );
}
dissect_tacplus_body( tvb, new_tvb, proto_item_add_subtree( tmp_pi, ett_tacplus_body ));
}
}
}
@ -445,14 +894,21 @@ proto_register_tacplus(void)
FT_UINT32, BASE_DEC, NULL, 0x0,
"Packet length", HFILL }}
};
static gint *ett[] = {
&ett_tacplus,
&ett_tacplus_flags,
&ett_tacplus_body,
&ett_tacplus_body_chap,
};
module_t *tacplus_module;
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);
prefs_register_string_preference(tacplus_module, "key",
"TACACS+ Encryption Key", "TACACS+ Encryption Key",
&tacplus_key);
}
void
@ -464,3 +920,49 @@ proto_reg_handoff_tacplus(void)
proto_tacplus);
dissector_add("tcp.port", TCP_PORT_TACACS, tacplus_handle);
}
#define MD5_LEN 16
static int
md5_xor( u_char *data, char *key, int data_len, guint32 session_id, u_char version, u_char seq_no )
{
int i,j,md5_len;
md5_byte_t *md5_buff;
md5_byte_t hash[MD5_LEN]; /* the md5 hash */
md5_byte_t *mdp;
md5_state_t mdcontext;
md5_len = sizeof(session_id) + strlen(key)
+ sizeof(version) + sizeof(seq_no);
md5_buff = (md5_byte_t*)g_malloc(md5_len+MD5_LEN);
mdp = md5_buff;
bcopy(&session_id, mdp, sizeof(session_id));
mdp += sizeof(session_id);
bcopy(key, mdp, strlen(key));
mdp += strlen(key);
bcopy(&version, mdp, sizeof(version));
mdp += sizeof(version);
bcopy(&seq_no, mdp, sizeof(seq_no));
mdp += sizeof(seq_no);
md5_init(&mdcontext);
md5_append(&mdcontext, md5_buff, md5_len);
md5_finish(&mdcontext,hash);
md5_len += MD5_LEN;
for (i = 0; i < data_len; i += 16) {
for (j = 0; j < 16; j++) {
if ((i + j) >= data_len)
return 0;
data[i + j] ^= hash[j];
}
bcopy( hash, mdp , MD5_LEN );
md5_init(&mdcontext);
md5_append(&mdcontext, md5_buff, md5_len);
md5_finish(&mdcontext,hash);
}
g_free( md5_buff );
return 0;
}

424
packet-tacacs.h Normal file
View File

@ -0,0 +1,424 @@
/* packet-tacacs.h
* Routines for cisco tacplus packet dissection
* Copyright 2000, Emanuele Caratti <wiz@iol.it>
*
* $Id: packet-tacacs.h,v 1.3 2003/09/20 09:41:48 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* 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.
*/
#ifndef __PACKET_TACACS_H__
#define __PACKET_TACACS_H__
#define TAC_PLUS_HDR_SIZE 12
#define MD5_LEN 16
#define MSCHAP_DIGEST_LEN 49
/* Tacacs+ packet type */
enum
{
TAC_PLUS_AUTHEN = 0x01, /* Authentication */
TAC_PLUS_AUTHOR = 0x02, /* Authorization */
TAC_PLUS_ACCT = 0x03 /* Accounting */
};
/* Flags */
#define TAC_PLUS_ENCRYPTED 0x0
#define TAC_PLUS_CLEAR 0x1
/* Authentication action to perform */
enum
{
TAC_PLUS_AUTHEN_LOGIN = 0x01,
TAC_PLUS_AUTHEN_CHPASS = 0x02,
TAC_PLUS_AUTHEN_SENDPASS = 0x03, /* deprecated */
TAC_PLUS_AUTHEN_SENDAUTH = 0x04
};
/* Authentication priv_levels */
enum
{
TAC_PLUS_PRIV_LVL_MAX = 0x0f,
TAC_PLUS_PRIV_LVL_ROOT = 0x0f,
TAC_PLUS_PRIV_LVL_USER = 0x01,
TAC_PLUS_PRIV_LVL_MIN = 0x00,
};
/* authen types */
enum
{
TAC_PLUS_AUTHEN_TYPE_ASCII = 0x01, /* ascii */
TAC_PLUS_AUTHEN_TYPE_PAP = 0x02, /* pap */
TAC_PLUS_AUTHEN_TYPE_CHAP = 0x03, /* chap */
TAC_PLUS_AUTHEN_TYPE_ARAP = 0x04, /* arap */
TAC_PLUS_AUTHEN_TYPE_MSCHAP = 0x05 /* mschap */
};
/* authen services */
enum
{
TAC_PLUS_AUTHEN_SVC_NONE = 0x00,
TAC_PLUS_AUTHEN_SVC_LOGIN = 0x01,
TAC_PLUS_AUTHEN_SVC_ENABLE = 0x02,
TAC_PLUS_AUTHEN_SVC_PPP = 0x03,
TAC_PLUS_AUTHEN_SVC_ARAP = 0x04,
TAC_PLUS_AUTHEN_SVC_PT = 0x05,
TAC_PLUS_AUTHEN_SVC_RCMD = 0x06,
TAC_PLUS_AUTHEN_SVC_X25 = 0x07,
TAC_PLUS_AUTHEN_SVC_NASI = 0x08,
TAC_PLUS_AUTHEN_SVC_FWPROXY = 0x09
};
/* status of reply packet, that client get from server in authen */
enum
{
TAC_PLUS_AUTHEN_STATUS_PASS = 0x01,
TAC_PLUS_AUTHEN_STATUS_FAIL = 0x02,
TAC_PLUS_AUTHEN_STATUS_GETDATA = 0x03,
TAC_PLUS_AUTHEN_STATUS_GETUSER = 0x04,
TAC_PLUS_AUTHEN_STATUS_GETPASS = 0x05,
TAC_PLUS_AUTHEN_STATUS_RESTART = 0x06,
TAC_PLUS_AUTHEN_STATUS_ERROR = 0x07,
TAC_PLUS_AUTHEN_STATUS_FOLLOW = 0x21
};
/* Authen reply Flags */
#define TAC_PLUS_REPLY_FLAG_NOECHO 0x01
/* Authen continue Flags */
#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x01
/* methods of authentication */
enum {
TAC_PLUS_AUTHEN_METH_NOT_SET = 0x00,
TAC_PLUS_AUTHEN_METH_NONE = 0x01,
TAC_PLUS_AUTHEN_METH_KRB5 = 0x03,
TAC_PLUS_AUTHEN_METH_LINE = 0x03,
TAC_PLUS_AUTHEN_METH_ENABLE = 0x04,
TAC_PLUS_AUTHEN_METH_LOCAL = 0x05,
TAC_PLUS_AUTHEN_METH_TACACSPLUS = 0x06,
TAC_PLUS_AUTHEN_METH_GUEST = 0x08,
TAC_PLUS_AUTHEN_METH_RADIUS = 0x10,
TAC_PLUS_AUTHEN_METH_KRB4 = 0x11,
TAC_PLUS_AUTHEN_METH_RCMD = 0x20
};
/* authorization status */
enum
{
TAC_PLUS_AUTHOR_STATUS_PASS_ADD = 0x01,
TAC_PLUS_AUTHOR_STATUS_PASS_REPL = 0x02,
TAC_PLUS_AUTHOR_STATUS_FAIL = 0x10,
TAC_PLUS_AUTHOR_STATUS_ERROR = 0x11,
TAC_PLUS_AUTHOR_STATUS_FOLLOW = 0x21
};
/* accounting flag */
enum
{
TAC_PLUS_ACCT_FLAG_MORE = 0x1, /* deprecated */
TAC_PLUS_ACCT_FLAG_START = 0x2,
TAC_PLUS_ACCT_FLAG_STOP = 0x4,
TAC_PLUS_ACCT_FLAG_WATCHDOG = 0x8
};
/* accounting status */
enum {
TAC_PLUS_ACCT_STATUS_SUCCESS = 0x01,
TAC_PLUS_ACCT_STATUS_ERROR = 0x02,
TAC_PLUS_ACCT_STATUS_FOLLOW = 0x21
};
/* Header offsets */
#define H_VER_OFF (0)
#define H_TYPE_OFF (H_VER_OFF+1)
#define H_SEQ_NO_OFF (H_TYPE_OFF+1)
#define H_FLAGS_OFF (H_SEQ_NO_OFF+1)
#define H_SESSION_ID_OFF (H_FLAGS_OFF+1)
#define H_LENGTH_OFF (H_SESSION_ID_OFF+4)
#define TACPLUS_BODY_OFF 0
/* authen START offsets */
#define AUTHEN_S_ACTION_OFF (TACPLUS_BODY_OFF)
#define AUTHEN_S_PRIV_LVL_OFF (AUTHEN_S_ACTION_OFF+1)
#define AUTHEN_S_AUTHEN_TYPE_OFF (AUTHEN_S_PRIV_LVL_OFF+1)
#define AUTHEN_S_SERVICE_OFF (AUTHEN_S_AUTHEN_TYPE_OFF+1)
#define AUTHEN_S_USER_LEN_OFF (AUTHEN_S_SERVICE_OFF+1)
#define AUTHEN_S_PORT_LEN_OFF (AUTHEN_S_USER_LEN_OFF+1)
#define AUTHEN_S_REM_ADDR_LEN_OFF (AUTHEN_S_PORT_LEN_OFF+1)
#define AUTHEN_S_DATA_LEN_OFF (AUTHEN_S_REM_ADDR_LEN_OFF+1)
#define AUTHEN_S_VARDATA_OFF (AUTHEN_S_DATA_LEN_OFF+1) /* variable data offset (user, port, etc ) */
/* authen REPLY fields offset */
#define AUTHEN_R_STATUS_OFF (TACPLUS_BODY_OFF)
#define AUTHEN_R_FLAGS_OFF (AUTHEN_R_STATUS_OFF+1)
#define AUTHEN_R_SRV_MSG_LEN_OFF (AUTHEN_R_FLAGS_OFF+1)
#define AUTHEN_R_DATA_LEN_OFF (AUTHEN_R_SRV_MSG_LEN_OFF+2)
#define AUTHEN_R_VARDATA_OFF (AUTHEN_R_DATA_LEN_OFF+2)
/* authen CONTINUE fields offset */
#define AUTHEN_C_USER_LEN_OFF (TACPLUS_BODY_OFF)
#define AUTHEN_C_DATA_LEN_OFF (AUTHEN_C_USER_LEN_OFF+2)
#define AUTHEN_C_FLAGS_OFF (AUTHEN_C_DATA_LEN_OFF+2)
#define AUTHEN_C_VARDATA_OFF (AUTHEN_C_FLAGS_OFF+1)
/* acct REQUEST fields offsets */
#define ACCT_Q_FLAGS_OFF (TACPLUS_BODY_OFF)
#define ACCT_Q_METHOD_OFF (ACCT_Q_FLAGS_OFF+1)
#define ACCT_Q_PRIV_LVL_OFF (ACCT_Q_METHOD_OFF+1)
#define ACCT_Q_AUTHEN_TYPE_OFF (ACCT_Q_PRIV_LVL_OFF+1)
#define ACCT_Q_SERVICE_OFF (ACCT_Q_AUTHEN_TYPE_OFF+1)
#define ACCT_Q_USER_LEN_OFF (ACCT_Q_SERVICE_OFF+1)
#define ACCT_Q_PORT_LEN_OFF (ACCT_Q_USER_LEN_OFF+1)
#define ACCT_Q_REM_ADDR_LEN_OFF (ACCT_Q_PORT_LEN_OFF+1)
#define ACCT_Q_ARG_CNT_OFF (ACCT_Q_REM_ADDR_LEN_OFF+1)
#define ACCT_Q_VARDATA_OFF (ACCT_Q_ARG_CNT_OFF+1)
/* acct REPLY fields offsets */
#define ACCT_R_SRV_MSG_LEN_OFF (TACPLUS_BODY_OFF)
#define ACCT_R_DATA_LEN_OFF (ACCT_R_SRV_MSG_LEN_OFF+2)
#define ACCT_R_STATUS_OFF (ACCT_R_DATA_LEN_OFF+2)
#define ACCT_R_VARDATA_OFF (ACCT_R_STATUS_OFF+1)
/* AUTHORIZATION */
/* Request */
#define AUTHOR_Q_AUTH_METH_OFF (TACPLUS_BODY_OFF)
#define AUTHOR_Q_PRIV_LVL_OFF (AUTHOR_Q_AUTH_METH_OFF+1)
#define AUTHOR_Q_AUTHEN_TYPE_OFF (AUTHOR_Q_PRIV_LVL_OFF+1)
#define AUTHOR_Q_SERVICE_OFF (AUTHOR_Q_AUTHEN_TYPE_OFF+1)
#define AUTHOR_Q_USER_LEN_OFF (AUTHOR_Q_SERVICE_OFF+1)
#define AUTHOR_Q_PORT_LEN_OFF (AUTHOR_Q_USER_LEN_OFF+1)
#define AUTHOR_Q_REM_ADDR_LEN_OFF (AUTHOR_Q_PORT_LEN_OFF+1)
#define AUTHOR_Q_ARGC_OFF (AUTHOR_Q_REM_ADDR_LEN_OFF+1)
#define AUTHOR_Q_VARDATA_OFF (AUTHOR_Q_ARGC_OFF+1)
/* Reply */
#define AUTHOR_R_STATUS_OFF (TACPLUS_BODY_OFF)
#define AUTHOR_R_ARGC_OFF (AUTHOR_R_STATUS_OFF+1)
#define AUTHOR_R_SRV_MSG_LEN_OFF (AUTHOR_R_ARGC_OFF+1)
#define AUTHOR_R_DATA_LEN_OFF (AUTHOR_R_SRV_MSG_LEN_OFF+2)
#define AUTHOR_R_VARDATA_OFF (AUTHOR_R_DATA_LEN_OFF+2)
#if 0
/* Packet structures */
typedef struct {
u_char version;
u_char type;
u_char seq_no;
u_char flags;
guint32 session_id;
guint32 length;
} tacplus_pkt_hdr;
/* Authentication START packet */
typedef struct {
u_char action;
u_char priv_lvl;
u_char authen_type;
u_char service;
u_char user_len;
u_char port_len;
u_char rem_addr_len;
u_char data_len;
u_char vardata[1];
} tacplus_authen_start ;
/* Authentication CONTINUE packet */
typedef struct {
guint16 user_len;
guint16 data_len;
u_char flags;
u_char vardata[1];
} tacplus_authen_continue ;
/* Authentication REPLY packet */
typedef struct {
u_char status;
u_char flags;
guint16 srv_msg_len;
guint16 data_len;
u_char vardata[1];
} tacplus_authen_reply;
/* Authentication sub-PACKET */
typedef union {
tacplus_authen_start s; /* start */
tacplus_authen_continue c; /* continue */
tacplus_authen_reply r; /* reply (from srv) */
} tacplus_authen_pkt;
/* AUTHORIZATION request */
typedef struct {
u_char authen_method;
u_char priv_lvl;
u_char authen_type;
u_char authen_service;
u_char user_len;
u_char port_len;
u_char rem_addr_len;
u_char arg_cnt;
u_char vardata[1];
} tacplus_author_request;
typedef struct {
u_char status;
u_char arg_cnt;
guint16 srv_msg_len;
guint16 data_len;
u_char vardata[1];
} tacplus_author_reply;
typedef union {
tacplus_author_request q;
tacplus_author_reply r;
} tacplus_author_pkt;
/* ACCOUNTING request */
typedef struct {
u_char flags;
u_char authen_method;
u_char priv_lvl;
u_char authen_type;
u_char authen_service;
u_char user_len;
u_char port_len;
u_char rem_addr_len;
u_char arg_cnt;
u_char vardata[1];
} tacplus_account_request;
typedef struct {
guint16 srv_msg_len;
guint16 data_len;
u_char status;
u_char vardata[1];
} tacplus_account_reply;
typedef union {
tacplus_account_request q; /* Request */
tacplus_account_reply r; /* Reply */
} tacplus_account_pkt;
/* TACACS+ Packet */
typedef struct {
tacplus_pkt_hdr hdr;
union {
tacplus_authen_pkt authen;
tacplus_author_pkt author;
tacplus_account_pkt acct;
} body;
} tacplus_pkt;
#endif
/* From my old tacacs dissector */
static value_string tacplus_type_vals[] = {
{TAC_PLUS_AUTHEN, "Authentication"},
{TAC_PLUS_AUTHOR, "Authorization" },
{TAC_PLUS_ACCT, "Accounting" },
{0, NULL}};
static value_string tacplus_authen_action_vals[] = {
{TAC_PLUS_AUTHEN_LOGIN, "Inbound Login"},
{TAC_PLUS_AUTHEN_CHPASS, "Change password request"},
{TAC_PLUS_AUTHEN_SENDPASS, "Send password request"},
{TAC_PLUS_AUTHEN_SENDAUTH, "Outbound Request (SENDAUTH)"},
{0, NULL}};
#if 0
static value_string tacplus_authen_priv_lvl_vals[] = {
{TAC_PLUS_PRIV_LVL_MAX, "LVL_MAX"},
{TAC_PLUS_PRIV_LVL_ROOT, "LVL_ROOT"},
{TAC_PLUS_PRIV_LVL_USER, "LVL_USER"},
{TAC_PLUS_PRIV_LVL_MIN, "LVL_MIN"},
{0, NULL}};
#endif
static value_string tacplus_authen_type_vals[] = {
{TAC_PLUS_AUTHEN_TYPE_ASCII, "ASCII"},
{TAC_PLUS_AUTHEN_TYPE_PAP, "PAP"},
{TAC_PLUS_AUTHEN_TYPE_CHAP, "CHAP"},
{TAC_PLUS_AUTHEN_TYPE_ARAP, "ARAP"},
{TAC_PLUS_AUTHEN_TYPE_MSCHAP, "MS-CHAP"},
{0, NULL}};
static value_string tacplus_authen_service_vals[] = {
{TAC_PLUS_AUTHEN_SVC_NONE, "TAC_PLUS_AUTHEN_SVC_NONE"},
{TAC_PLUS_AUTHEN_SVC_LOGIN, "Login" },
{TAC_PLUS_AUTHEN_SVC_ENABLE, "ENABLE"},
{TAC_PLUS_AUTHEN_SVC_PPP, "PPP" },
{TAC_PLUS_AUTHEN_SVC_ARAP, "ARAP" },
{TAC_PLUS_AUTHEN_SVC_PT, "TAC_PLUS_AUTHEN_SVC_PT"},
{TAC_PLUS_AUTHEN_SVC_RCMD, "TAC_PLUS_AUTHEN_SVC_RCMD"},
{TAC_PLUS_AUTHEN_SVC_X25, "TAC_PLUS_AUTHEN_SVC_X25"},
{TAC_PLUS_AUTHEN_SVC_NASI, "TAC_PLUS_AUTHEN_SVC_NASI"},
{TAC_PLUS_AUTHEN_SVC_FWPROXY, "TAC_PLUS_AUTHEN_SVC_FWPROXY"},
{0, NULL}};
static value_string tacplus_reply_status_vals[] = {
{TAC_PLUS_AUTHEN_STATUS_PASS, "Authentication Passed"},
{TAC_PLUS_AUTHEN_STATUS_FAIL, "Authentication Failed"},
{TAC_PLUS_AUTHEN_STATUS_GETDATA, "Send Data"},
{TAC_PLUS_AUTHEN_STATUS_GETUSER, "Send Username"},
{TAC_PLUS_AUTHEN_STATUS_GETPASS, "Send Password"},
{TAC_PLUS_AUTHEN_STATUS_RESTART, "Restart Authentication Sequence"},
{TAC_PLUS_AUTHEN_STATUS_ERROR, "Unrecoverable Error"},
{TAC_PLUS_AUTHEN_STATUS_FOLLOW, "Use Alternate Server"},
{0, NULL}};
static value_string tacplus_authen_method[] = {
{TAC_PLUS_AUTHEN_METH_NOT_SET, "NOT_SET"},
{TAC_PLUS_AUTHEN_METH_NONE, "NONE"},
{TAC_PLUS_AUTHEN_METH_KRB5, "KRB5"},
{TAC_PLUS_AUTHEN_METH_LINE, "LINE"},
{TAC_PLUS_AUTHEN_METH_ENABLE, "ENABLE"},
{TAC_PLUS_AUTHEN_METH_LOCAL, "LOCAL"},
{TAC_PLUS_AUTHEN_METH_TACACSPLUS, "TACACSPLUS"},
{TAC_PLUS_AUTHEN_METH_GUEST, "GUEST"},
{TAC_PLUS_AUTHEN_METH_RADIUS, "RADIUS"},
{TAC_PLUS_AUTHEN_METH_KRB4, "KRB4"},
{TAC_PLUS_AUTHEN_METH_RCMD, "RCMD"},
{0, NULL}};
static value_string tacplus_author_status[] = {
{TAC_PLUS_AUTHOR_STATUS_PASS_ADD, "PASS_ADD"},
{TAC_PLUS_AUTHOR_STATUS_PASS_REPL, "PASS_REPL"},
{TAC_PLUS_AUTHOR_STATUS_FAIL, "FAIL"},
{TAC_PLUS_AUTHOR_STATUS_ERROR, "ERROR"},
{TAC_PLUS_AUTHOR_STATUS_FOLLOW, "FOLLOW"},
{0, NULL}};
static value_string tacplus_acct_status[] = {
{TAC_PLUS_ACCT_STATUS_SUCCESS, "Success"},
{TAC_PLUS_ACCT_STATUS_ERROR, "Error"},
{TAC_PLUS_ACCT_STATUS_FOLLOW, "Follow"},
{0, NULL}};
static value_string tacplus_acct_flags[] = {
{TAC_PLUS_ACCT_FLAG_MORE, "More (deprecated)"},
{TAC_PLUS_ACCT_FLAG_START, "Start"},
{TAC_PLUS_ACCT_FLAG_STOP, "Stop"},
{TAC_PLUS_ACCT_FLAG_WATCHDOG,"Update"},
{0, NULL}};
#endif /* __PACKET_TACACS_H__ */