1999-12-03 21:50:31 +00:00
/* packet-tacacs.c
2001-07-10 21:06:53 +00:00
* Routines for cisco tacacs / xtacacs / tacacs + packet dissection
* Copyright 2001 , Paul Ionescu < paul @ acorp . ro >
2006-07-11 17:53:15 +00:00
*
2003-09-20 09:41:48 +00:00
* Full Tacacs + parsing with decryption by
* Emanuele Caratti < wiz @ iol . it >
1999-12-03 21:50:31 +00:00
*
2004-07-18 00:24:25 +00:00
* $ Id $
1999-12-03 21:50:31 +00:00
*
2006-05-21 04:49:01 +00:00
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
1999-12-03 21:50:31 +00:00
* Copyright 1998 Gerald Combs
*
2001-07-10 21:06:53 +00:00
* Copied from old packet - tacacs . c
2002-08-28 21:04:11 +00:00
*
1999-12-03 21:50:31 +00:00
* 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 .
2002-08-28 21:04:11 +00:00
*
1999-12-03 21:50:31 +00:00
* 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 .
2002-08-28 21:04:11 +00:00
*
1999-12-03 21:50:31 +00:00
* 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 .
*/
2001-07-10 21:06:53 +00:00
2002-08-28 21:04:11 +00:00
/* rfc-1492 for tacacs and xtacacs
2003-09-20 09:41:48 +00:00
* draft - grant - tacacs - 02. txt for tacacs + ( tacplus )
2006-04-25 13:41:05 +00:00
* ftp : //ftp.cisco.com/pub/rfc/DRAFTS/draft-grant-tacacs-02.txt
2001-07-10 21:06:53 +00:00
*/
1999-12-03 21:50:31 +00:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <stdio.h>
# include <string.h>
2004-12-31 02:16:05 +00:00
# include <sys/types.h>
# ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
# endif
# ifdef HAVE_NETINET_IN_H
# include <netinet / in.h>
# endif
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h> /* needed to define AF_ values on Windows */
# endif
2005-01-01 23:40:56 +00:00
# ifdef NEED_INET_V6DEFS_H
# include "inet_v6defs.h"
# endif
1999-12-03 21:50:31 +00:00
# include <glib.h>
2002-01-21 07:37:49 +00:00
# include <epan/packet.h>
1999-12-03 21:50:31 +00:00
2004-09-27 22:55:15 +00:00
# include <epan/prefs.h>
2007-01-02 22:49:57 +00:00
# include <epan/crypt/crypt-md5.h>
2005-08-17 08:43:40 +00:00
# include <epan/emem.h>
2003-09-20 09:41:48 +00:00
# include "packet-tacacs.h"
2005-07-24 19:01:28 +00:00
static void md5_xor ( guint8 * data , const char * key , int data_len , guint8 * session_id , guint8 version , guint8 seq_no ) ;
2003-09-20 09:41:48 +00:00
1999-12-03 21:50:31 +00:00
static int proto_tacacs = - 1 ;
2001-07-11 07:03:45 +00:00
static int hf_tacacs_version = - 1 ;
static int hf_tacacs_type = - 1 ;
static int hf_tacacs_nonce = - 1 ;
static int hf_tacacs_userlen = - 1 ;
static int hf_tacacs_passlen = - 1 ;
static int hf_tacacs_response = - 1 ;
static int hf_tacacs_reason = - 1 ;
static int hf_tacacs_result1 = - 1 ;
static int hf_tacacs_destaddr = - 1 ;
static int hf_tacacs_destport = - 1 ;
static int hf_tacacs_line = - 1 ;
static int hf_tacacs_result2 = - 1 ;
static int hf_tacacs_result3 = - 1 ;
1999-12-03 21:50:31 +00:00
static gint ett_tacacs = - 1 ;
2007-01-24 04:57:32 +00:00
static gboolean tacplus_preference_desegment = TRUE ;
2005-07-24 19:01:28 +00:00
static const char * tacplus_opt_key ;
2003-10-19 17:30:43 +00:00
static GSList * tacplus_keys = NULL ;
2003-09-20 09:41:48 +00:00
2001-07-11 07:03:45 +00:00
# define VERSION_TACACS 0x00
# define VERSION_XTACACS 0x80
static const value_string tacacs_version_vals [ ] = {
{ VERSION_TACACS , " TACACS " } ,
{ VERSION_XTACACS , " XTACACS " } ,
{ 0 , NULL }
} ;
# define TACACS_LOGIN 1
# define TACACS_RESPONSE 2
# define TACACS_CHANGE 3
# define TACACS_FOLLOW 4
# define TACACS_CONNECT 5
# define TACACS_SUPERUSER 6
# define TACACS_LOGOUT 7
# define TACACS_RELOAD 8
# define TACACS_SLIP_ON 9
# define TACACS_SLIP_OFF 10
# define TACACS_SLIP_ADDR 11
2001-07-10 21:06:53 +00:00
static const value_string tacacs_type_vals [ ] = {
2001-07-11 07:03:45 +00:00
{ TACACS_LOGIN , " Login " } ,
{ TACACS_RESPONSE , " Response " } ,
{ TACACS_CHANGE , " Change " } ,
{ TACACS_FOLLOW , " Follow " } ,
{ TACACS_CONNECT , " Connect " } ,
{ TACACS_SUPERUSER , " Superuser " } ,
{ TACACS_LOGOUT , " Logout " } ,
{ TACACS_RELOAD , " Reload " } ,
{ TACACS_SLIP_ON , " SLIP on " } ,
{ TACACS_SLIP_OFF , " SLIP off " } ,
{ TACACS_SLIP_ADDR , " SLIP Addr " } ,
2002-08-28 21:04:11 +00:00
{ 0 , NULL } } ;
2001-07-10 21:06:53 +00:00
static const value_string tacacs_reason_vals [ ] = {
{ 0 , " none " } ,
{ 1 , " expiring " } ,
{ 2 , " password " } ,
{ 3 , " denied " } ,
{ 4 , " quit " } ,
{ 5 , " idle " } ,
{ 6 , " drop " } ,
2001-11-27 22:37:20 +00:00
{ 7 , " bad " } ,
{ 0 , NULL }
} ;
2001-07-10 21:06:53 +00:00
static const value_string tacacs_resp_vals [ ] = {
{ 0 , " this is not a response " } ,
{ 1 , " accepted " } ,
2001-11-27 22:37:20 +00:00
{ 2 , " rejected " } ,
{ 0 , NULL }
} ;
2001-07-10 21:06:53 +00:00
2000-04-08 07:07:42 +00:00
# define UDP_PORT_TACACS 49
# define TCP_PORT_TACACS 49
static void
2001-02-28 10:28:55 +00:00
dissect_tacacs ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
1999-12-03 21:50:31 +00:00
{
2001-07-11 07:03:45 +00:00
proto_tree * tacacs_tree ;
proto_item * ti ;
2003-05-15 05:18:17 +00:00
guint8 txt_buff [ 255 + 1 ] , version , type , userlen , passlen ;
1999-12-03 21:50:31 +00:00
2001-12-10 00:26:21 +00:00
if ( check_col ( pinfo - > cinfo , COL_PROTOCOL ) )
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " TACACS " ) ;
if ( check_col ( pinfo - > cinfo , COL_INFO ) )
col_clear ( pinfo - > cinfo , COL_INFO ) ;
2001-07-11 07:03:45 +00:00
version = tvb_get_guint8 ( tvb , 0 ) ;
if ( version ! = 0 ) {
2001-12-10 00:26:21 +00:00
if ( check_col ( pinfo - > cinfo , COL_PROTOCOL ) )
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " XTACACS " ) ;
2001-07-11 07:03:45 +00:00
}
Add the "Edit:Protocols..." feature which currently only implements
the following:
It is now possible to enable/disable a particular protocol decoding
(i.e. the protocol dissector is void or not). When a protocol
is disabled, it is displayed as Data and of course, all linked
sub-protocols are disabled as well.
Disabling a protocol could be interesting:
- in case of buggy dissectors
- in case of wrong heuristics
- for performance reasons
- to decode the data as another protocol (TODO)
Currently (if I am not wrong), all dissectors but NFS can be disabled
(and dissectors that do not register protocols :-)
I do not like the way the RPC sub-dissectors are disabled (in the
sub-dissectors) since this could be done in the RPC dissector itself,
knowing the sub-protocol hfinfo entry (this is why, I've not modified
the NFS one yet).
Two functions are added in proto.c :
gboolean proto_is_protocol_enabled(int n);
void proto_set_decoding(int n, gboolean enabled);
and two MACROs which can be used in dissectors:
OLD_CHECK_DISPLAY_AS_DATA(index, pd, offset, fd, tree)
CHECK_DISPLAY_AS_DATA(index, tvb, pinfo, tree)
See also the XXX in proto_dlg.c and proto.c around the new functions.
svn path=/trunk/; revision=2267
2000-08-13 14:09:15 +00:00
2001-07-11 07:03:45 +00:00
type = tvb_get_guint8 ( tvb , 1 ) ;
2001-12-10 00:26:21 +00:00
if ( check_col ( pinfo - > cinfo , COL_INFO ) )
col_add_str ( pinfo - > cinfo , COL_INFO ,
2001-07-11 07:03:45 +00:00
val_to_str ( type , tacacs_type_vals , " Unknown (0x%02x) " ) ) ;
1999-12-03 21:50:31 +00:00
2002-08-28 21:04:11 +00:00
if ( tree )
1999-12-03 21:50:31 +00:00
{
2001-07-10 21:06:53 +00:00
ti = proto_tree_add_protocol_format ( tree , proto_tacacs ,
2002-01-24 09:20:54 +00:00
tvb , 0 , - 1 , version = = 0 ? " TACACS " : " XTACACS " ) ;
1999-12-03 21:50:31 +00:00
tacacs_tree = proto_item_add_subtree ( ti , ett_tacacs ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_uint ( tacacs_tree , hf_tacacs_version , tvb , 0 , 1 ,
version ) ;
proto_tree_add_uint ( tacacs_tree , hf_tacacs_type , tvb , 1 , 1 ,
type ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_nonce , tvb , 2 , 2 ,
FALSE ) ;
2001-07-10 21:06:53 +00:00
if ( version = = 0 )
{
2001-07-11 07:03:45 +00:00
if ( type ! = TACACS_RESPONSE )
2001-07-10 21:06:53 +00:00
{
userlen = tvb_get_guint8 ( tvb , 4 ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_uint ( tacacs_tree , hf_tacacs_userlen , tvb , 4 , 1 ,
userlen ) ;
2001-07-10 21:06:53 +00:00
passlen = tvb_get_guint8 ( tvb , 5 ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_uint ( tacacs_tree , hf_tacacs_passlen , tvb , 5 , 1 ,
passlen ) ;
2003-05-15 05:18:17 +00:00
tvb_get_nstringz0 ( tvb , 6 , userlen + 1 , txt_buff ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_text ( tacacs_tree , tvb , 6 , userlen , " Username: %s " , txt_buff ) ;
2003-05-15 05:18:17 +00:00
tvb_get_nstringz0 ( tvb , 6 + userlen , passlen + 1 , txt_buff ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_text ( tacacs_tree , tvb , 6 + userlen , passlen , " Password: %s " , txt_buff ) ;
1999-12-03 21:50:31 +00:00
}
2001-07-10 21:06:53 +00:00
else
{
2001-07-11 07:03:45 +00:00
proto_tree_add_item ( tacacs_tree , hf_tacacs_response , tvb , 4 , 1 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_reason , tvb , 5 , 1 ,
FALSE ) ;
1999-12-03 21:50:31 +00:00
}
2001-07-10 21:06:53 +00:00
}
else
{
userlen = tvb_get_guint8 ( tvb , 4 ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_uint ( tacacs_tree , hf_tacacs_userlen , tvb , 4 , 1 ,
userlen ) ;
2001-07-10 21:06:53 +00:00
passlen = tvb_get_guint8 ( tvb , 5 ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_uint ( tacacs_tree , hf_tacacs_passlen , tvb , 5 , 1 ,
passlen ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_response , tvb , 6 , 1 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_reason , tvb , 7 , 1 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_result1 , tvb , 8 , 4 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_destaddr , tvb , 12 , 4 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_destport , tvb , 16 , 2 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_line , tvb , 18 , 2 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_result2 , tvb , 20 , 4 ,
FALSE ) ;
proto_tree_add_item ( tacacs_tree , hf_tacacs_result3 , tvb , 24 , 2 ,
FALSE ) ;
if ( type ! = TACACS_RESPONSE )
{
2003-05-15 05:18:17 +00:00
tvb_get_nstringz0 ( tvb , 26 , userlen + 1 , txt_buff ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_text ( tacacs_tree , tvb , 26 , userlen , " Username: %s " , txt_buff ) ;
2003-05-15 05:18:17 +00:00
tvb_get_nstringz0 ( tvb , 26 + userlen , passlen + 1 , txt_buff ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_text ( tacacs_tree , tvb , 26 + userlen , passlen , " Password; %s " , txt_buff ) ;
2001-07-10 21:06:53 +00:00
}
}
1999-12-03 21:50:31 +00:00
}
}
2001-07-11 07:03:45 +00:00
void
proto_register_tacacs ( void )
{
static hf_register_info hf [ ] = {
{ & hf_tacacs_version ,
{ " Version " , " tacacs.version " ,
FT_UINT8 , BASE_HEX , VALS ( tacacs_version_vals ) , 0x0 ,
" Version " , HFILL } } ,
{ & hf_tacacs_type ,
{ " Type " , " tacacs.type " ,
FT_UINT8 , BASE_DEC , VALS ( tacacs_type_vals ) , 0x0 ,
" Type " , HFILL } } ,
{ & hf_tacacs_nonce ,
{ " Nonce " , " tacacs.nonce " ,
FT_UINT16 , BASE_HEX , NULL , 0x0 ,
" Nonce " , HFILL } } ,
{ & hf_tacacs_userlen ,
{ " Username length " , " tacacs.userlen " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Username length " , HFILL } } ,
{ & hf_tacacs_passlen ,
{ " Password length " , " tacacs.passlen " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Password length " , HFILL } } ,
{ & hf_tacacs_response ,
{ " Response " , " tacacs.response " ,
FT_UINT8 , BASE_DEC , VALS ( tacacs_resp_vals ) , 0x0 ,
" Response " , HFILL } } ,
{ & hf_tacacs_reason ,
{ " Reason " , " tacacs.reason " ,
FT_UINT8 , BASE_DEC , VALS ( tacacs_reason_vals ) , 0x0 ,
" Reason " , HFILL } } ,
{ & hf_tacacs_result1 ,
{ " Result 1 " , " tacacs.result1 " ,
FT_UINT32 , BASE_HEX , NULL , 0x0 ,
" Result 1 " , HFILL } } ,
{ & hf_tacacs_destaddr ,
{ " Destination address " , " tacacs.destaddr " ,
FT_IPv4 , BASE_NONE , NULL , 0x0 ,
" Destination address " , HFILL } } ,
{ & hf_tacacs_destport ,
{ " Destination port " , " tacacs.destport " ,
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
" Destination port " , HFILL } } ,
{ & hf_tacacs_line ,
{ " Line " , " tacacs.line " ,
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
" Line " , HFILL } } ,
{ & hf_tacacs_result2 ,
{ " Result 2 " , " tacacs.result2 " ,
FT_UINT32 , BASE_HEX , NULL , 0x0 ,
" Result 2 " , HFILL } } ,
{ & hf_tacacs_result3 ,
{ " Result 3 " , " tacacs.result3 " ,
FT_UINT16 , BASE_HEX , NULL , 0x0 ,
" Result 3 " , HFILL } } ,
} ;
static gint * ett [ ] = {
& ett_tacacs ,
} ;
proto_tacacs = proto_register_protocol ( " TACACS " , " TACACS " , " tacacs " ) ;
proto_register_field_array ( proto_tacacs , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
}
void
proto_reg_handoff_tacacs ( void )
{
2001-12-03 04:00:26 +00:00
dissector_handle_t tacacs_handle ;
tacacs_handle = create_dissector_handle ( dissect_tacacs , proto_tacacs ) ;
dissector_add ( " udp.port " , UDP_PORT_TACACS , tacacs_handle ) ;
2001-07-11 07:03:45 +00:00
}
static int proto_tacplus = - 1 ;
static int hf_tacplus_response = - 1 ;
static int hf_tacplus_request = - 1 ;
static int hf_tacplus_majvers = - 1 ;
static int hf_tacplus_minvers = - 1 ;
static int hf_tacplus_type = - 1 ;
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 ;
2003-10-19 17:30:43 +00:00
static int hf_tacplus_acct_flags = - 1 ;
2001-07-11 07:03:45 +00:00
static int hf_tacplus_session_id = - 1 ;
static int hf_tacplus_packet_len = - 1 ;
static gint ett_tacplus = - 1 ;
2003-09-20 09:41:48 +00:00
static gint ett_tacplus_body = - 1 ;
static gint ett_tacplus_body_chap = - 1 ;
2001-07-11 07:03:45 +00:00
static gint ett_tacplus_flags = - 1 ;
2003-10-19 17:30:43 +00:00
static gint ett_tacplus_acct_flags = - 1 ;
2001-07-11 07:03:45 +00:00
2003-10-19 17:30:43 +00:00
typedef struct _tacplus_key_entry {
address * s ; /* Server address */
address * c ; /* client address */
char * k ; /* Key */
} tacplus_key_entry ;
2001-07-11 07:03:45 +00:00
2006-07-11 17:53:15 +00:00
static gint
2005-07-24 19:01:28 +00:00
tacplus_decrypted_tvb_setup ( tvbuff_t * tvb , tvbuff_t * * dst_tvb , packet_info * pinfo , guint32 len , guint8 version , const char * key )
2003-09-20 09:41:48 +00:00
{
guint8 * buff ;
2003-12-19 19:03:13 +00:00
guint8 session_id [ 4 ] ;
2003-09-23 03:18:30 +00:00
2003-10-19 17:30:43 +00:00
/* TODO Check the possibility to use pinfo->decrypted_data */
2003-09-23 03:18:30 +00:00
/* session_id is in NETWORK Byte Order, and is used as byte array in the md5_xor */
2003-09-20 09:41:48 +00:00
2006-07-11 17:53:15 +00:00
tvb_memcpy ( tvb , ( guint8 * ) session_id , 4 , 4 ) ;
2003-09-20 09:41:48 +00:00
2003-09-23 03:18:30 +00:00
buff = tvb_memdup ( tvb , TAC_PLUS_HDR_SIZE , len ) ;
2003-09-20 09:41:48 +00:00
2003-09-23 03:18:30 +00:00
2003-10-19 17:30:43 +00:00
md5_xor ( buff , key , len , session_id , version , tvb_get_guint8 ( tvb , 2 ) ) ;
2003-09-20 09:41:48 +00:00
2003-09-20 09:54:11 +00:00
/* Allocate a new tvbuff, referring to the decrypted data. */
2003-09-20 09:41:48 +00:00
* dst_tvb = tvb_new_real_data ( buff , len , len ) ;
2003-09-20 09:54:11 +00:00
/* Arrange that the allocated packet data copy be freed when the
tvbuff is freed . */
tvb_set_free_cb ( * dst_tvb , g_free ) ;
/* Add the tvbuff to the list of tvbuffs to which the tvbuff we
were handed refers , so it ' ll get cleaned up when that tvbuff
is cleaned up . */
2003-09-20 09:41:48 +00:00
tvb_set_child_real_data_tvbuff ( tvb , * dst_tvb ) ;
2003-09-20 09:54:11 +00:00
/* Add the decrypted data to the data source list. */
2003-09-20 09:41:48 +00:00
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 ) ;
2003-10-19 17:30:43 +00:00
proto_tree_add_text ( tree , tvb , len_off + i , 1 , " Arg[%d] length: %d " , i , len ) ;
2003-09-20 09:41:48 +00:00
tvb_get_nstringz0 ( tvb , data_off , len + 1 , buff ) ;
2003-10-19 17:30:43 +00:00
proto_tree_add_text ( tree , tvb , data_off , len , " Arg[%d] value: %s " , i , buff ) ;
2003-09-20 09:41:48 +00:00
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 ,
2003-10-19 17:30:43 +00:00
" Authentication type: %s " ,
val_to_str ( val , tacplus_authen_type_vals , " Unknown Packet " ) ) ;
2003-09-20 09:41:48 +00:00
offset + + ;
/* service */
val = tvb_get_guint8 ( tvb , offset ) ;
proto_tree_add_text ( tree , tvb , offset , 1 ,
2003-10-19 17:30:43 +00:00
" Service: %s " ,
val_to_str ( val , tacplus_authen_service_vals , " Unknown Packet " ) ) ;
2003-09-20 09:41:48 +00:00
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 ,
2006-07-11 17:53:15 +00:00
AUTHEN_S_ACTION_OFF , 1 ,
" Action: %s " ,
2003-09-20 09:41:48 +00:00
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) " : " " ) ) ;
2006-07-11 17:53:15 +00:00
val = tvb_get_ntohs ( tvb , AUTHEN_C_USER_LEN_OFF ) ;
2003-09-20 09:41:48 +00:00
proto_tree_add_text ( tree , tvb , AUTHEN_C_USER_LEN_OFF , 2 , " User length: %d " , val ) ;
if ( val ) {
2005-08-10 13:41:13 +00:00
buff = tvb_get_ephemeral_string ( tvb , var_off , val ) ;
2003-09-20 09:41:48 +00:00
proto_tree_add_text ( tree , tvb , var_off , val , " User: %s " , buff ) ;
var_off + = val ;
}
2006-07-11 17:53:15 +00:00
val = tvb_get_ntohs ( tvb , AUTHEN_C_DATA_LEN_OFF ) ;
2003-09-20 09:41:48 +00:00
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) " : " " ) ) ;
2006-07-11 17:53:15 +00:00
2003-09-20 09:41:48 +00:00
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 ) {
2005-08-10 13:41:13 +00:00
buff = tvb_get_ephemeral_string ( tvb , var_off , val ) ;
2003-09-20 09:41:48 +00:00
proto_tree_add_text ( tree , tvb , var_off , val , " Server message: %s " , buff ) ;
var_off + = val ;
}
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 ) ;
2006-07-11 17:53:15 +00:00
proto_tree_add_text ( tree , tvb , AUTHOR_Q_AUTH_METH_OFF , 1 ,
2003-10-19 17:30:43 +00:00
" Auth Method: %s " , val_to_str ( val , tacplus_authen_method , " Unknown Authen Method " ) ) ;
2003-09-20 09:41:48 +00:00
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 ) ;
2006-07-11 17:53:15 +00:00
2003-09-20 09:41:48 +00:00
/* 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 ) ;
2006-07-11 17:53:15 +00:00
proto_tree_add_text ( tree , tvb , AUTHOR_R_STATUS_OFF , 1 ,
2003-09-20 09:41:48 +00:00
" 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 ;
2003-10-19 17:30:43 +00:00
proto_item * tf ;
proto_tree * flags_tree ;
2006-07-11 17:53:15 +00:00
val = tvb_get_guint8 ( tvb , ACCT_Q_FLAGS_OFF ) ;
2003-10-19 17:30:43 +00:00
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 " ) ) ;
2003-09-20 09:41:48 +00:00
val = tvb_get_guint8 ( tvb , ACCT_Q_METHOD_OFF ) ;
2006-07-11 17:53:15 +00:00
proto_tree_add_text ( tree , tvb , ACCT_Q_METHOD_OFF , 1 ,
" Authen Method: 0x%01x (%s) " ,
2003-10-19 17:30:43 +00:00
val , val_to_str ( val , tacplus_authen_method , " Unknown Authen Method " ) ) ;
2003-09-20 09:41:48 +00:00
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 ) {
2005-08-10 13:41:13 +00:00
buff = tvb_get_ephemeral_string ( tvb , var_off , val ) ;
2003-09-20 09:41:48 +00:00
proto_tree_add_text ( tree , tvb , var_off ,
val , " Server message: %s " , buff ) ;
var_off + = val ;
}
/* 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 ) {
2005-08-10 13:41:13 +00:00
buff = tvb_get_ephemeral_string ( tvb , var_off , val ) ;
2003-09-20 09:41:48 +00:00
proto_tree_add_text ( tree , tvb , var_off ,
val , " Data: %s " , 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 ) ;
2006-07-11 17:53:15 +00:00
else
2003-09-20 09:41:48 +00:00
dissect_tacplus_body_author_rep ( tvb , tree ) ;
return ;
break ;
case TAC_PLUS_ACCT :
if ( seq_no & 0x01 )
2006-07-11 17:53:15 +00:00
dissect_tacplus_body_acct_req ( tvb , tree ) ;
2003-09-20 09:41:48 +00:00
else
dissect_tacplus_body_acct_rep ( tvb , tree ) ;
return ;
break ;
}
proto_tree_add_text ( tree , tvb , 0 , tvb_length ( tvb ) , " Bogus.. " ) ;
}
2003-10-19 17:30:43 +00:00
# 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 )
{
2004-12-31 02:16:05 +00:00
const tacplus_key_entry * a1 = p1 ;
const tacplus_key_entry * a2 = p2 ;
2003-10-19 17:30:43 +00:00
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 ;
}
2005-07-24 19:01:28 +00:00
static const char *
2003-10-19 17:30:43 +00:00
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); */
2006-07-11 17:53:15 +00:00
if ( match )
2003-10-19 17:30:43 +00:00
return ( ( tacplus_key_entry * ) match - > data ) - > k ;
return ( tacplus_keys ? NULL : tacplus_opt_key ) ;
}
static void
2004-12-31 02:16:05 +00:00
mkipv4_address ( address * * addr , const char * str_addr )
2003-10-19 17:30:43 +00:00
{
2004-12-31 02:16:05 +00:00
char * addr_data ;
2003-10-19 17:30:43 +00:00
* addr = g_malloc ( sizeof ( address ) ) ;
2004-12-31 02:16:05 +00:00
addr_data = g_malloc ( 4 ) ;
inet_pton ( AF_INET , str_addr , addr_data ) ;
2003-10-19 17:30:43 +00:00
( * addr ) - > type = AT_IPv4 ;
( * addr ) - > len = 4 ;
2007-03-26 11:06:26 +00:00
( * addr ) - > data = ( guint8 * ) addr_data ;
2003-10-19 17:30:43 +00:00
}
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 ) ;
2006-07-04 03:59:36 +00:00
tacplus_data - > k = g_strdup ( key ) ;
2003-10-19 17:30:43 +00:00
tacplus_keys = g_slist_prepend ( tacplus_keys , tacplus_data ) ;
}
2006-07-11 17:53:15 +00:00
static
2003-10-19 17:30:43 +00:00
void
2005-07-24 19:01:28 +00:00
parse_tacplus_keys ( const char * keys_from_option )
2003-10-19 17:30:43 +00:00
{
2005-07-24 19:01:28 +00:00
char * key_copy , * s , * s1 ;
2003-10-19 17:30:43 +00:00
/* Drop old keys */
if ( tacplus_keys ) {
g_slist_free ( tacplus_keys ) ;
tacplus_keys = NULL ;
}
if ( ! strchr ( keys_from_option , ' / ' ) ) {
/* option not in client/server=key format */
return ;
}
2005-07-24 19:01:28 +00:00
key_copy = strdup ( keys_from_option ) ;
s = key_copy ;
while ( s ) {
if ( ( s1 = strchr ( s , ' ' ) ) ! = NULL )
* s1 + + = ' \0 ' ;
parse_tuple ( s ) ;
s = s1 ;
2003-10-19 17:30:43 +00:00
}
2005-07-24 19:01:28 +00:00
g_free ( key_copy ) ;
2003-10-19 17:30:43 +00:00
# ifdef DEB_TACPLUS
g_slist_foreach ( tacplus_keys , tacplus_print_key_entry , GINT_TO_POINTER ( 1 ) ) ;
# endif
}
2000-04-08 07:07:42 +00:00
static void
2001-02-28 10:28:55 +00:00
dissect_tacplus ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
1999-12-03 21:50:31 +00:00
{
2003-09-20 09:41:48 +00:00
tvbuff_t * new_tvb = NULL ;
2001-07-11 07:03:45 +00:00
proto_tree * tacplus_tree ;
proto_item * ti ;
guint8 version , flags ;
proto_tree * flags_tree ;
proto_item * tf ;
2003-09-20 09:41:48 +00:00
proto_item * tmp_pi ;
2001-07-10 21:06:53 +00:00
guint32 len ;
2003-10-19 17:30:43 +00:00
gboolean request = ( pinfo - > destport = = TCP_PORT_TACACS ) ;
2005-07-24 19:01:28 +00:00
const char * key = NULL ;
1999-12-03 21:50:31 +00:00
2007-01-24 04:57:32 +00:00
len = tvb_get_ntohl ( tvb , 8 ) ;
if ( len > ( guint ) tvb_length_remaining ( tvb , 12 ) & &
pinfo - > can_desegment & & tacplus_preference_desegment ) {
pinfo - > desegment_offset = 0 ;
pinfo - > desegment_len = len ;
return ;
}
2003-10-19 17:30:43 +00:00
if ( request ) {
key = find_key ( & pinfo - > dst , & pinfo - > src ) ;
} else {
key = find_key ( & pinfo - > src , & pinfo - > dst ) ;
}
2001-12-10 00:26:21 +00:00
if ( check_col ( pinfo - > cinfo , COL_PROTOCOL ) )
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " TACACS+ " ) ;
1999-12-03 21:50:31 +00:00
2001-12-10 00:26:21 +00:00
if ( check_col ( pinfo - > cinfo , COL_INFO ) )
1999-12-03 21:50:31 +00:00
{
2003-09-20 09:41:48 +00:00
int type = tvb_get_guint8 ( tvb , 1 ) ;
2006-07-11 17:53:15 +00:00
col_add_fstr ( pinfo - > cinfo , COL_INFO , " %s: %s " ,
2003-09-20 09:41:48 +00:00
request ? " Q " : " R " ,
val_to_str ( type , tacplus_type_vals , " Unknown (0x%02x) " ) ) ;
1999-12-03 21:50:31 +00:00
}
2002-08-28 21:04:11 +00:00
if ( tree )
1999-12-03 21:50:31 +00:00
{
2001-07-11 07:03:45 +00:00
ti = proto_tree_add_protocol_format ( tree , proto_tacplus ,
2002-01-24 09:20:54 +00:00
tvb , 0 , - 1 , " TACACS+ " ) ;
1999-12-03 21:50:31 +00:00
2001-07-11 07:03:45 +00:00
tacplus_tree = proto_item_add_subtree ( ti , ett_tacplus ) ;
if ( pinfo - > match_port = = pinfo - > destport )
{
proto_tree_add_boolean_hidden ( tacplus_tree ,
hf_tacplus_request , tvb , 0 , 0 , TRUE ) ;
}
else
{
proto_tree_add_boolean_hidden ( tacplus_tree ,
hf_tacplus_response , tvb , 0 , 0 , TRUE ) ;
}
2001-07-10 21:06:53 +00:00
version = tvb_get_guint8 ( tvb , 0 ) ;
2001-07-11 07:03:45 +00:00
proto_tree_add_uint_format ( tacplus_tree , hf_tacplus_majvers , tvb , 0 , 1 ,
version ,
" Major version: %s " ,
( version & 0xf0 ) = = 0xc0 ? " TACACS+ " : " Unknown Version " ) ;
proto_tree_add_uint ( tacplus_tree , hf_tacplus_minvers , tvb , 0 , 1 ,
version & 0xf ) ;
proto_tree_add_item ( tacplus_tree , hf_tacplus_type , tvb , 1 , 1 ,
FALSE ) ;
proto_tree_add_item ( tacplus_tree , hf_tacplus_seqno , tvb , 2 , 1 ,
FALSE ) ;
2001-07-10 21:06:53 +00:00
flags = tvb_get_guint8 ( tvb , 3 ) ;
2001-07-11 16:03:34 +00:00
tf = proto_tree_add_uint_format ( tacplus_tree , hf_tacplus_flags ,
tvb , 3 , 1 , flags ,
2003-10-19 17:30:43 +00:00
" Flags: 0x%02x (%s payload, %s) " ,
flags ,
( flags & FLAGS_UNENCRYPTED ) ? " Unencrypted " :
" Encrypted " ,
2001-07-11 16:03:34 +00:00
( flags & FLAGS_SINGLE ) ? " Single connection " :
2003-10-19 17:30:43 +00:00
" Multiple Connections " ) ;
2001-07-11 07:03:45 +00:00
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 ) ;
proto_tree_add_boolean ( flags_tree , hf_tacplus_flags_connection_type ,
tvb , 3 , 1 , flags ) ;
proto_tree_add_item ( tacplus_tree , hf_tacplus_session_id , tvb , 4 , 4 ,
FALSE ) ;
2007-01-24 04:57:32 +00:00
2006-07-11 17:53:15 +00:00
if ( ( gint ) len < 1 ) {
proto_tree_add_text ( tacplus_tree , tvb , 8 , 4 ,
" Invalid length: %u " , len ) ;
THROW ( ReportedBoundsError ) ;
}
2001-07-11 07:03:45 +00:00
proto_tree_add_uint ( tacplus_tree , hf_tacplus_packet_len , tvb , 8 , 4 ,
len ) ;
1999-12-03 21:50:31 +00:00
2003-09-20 09:41:48 +00:00
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 ;
2003-10-19 17:30:43 +00:00
if ( key & & * key ) {
tacplus_decrypted_tvb_setup ( tvb , & new_tvb , pinfo , len , version , key ) ;
2003-09-20 09:41:48 +00:00
}
}
if ( new_tvb ) {
/* Check to see if I've a decrypted tacacs packet */
2006-07-11 17:53:15 +00:00
if ( ! ( flags & FLAGS_UNENCRYPTED ) ) {
2003-09-20 09:41:48 +00:00
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 ) ) ;
}
1999-12-03 21:50:31 +00:00
}
}
2005-08-02 08:30:33 +00:00
static void
2003-11-11 19:23:22 +00:00
tacplus_pref_cb ( void )
2003-10-19 17:30:43 +00:00
{
parse_tacplus_keys ( tacplus_opt_key ) ;
}
1999-12-03 21:50:31 +00:00
void
2001-07-11 07:03:45 +00:00
proto_register_tacplus ( void )
1999-12-03 21:50:31 +00:00
{
2001-07-11 07:03:45 +00:00
static hf_register_info hf [ ] = {
{ & hf_tacplus_response ,
{ " Response " , " tacplus.response " ,
FT_BOOLEAN , BASE_NONE , NULL , 0x0 ,
" TRUE if TACACS+ response " , HFILL } } ,
{ & hf_tacplus_request ,
{ " Request " , " tacplus.request " ,
FT_BOOLEAN , BASE_NONE , NULL , 0x0 ,
" TRUE if TACACS+ request " , HFILL } } ,
{ & hf_tacplus_majvers ,
{ " Major version " , " tacplus.majvers " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Major version number " , HFILL } } ,
{ & hf_tacplus_minvers ,
{ " Minor version " , " tacplus.minvers " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Minor version number " , HFILL } } ,
{ & hf_tacplus_type ,
{ " Type " , " tacplus.type " ,
FT_UINT8 , BASE_DEC , VALS ( tacplus_type_vals ) , 0x0 ,
" Type " , HFILL } } ,
{ & hf_tacplus_seqno ,
{ " Sequence number " , " tacplus.seqno " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Sequence number " , HFILL } } ,
{ & hf_tacplus_flags ,
{ " Flags " , " tacplus.flags " ,
FT_UINT8 , BASE_HEX , NULL , 0x0 ,
" Flags " , HFILL } } ,
{ & hf_tacplus_flags_payload_type ,
2003-10-19 17:30:43 +00:00
{ " Unencrypted " , " tacplus.flags.unencrypted " ,
FT_BOOLEAN , 8 , TFS ( & flags_set_truth ) , FLAGS_UNENCRYPTED ,
" Is payload unencrypted? " , HFILL } } ,
2001-07-11 07:03:45 +00:00
{ & hf_tacplus_flags_connection_type ,
2003-10-19 17:30:43 +00:00
{ " 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 } } ,
2001-07-11 07:03:45 +00:00
{ & hf_tacplus_session_id ,
{ " Session ID " , " tacplus.session_id " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Session ID " , HFILL } } ,
{ & hf_tacplus_packet_len ,
{ " Packet length " , " tacplus.packet_len " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Packet length " , HFILL } }
} ;
1999-12-03 21:50:31 +00:00
static gint * ett [ ] = {
2001-07-11 07:03:45 +00:00
& ett_tacplus ,
& ett_tacplus_flags ,
2003-10-19 17:30:43 +00:00
& ett_tacplus_acct_flags ,
2003-09-20 09:41:48 +00:00
& ett_tacplus_body ,
2006-07-11 17:53:15 +00:00
& ett_tacplus_body_chap ,
1999-12-03 21:50:31 +00:00
} ;
2003-09-20 09:41:48 +00:00
module_t * tacplus_module ;
2001-07-11 07:03:45 +00:00
proto_tacplus = proto_register_protocol ( " TACACS+ " , " TACACS+ " , " tacplus " ) ;
proto_register_field_array ( proto_tacplus , hf , array_length ( hf ) ) ;
1999-12-03 21:50:31 +00:00
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2003-10-19 17:30:43 +00:00
tacplus_module = prefs_register_protocol ( proto_tacplus , tacplus_pref_cb ) ;
2007-01-24 04:57:32 +00:00
prefs_register_bool_preference ( tacplus_module , " desegment " , " Reassemble TACACS+ messages spanning multiple TCP segments. " , " Whether the TACACS+ dissector should reasssemble messages spanning multiple TCP segments. To use this option, you must also enable \" Allow subdissectors to reassemble TCP streams \" in the TCP protocol settings. " , & tacplus_preference_desegment ) ;
2003-09-23 03:18:30 +00:00
prefs_register_string_preference ( tacplus_module , " key " ,
2003-10-19 17:30:43 +00:00
" TACACS+ Encryption Key " , " TACACS+ Encryption Key " , & tacplus_opt_key ) ;
1999-12-03 21:50:31 +00:00
}
2000-04-08 07:07:42 +00:00
void
2001-07-11 07:03:45 +00:00
proto_reg_handoff_tacplus ( void )
2000-04-08 07:07:42 +00:00
{
2001-12-03 04:00:26 +00:00
dissector_handle_t tacplus_handle ;
tacplus_handle = create_dissector_handle ( dissect_tacplus ,
2001-07-11 07:03:45 +00:00
proto_tacplus ) ;
2001-12-03 04:00:26 +00:00
dissector_add ( " tcp.port " , TCP_PORT_TACACS , tacplus_handle ) ;
2000-04-08 07:07:42 +00:00
}
2003-09-20 09:41:48 +00:00
2003-09-23 03:18:30 +00:00
2003-09-20 09:41:48 +00:00
# define MD5_LEN 16
2003-09-23 03:18:30 +00:00
static void
2005-07-24 19:01:28 +00:00
md5_xor ( guint8 * data , const char * key , int data_len , guint8 * session_id , guint8 version , guint8 seq_no )
2003-09-20 09:41:48 +00:00
{
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 ;
2003-09-23 03:18:30 +00:00
md5_len = 4 /* sizeof(session_id) */ + strlen ( key )
2003-09-20 09:41:48 +00:00
+ sizeof ( version ) + sizeof ( seq_no ) ;
2006-07-11 17:53:15 +00:00
2005-08-17 08:43:40 +00:00
md5_buff = ( md5_byte_t * ) ep_alloc ( md5_len + MD5_LEN ) ;
2003-09-20 09:41:48 +00:00
2003-09-23 03:18:30 +00:00
2003-09-20 09:41:48 +00:00
mdp = md5_buff ;
2003-09-23 03:18:30 +00:00
* ( guint32 * ) mdp = * ( guint32 * ) session_id ;
mdp + = 4 ;
2003-09-23 21:37:11 +00:00
memcpy ( mdp , key , strlen ( key ) ) ;
2003-09-20 09:41:48 +00:00
mdp + = strlen ( key ) ;
2003-09-23 03:18:30 +00:00
* mdp + + = version ;
* mdp + + = seq_no ;
2003-09-20 09:41:48 +00:00
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 + + ) {
2003-09-23 03:18:30 +00:00
if ( ( i + j ) > = data_len ) {
i = data_len + 1 ; /* To exit from the external loop */
break ;
}
2003-09-20 09:41:48 +00:00
data [ i + j ] ^ = hash [ j ] ;
}
2003-09-23 21:37:11 +00:00
memcpy ( mdp , hash , MD5_LEN ) ;
2003-09-20 09:41:48 +00:00
md5_init ( & mdcontext ) ;
md5_append ( & mdcontext , md5_buff , md5_len ) ;
md5_finish ( & mdcontext , hash ) ;
}
}