2 * Routines for cisco tacacs/xtacacs/tacacs+ packet dissection
3 * Copyright 2001, Paul Ionescu <paul@acorp.ro>
5 * Full Tacacs+ parsing with decryption by
6 * Emanuele Caratti <wiz@iol.it>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * Copied from old packet-tacacs.c
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 /* rfc-1492 for tacacs and xtacacs
33 * draft-grant-tacacs-02.txt for tacacs+ (tacplus)
34 * ftp://ftp.cisco.com/pub/rfc/DRAFTS/draft-grant-tacacs-02.txt
39 #ifdef HAVE_SYS_TYPES_H
40 #include <sys/types.h>
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
45 #ifdef HAVE_NETINET_IN_H
46 # include <netinet/in.h>
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
52 #ifdef HAVE_WINSOCK2_H
53 #include <winsock2.h> /* needed to define AF_ values on Windows */
56 #ifdef NEED_INET_V6DEFS_H
57 # include "wsutil/inet_v6defs.h"
62 #include <wsutil/md5.h>
64 #include <epan/packet.h>
65 #include <epan/prefs.h>
66 #include <epan/wmem/wmem.h>
67 #include <epan/expert.h>
68 #include "packet-tacacs.h"
70 static void md5_xor( guint8
*data
, const char *key
, int data_len
, guint8
*session_id
, guint8 version
, guint8 seq_no
);
72 static int proto_tacacs
= -1;
73 static int hf_tacacs_version
= -1;
74 static int hf_tacacs_type
= -1;
75 static int hf_tacacs_nonce
= -1;
76 static int hf_tacacs_userlen
= -1;
77 static int hf_tacacs_passlen
= -1;
78 static int hf_tacacs_response
= -1;
79 static int hf_tacacs_reason
= -1;
80 static int hf_tacacs_result1
= -1;
81 static int hf_tacacs_destaddr
= -1;
82 static int hf_tacacs_destport
= -1;
83 static int hf_tacacs_line
= -1;
84 static int hf_tacacs_result2
= -1;
85 static int hf_tacacs_result3
= -1;
86 static int hf_tacacs_username
= -1;
87 static int hf_tacacs_password
= -1;
89 static gint ett_tacacs
= -1;
91 static expert_field ei_tacplus_packet_len_invalid
= EI_INIT
;
93 static gboolean tacplus_preference_desegment
= TRUE
;
95 static const char *tacplus_opt_key
;
96 static GSList
*tacplus_keys
= NULL
;
98 #define ADDR_INVLD "invalid"
100 #define VERSION_TACACS 0x00
101 #define VERSION_XTACACS 0x80
103 static const value_string tacacs_version_vals
[] = {
104 { VERSION_TACACS
, "TACACS" },
105 { VERSION_XTACACS
, "XTACACS" },
109 #define TACACS_LOGIN 1
110 #define TACACS_RESPONSE 2
111 #define TACACS_CHANGE 3
112 #define TACACS_FOLLOW 4
113 #define TACACS_CONNECT 5
114 #define TACACS_SUPERUSER 6
115 #define TACACS_LOGOUT 7
116 #define TACACS_RELOAD 8
117 #define TACACS_SLIP_ON 9
118 #define TACACS_SLIP_OFF 10
119 #define TACACS_SLIP_ADDR 11
120 static const value_string tacacs_type_vals
[] = {
121 { TACACS_LOGIN
, "Login" },
122 { TACACS_RESPONSE
, "Response" },
123 { TACACS_CHANGE
, "Change" },
124 { TACACS_FOLLOW
, "Follow" },
125 { TACACS_CONNECT
, "Connect" },
126 { TACACS_SUPERUSER
, "Superuser" },
127 { TACACS_LOGOUT
, "Logout" },
128 { TACACS_RELOAD
, "Reload" },
129 { TACACS_SLIP_ON
, "SLIP on" },
130 { TACACS_SLIP_OFF
, "SLIP off" },
131 { TACACS_SLIP_ADDR
, "SLIP Addr" },
134 static const value_string tacacs_reason_vals
[] = {
146 static const value_string tacacs_resp_vals
[] = {
147 { 0 , "this is not a response" },
153 #define UDP_PORT_TACACS 49
154 #define TCP_PORT_TACACS 49
157 dissect_tacacs(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
159 proto_tree
*tacacs_tree
;
161 guint8 version
,type
,userlen
,passlen
;
163 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TACACS");
164 col_clear(pinfo
->cinfo
, COL_INFO
);
166 version
= tvb_get_guint8(tvb
,0);
168 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "XTACACS");
171 type
= tvb_get_guint8(tvb
,1);
172 col_add_str(pinfo
->cinfo
, COL_INFO
,
173 val_to_str(type
, tacacs_type_vals
, "Unknown (0x%02x)"));
177 ti
= proto_tree_add_protocol_format(tree
, proto_tacacs
,
178 tvb
, 0, -1, version
==0?"TACACS":"XTACACS");
179 tacacs_tree
= proto_item_add_subtree(ti
, ett_tacacs
);
181 proto_tree_add_uint(tacacs_tree
, hf_tacacs_version
, tvb
, 0, 1, version
);
182 proto_tree_add_uint(tacacs_tree
, hf_tacacs_type
, tvb
, 1, 1, type
);
183 proto_tree_add_item(tacacs_tree
, hf_tacacs_nonce
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
187 if (type
!=TACACS_RESPONSE
)
189 userlen
=tvb_get_guint8(tvb
,4);
190 proto_tree_add_uint(tacacs_tree
, hf_tacacs_userlen
, tvb
, 4, 1, userlen
);
191 passlen
=tvb_get_guint8(tvb
,5);
192 proto_tree_add_uint(tacacs_tree
, hf_tacacs_passlen
, tvb
, 5, 1, passlen
);
193 proto_tree_add_item(tree
, hf_tacacs_username
, tvb
, 6, userlen
, ENC_ASCII
|ENC_NA
);
194 proto_tree_add_item(tree
, hf_tacacs_password
, tvb
, 6+userlen
, passlen
, ENC_ASCII
|ENC_NA
);
198 proto_tree_add_item(tacacs_tree
, hf_tacacs_response
, tvb
, 4, 1, ENC_BIG_ENDIAN
);
199 proto_tree_add_item(tacacs_tree
, hf_tacacs_reason
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
204 userlen
=tvb_get_guint8(tvb
,4);
205 proto_tree_add_uint(tacacs_tree
, hf_tacacs_userlen
, tvb
, 4, 1, userlen
);
206 passlen
=tvb_get_guint8(tvb
,5);
207 proto_tree_add_uint(tacacs_tree
, hf_tacacs_passlen
, tvb
, 5, 1, passlen
);
208 proto_tree_add_item(tacacs_tree
, hf_tacacs_response
, tvb
, 6, 1, ENC_BIG_ENDIAN
);
209 proto_tree_add_item(tacacs_tree
, hf_tacacs_reason
, tvb
, 7, 1, ENC_BIG_ENDIAN
);
210 proto_tree_add_item(tacacs_tree
, hf_tacacs_result1
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
211 proto_tree_add_item(tacacs_tree
, hf_tacacs_destaddr
, tvb
, 12, 4, ENC_BIG_ENDIAN
);
212 proto_tree_add_item(tacacs_tree
, hf_tacacs_destport
, tvb
, 16, 2, ENC_BIG_ENDIAN
);
213 proto_tree_add_item(tacacs_tree
, hf_tacacs_line
, tvb
, 18, 2, ENC_BIG_ENDIAN
);
214 proto_tree_add_item(tacacs_tree
, hf_tacacs_result2
, tvb
, 20, 4, ENC_BIG_ENDIAN
);
215 proto_tree_add_item(tacacs_tree
, hf_tacacs_result3
, tvb
, 24, 2, ENC_BIG_ENDIAN
);
216 if (type
!=TACACS_RESPONSE
)
218 proto_tree_add_item(tree
, hf_tacacs_username
, tvb
, 26, userlen
, ENC_ASCII
|ENC_NA
);
219 proto_tree_add_item(tree
, hf_tacacs_password
, tvb
, 26+userlen
, passlen
, ENC_ASCII
|ENC_NA
);
226 proto_register_tacacs(void)
228 static hf_register_info hf
[] = {
229 { &hf_tacacs_version
,
230 { "Version", "tacacs.version",
231 FT_UINT8
, BASE_HEX
, VALS(tacacs_version_vals
), 0x0,
234 { "Type", "tacacs.type",
235 FT_UINT8
, BASE_DEC
, VALS(tacacs_type_vals
), 0x0,
238 { "Nonce", "tacacs.nonce",
239 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
241 { &hf_tacacs_userlen
,
242 { "Username length", "tacacs.userlen",
243 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
245 { &hf_tacacs_passlen
,
246 { "Password length", "tacacs.passlen",
247 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
249 { &hf_tacacs_response
,
250 { "Response", "tacacs.response",
251 FT_UINT8
, BASE_DEC
, VALS(tacacs_resp_vals
), 0x0,
254 { "Reason", "tacacs.reason",
255 FT_UINT8
, BASE_DEC
, VALS(tacacs_reason_vals
), 0x0,
257 { &hf_tacacs_result1
,
258 { "Result 1", "tacacs.result1",
259 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
261 { &hf_tacacs_destaddr
,
262 { "Destination address", "tacacs.destaddr",
263 FT_IPv4
, BASE_NONE
, NULL
, 0x0,
265 { &hf_tacacs_destport
,
266 { "Destination port", "tacacs.destport",
267 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
270 { "Line", "tacacs.line",
271 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
273 { &hf_tacacs_result2
,
274 { "Result 2", "tacacs.result2",
275 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
277 { &hf_tacacs_result3
,
278 { "Result 3", "tacacs.result3",
279 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
281 { &hf_tacacs_username
,
282 { "Username", "tacacs.username",
283 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
285 { &hf_tacacs_password
,
286 { "Password", "tacacs.password",
287 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
291 static gint
*ett
[] = {
294 proto_tacacs
= proto_register_protocol("TACACS", "TACACS", "tacacs");
295 proto_register_field_array(proto_tacacs
, hf
, array_length(hf
));
296 proto_register_subtree_array(ett
, array_length(ett
));
300 proto_reg_handoff_tacacs(void)
302 dissector_handle_t tacacs_handle
;
304 tacacs_handle
= create_dissector_handle(dissect_tacacs
, proto_tacacs
);
305 dissector_add_uint("udp.port", UDP_PORT_TACACS
, tacacs_handle
);
308 static int proto_tacplus
= -1;
309 static int hf_tacplus_response
= -1;
310 static int hf_tacplus_request
= -1;
311 static int hf_tacplus_majvers
= -1;
312 static int hf_tacplus_minvers
= -1;
313 static int hf_tacplus_type
= -1;
314 static int hf_tacplus_seqno
= -1;
315 static int hf_tacplus_flags
= -1;
316 static int hf_tacplus_flags_payload_type
= -1;
317 static int hf_tacplus_flags_connection_type
= -1;
318 static int hf_tacplus_acct_flags
= -1;
319 static int hf_tacplus_acct_flags_more
= -1;
320 static int hf_tacplus_acct_flags_start
= -1;
321 static int hf_tacplus_acct_flags_stop
= -1;
322 static int hf_tacplus_acct_flags_watchdog
= -1;
323 static int hf_tacplus_session_id
= -1;
324 static int hf_tacplus_packet_len
= -1;
325 static int hf_tacplus_auth_password
= -1;
326 static int hf_tacplus_port
= -1;
327 static int hf_tacplus_remote_address
= -1;
328 static int hf_tacplus_chap_challenge
= -1;
329 static int hf_tacplus_chap_response
= -1;
330 static int hf_tacplus_mschap_challenge
= -1;
331 static int hf_tacplus_mschap_response
= -1;
332 static int hf_tacplus_arap_nas_challenge
= -1;
333 static int hf_tacplus_arap_remote_challenge
= -1;
334 static int hf_tacplus_arap_remote_response
= -1;
335 static int hf_tacplus_privilege_level
= -1;
336 static int hf_tacplus_authentication_type
= -1;
337 static int hf_tacplus_service
= -1;
338 static int hf_tacplus_user_len
= -1;
339 static int hf_tacplus_user
= -1;
340 static int hf_tacplus_port_len
= -1;
341 static int hf_tacplus_remote_address_len
= -1;
342 static int hf_tacplus_arg_length
= -1;
343 static int hf_tacplus_arg_value
= -1;
344 static int hf_tacplus_chap_id
= -1;
345 static int hf_tacplus_mschap_id
= -1;
346 static int hf_tacplus_authen_action
= -1;
347 static int hf_tacplus_body_authen_req_cont_flags
= -1;
348 static int hf_tacplus_body_authen_req_cont_user_length
= -1;
349 static int hf_tacplus_body_authen_req_cont_user
= -1;
350 static int hf_tacplus_body_authen_req_cont_data_length
= -1;
351 static int hf_tacplus_body_authen_rep_status
= -1;
352 static int hf_tacplus_body_authen_rep_flags
= -1;
353 static int hf_tacplus_body_authen_rep_server_msg_len
= -1;
354 static int hf_tacplus_body_authen_rep_server_msg
= -1;
355 static int hf_tacplus_body_authen_rep_server_data_len
= -1;
356 static int hf_tacplus_body_author_req_auth_method
= -1;
357 static int hf_tacplus_body_author_req_arg_count
= -1;
358 static int hf_tacplus_body_author_rep_auth_status
= -1;
359 static int hf_tacplus_body_author_rep_server_msg_len
= -1;
360 static int hf_tacplus_body_author_rep_server_data_len
= -1;
361 static int hf_tacplus_body_author_rep_arg_count
= -1;
362 static int hf_tacplus_acct_authen_method
= -1;
363 static int hf_tacplus_acct_arg_count
= -1;
364 static int hf_tacplus_body_acct_status
= -1;
365 static int hf_tacplus_body_acct_server_msg_len
= -1;
366 static int hf_tacplus_body_acct_server_msg
= -1;
367 static int hf_tacplus_body_acct_data_len
= -1;
368 static int hf_tacplus_body_acct_data
= -1;
370 static gint ett_tacplus
= -1;
371 static gint ett_tacplus_body
= -1;
372 static gint ett_tacplus_body_chap
= -1;
373 static gint ett_tacplus_flags
= -1;
374 static gint ett_tacplus_acct_flags
= -1;
376 typedef struct _tacplus_key_entry
{
377 address
*s
; /* Server address */
378 address
*c
; /* client address */
383 tacplus_decrypted_tvb_setup( tvbuff_t
*tvb
, tvbuff_t
**dst_tvb
, packet_info
*pinfo
, guint32 len
, guint8 version
, const char *key
)
386 guint8 session_id
[4];
388 /* TODO Check the possibility to use pinfo->decrypted_data */
389 /* session_id is in NETWORK Byte Order, and is used as byte array in the md5_xor */
391 tvb_memcpy(tvb
, session_id
, 4,4);
393 buff
= (guint8
*)tvb_memdup(NULL
, tvb
, TAC_PLUS_HDR_SIZE
, len
);
396 md5_xor( buff
, key
, len
, session_id
,version
, tvb_get_guint8(tvb
,2) );
398 /* Allocate a new tvbuff, referring to the decrypted data. */
399 *dst_tvb
= tvb_new_child_real_data(tvb
, buff
, len
, len
);
401 /* Arrange that the allocated packet data copy be freed when the
403 tvb_set_free_cb( *dst_tvb
, g_free
);
405 /* Add the decrypted data to the data source list. */
406 add_new_data_source(pinfo
, *dst_tvb
, "TACACS+ Decrypted");
411 dissect_tacplus_args_list( tvbuff_t
*tvb
, proto_tree
*tree
, int data_off
, int len_off
, int arg_cnt
)
415 for(i
=0;i
<arg_cnt
;i
++){
416 int len
=tvb_get_guint8(tvb
,len_off
+i
);
417 proto_tree_add_uint_format(tree
, hf_tacplus_arg_length
, tvb
, len_off
+i
, 1, len
,
418 "Arg[%d] length: %d", i
, len
);
419 tvb_get_nstringz0(tvb
, data_off
, len
+1, buff
);
420 proto_tree_add_string_format(tree
, hf_tacplus_arg_value
, tvb
, data_off
, len
, buff
,
421 "Arg[%d] value: %s", i
, buff
);
428 proto_tree_add_tacplus_common_fields( tvbuff_t
*tvb
, proto_tree
*tree
, int offset
, int var_off
)
432 proto_tree_add_item(tree
, hf_tacplus_privilege_level
, tvb
, offset
, 1, ENC_NA
);
436 proto_tree_add_item(tree
, hf_tacplus_authentication_type
, tvb
, offset
, 1, ENC_NA
);
440 proto_tree_add_item(tree
, hf_tacplus_service
, tvb
, offset
, 1, ENC_NA
);
443 /* user_len && user */
444 val
=tvb_get_guint8(tvb
,offset
);
445 proto_tree_add_uint(tree
, hf_tacplus_user_len
, tvb
, offset
, 1, val
);
448 proto_tree_add_item(tree
, hf_tacplus_user
, tvb
, var_off
, val
, ENC_NA
);
454 /* port_len && port */
455 val
=tvb_get_guint8(tvb
,offset
);
456 proto_tree_add_uint(tree
, hf_tacplus_port_len
, tvb
, offset
, 1, val
);
458 proto_tree_add_item(tree
, hf_tacplus_port
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
463 /* rem_addr_len && rem_addr */
464 val
=tvb_get_guint8(tvb
,offset
);
465 proto_tree_add_uint(tree
, hf_tacplus_remote_address_len
, tvb
, offset
, 1, val
);
467 proto_tree_add_item(tree
, hf_tacplus_remote_address
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
474 dissect_tacplus_body_authen_req_login( tvbuff_t
* tvb
, proto_tree
*tree
, int var_off
)
477 val
=tvb_get_guint8( tvb
, AUTHEN_S_DATA_LEN_OFF
);
479 switch ( tvb_get_guint8(tvb
, AUTHEN_S_AUTHEN_TYPE_OFF
) ) { /* authen_type */
481 case TAC_PLUS_AUTHEN_TYPE_ASCII
:
482 proto_tree_add_text( tree
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, "Data: %d (not used)", val
);
484 proto_tree_add_text( tree
, tvb
, var_off
, val
, "Data" );
487 case TAC_PLUS_AUTHEN_TYPE_PAP
:
488 proto_tree_add_text( tree
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, "Password Length %d", val
);
490 proto_tree_add_item(tree
, hf_tacplus_auth_password
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
494 case TAC_PLUS_AUTHEN_TYPE_CHAP
:
495 proto_tree_add_text( tree
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, "CHAP Data Length %d", val
);
499 guint8 chal_len
=val
-(1+16); /* Response field alwayes 16 octets */
500 pi
= proto_tree_add_text(tree
, tvb
, var_off
, val
, "CHAP Data" );
501 pt
= proto_item_add_subtree( pi
, ett_tacplus_body_chap
);
502 proto_tree_add_item(pt
, hf_tacplus_chap_id
, tvb
, var_off
, 1, ENC_NA
);
504 proto_tree_add_item(pt
, hf_tacplus_chap_challenge
, tvb
, var_off
, chal_len
, ENC_ASCII
|ENC_NA
);
506 proto_tree_add_item(pt
, hf_tacplus_chap_response
, tvb
, var_off
, 16, ENC_ASCII
|ENC_NA
);
509 case TAC_PLUS_AUTHEN_TYPE_MSCHAP
:
510 proto_tree_add_text( tree
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, "MSCHAP Data Length %d", val
);
514 guint8 chal_len
=val
-(1+49); /* Response field alwayes 49 octets */
515 pi
= proto_tree_add_text(tree
, tvb
, var_off
, val
, "MSCHAP Data" );
516 pt
= proto_item_add_subtree( pi
, ett_tacplus_body_chap
);
517 proto_tree_add_item(pt
, hf_tacplus_mschap_id
, tvb
, var_off
, 1, ENC_NA
);
519 proto_tree_add_item(pt
, hf_tacplus_mschap_challenge
, tvb
, var_off
, chal_len
, ENC_ASCII
|ENC_NA
);
521 proto_tree_add_item(pt
, hf_tacplus_mschap_response
, tvb
, var_off
, 49, ENC_ASCII
|ENC_NA
);
524 case TAC_PLUS_AUTHEN_TYPE_ARAP
:
525 proto_tree_add_text( tree
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, "ARAP Data Length %d", val
);
529 pi
= proto_tree_add_text(tree
, tvb
, var_off
, val
, "ARAP Data" );
530 pt
= proto_item_add_subtree( pi
, ett_tacplus_body_chap
);
531 proto_tree_add_item(pt
, hf_tacplus_arap_nas_challenge
, tvb
, var_off
, 8, ENC_ASCII
|ENC_NA
);
533 proto_tree_add_item(pt
, hf_tacplus_arap_remote_challenge
, tvb
, var_off
, 8, ENC_ASCII
|ENC_NA
);
535 proto_tree_add_item(pt
, hf_tacplus_arap_remote_response
, tvb
, var_off
, 8, ENC_ASCII
|ENC_NA
);
539 default: /* Should not be reached */
540 proto_tree_add_text( tree
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, "Data: %d", val
);
542 proto_tree_add_text( tree
, tvb
, var_off
, val
, "Data" );
548 dissect_tacplus_body_authen_req( tvbuff_t
* tvb
, proto_tree
*tree
)
551 int var_off
=AUTHEN_S_VARDATA_OFF
;
554 val
=tvb_get_guint8( tvb
, AUTHEN_S_ACTION_OFF
);
555 proto_tree_add_item(tree
, hf_tacplus_authen_action
, tvb
, AUTHEN_S_ACTION_OFF
, 1, ENC_NA
);
556 var_off
=proto_tree_add_tacplus_common_fields( tvb
, tree
, AUTHEN_S_PRIV_LVL_OFF
, AUTHEN_S_VARDATA_OFF
);
559 case TAC_PLUS_AUTHEN_LOGIN
:
560 dissect_tacplus_body_authen_req_login( tvb
, tree
, var_off
);
562 case TAC_PLUS_AUTHEN_SENDAUTH
:
568 dissect_tacplus_body_authen_req_cont( tvbuff_t
*tvb
, proto_tree
*tree
)
571 int var_off
=AUTHEN_C_VARDATA_OFF
;
574 val
=tvb_get_guint8( tvb
, AUTHEN_C_FLAGS_OFF
);
575 ti
= proto_tree_add_item(tree
, hf_tacplus_body_authen_req_cont_flags
, tvb
, AUTHEN_C_FLAGS_OFF
, 1, ENC_NA
);
576 if (val
&TAC_PLUS_CONTINUE_FLAG_ABORT
)
577 proto_item_append_text(ti
, "(Abort)");
579 val
=tvb_get_ntohs( tvb
, AUTHEN_C_USER_LEN_OFF
);
580 proto_tree_add_uint(tree
, hf_tacplus_body_authen_req_cont_user_length
, tvb
, AUTHEN_C_USER_LEN_OFF
, 2, val
);
582 proto_tree_add_item(tree
, hf_tacplus_body_authen_req_cont_user
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
586 val
=tvb_get_ntohs( tvb
, AUTHEN_C_DATA_LEN_OFF
);
587 proto_tree_add_uint(tree
, hf_tacplus_body_authen_req_cont_data_length
, tvb
, AUTHEN_C_DATA_LEN_OFF
, 2, val
);
589 proto_tree_add_text( tree
, tvb
, var_off
, val
, "Data" );
596 dissect_tacplus_body_authen_rep( tvbuff_t
*tvb
, proto_tree
*tree
)
599 int var_off
=AUTHEN_R_VARDATA_OFF
;
602 proto_tree_add_item(tree
, hf_tacplus_body_authen_rep_status
, tvb
, AUTHEN_R_STATUS_OFF
, 1, ENC_NA
);
604 val
=tvb_get_guint8( tvb
, AUTHEN_R_FLAGS_OFF
);
605 ti
= proto_tree_add_item(tree
, hf_tacplus_body_authen_rep_flags
, tvb
, AUTHEN_R_FLAGS_OFF
, 1, ENC_NA
);
606 if (val
&TAC_PLUS_REPLY_FLAG_NOECHO
)
607 proto_item_append_text(ti
, "(NoEcho)");
609 val
=tvb_get_ntohs(tvb
, AUTHEN_R_SRV_MSG_LEN_OFF
);
610 proto_tree_add_uint(tree
, hf_tacplus_body_authen_rep_server_msg_len
, tvb
, AUTHEN_R_SRV_MSG_LEN_OFF
, 2, val
);
613 proto_tree_add_item(tree
, hf_tacplus_body_authen_rep_server_msg
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
617 val
=tvb_get_ntohs(tvb
, AUTHEN_R_DATA_LEN_OFF
);
618 proto_tree_add_uint(tree
, hf_tacplus_body_authen_rep_server_data_len
, tvb
, AUTHEN_R_DATA_LEN_OFF
, 2, val
);
620 proto_tree_add_text(tree
, tvb
, var_off
, val
, "Data" );
625 dissect_tacplus_body_author_req( tvbuff_t
* tvb
, proto_tree
*tree
)
630 proto_tree_add_item(tree
, hf_tacplus_body_author_req_auth_method
, tvb
, AUTHOR_Q_AUTH_METH_OFF
, 1, ENC_NA
);
632 val
= tvb_get_guint8( tvb
, AUTHOR_Q_ARGC_OFF
);
633 var_off
=proto_tree_add_tacplus_common_fields( tvb
, tree
,
634 AUTHOR_Q_PRIV_LVL_OFF
,
635 AUTHOR_Q_VARDATA_OFF
+ val
);
637 proto_tree_add_item(tree
, hf_tacplus_body_author_req_arg_count
, tvb
, AUTHOR_Q_ARGC_OFF
, 1, ENC_NA
);
639 /* var_off points after rem_addr */
641 dissect_tacplus_args_list( tvb
, tree
, var_off
, AUTHOR_Q_VARDATA_OFF
, val
);
645 dissect_tacplus_body_author_rep( tvbuff_t
* tvb
, proto_tree
*tree
)
647 int offset
=AUTHOR_R_VARDATA_OFF
;
650 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_auth_status
, tvb
, AUTHOR_R_STATUS_OFF
, 1, ENC_NA
);
652 val
=tvb_get_ntohs( tvb
, AUTHOR_R_SRV_MSG_LEN_OFF
);
654 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_server_msg_len
, tvb
, AUTHOR_R_SRV_MSG_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
656 val
=tvb_get_ntohs( tvb
, AUTHOR_R_DATA_LEN_OFF
);
658 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_server_data_len
, tvb
, AUTHOR_R_DATA_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
660 val
=tvb_get_guint8( tvb
, AUTHOR_R_ARGC_OFF
);
662 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_arg_count
, tvb
, AUTHOR_R_ARGC_OFF
, 1, ENC_NA
);
664 dissect_tacplus_args_list( tvb
, tree
, offset
, AUTHOR_R_VARDATA_OFF
, val
);
668 dissect_tacplus_body_acct_req( tvbuff_t
* tvb
, proto_tree
*tree
)
673 proto_tree
*flags_tree
;
675 tf
= proto_tree_add_item( tree
, hf_tacplus_acct_flags
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
677 flags_tree
= proto_item_add_subtree( tf
, ett_tacplus_acct_flags
);
678 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_more
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
679 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_start
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
680 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_stop
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
681 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_watchdog
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
683 proto_tree_add_item(tree
, hf_tacplus_acct_authen_method
, tvb
, ACCT_Q_METHOD_OFF
, 1, ENC_BIG_ENDIAN
);
684 val
=tvb_get_guint8( tvb
, ACCT_Q_ARG_CNT_OFF
);
687 var_off
=proto_tree_add_tacplus_common_fields( tvb
, tree
,
689 ACCT_Q_VARDATA_OFF
+val
692 proto_tree_add_item(tree
, hf_tacplus_acct_arg_count
, tvb
, ACCT_Q_ARG_CNT_OFF
, 1, ENC_BIG_ENDIAN
);
694 dissect_tacplus_args_list( tvb
, tree
, var_off
, ACCT_Q_VARDATA_OFF
, val
);
700 dissect_tacplus_body_acct_rep( tvbuff_t
* tvb
, proto_tree
*tree
)
702 int val
, var_off
=ACCT_Q_VARDATA_OFF
;
705 proto_tree_add_item(tree
, hf_tacplus_body_acct_status
, tvb
, ACCT_R_STATUS_OFF
, 1, ENC_BIG_ENDIAN
);
708 val
=tvb_get_ntohs( tvb
, ACCT_R_SRV_MSG_LEN_OFF
);
709 proto_tree_add_item(tree
, hf_tacplus_body_acct_server_msg_len
, tvb
, ACCT_R_SRV_MSG_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
711 proto_tree_add_item(tree
, hf_tacplus_body_acct_server_msg
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
716 val
=tvb_get_ntohs( tvb
, ACCT_R_DATA_LEN_OFF
);
717 proto_tree_add_item(tree
, hf_tacplus_body_acct_data_len
, tvb
, ACCT_R_DATA_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
719 proto_tree_add_item(tree
, hf_tacplus_body_acct_data
, tvb
, var_off
, val
, ENC_ASCII
|ENC_NA
);
726 dissect_tacplus_body(tvbuff_t
* hdr_tvb
, tvbuff_t
* tvb
, proto_tree
* tree
)
728 int type
= tvb_get_guint8( hdr_tvb
, H_TYPE_OFF
);
729 int seq_no
= tvb_get_guint8( hdr_tvb
, H_SEQ_NO_OFF
);
732 case TAC_PLUS_AUTHEN
:
733 if ( seq_no
& 0x01) {
735 dissect_tacplus_body_authen_req( tvb
, tree
);
737 dissect_tacplus_body_authen_req_cont( tvb
, tree
);
739 dissect_tacplus_body_authen_rep( tvb
, tree
);
742 case TAC_PLUS_AUTHOR
:
744 dissect_tacplus_body_author_req( tvb
, tree
);
746 dissect_tacplus_body_author_rep( tvb
, tree
);
750 dissect_tacplus_body_acct_req( tvb
, tree
);
752 dissect_tacplus_body_acct_rep( tvb
, tree
);
755 proto_tree_add_text( tree
, tvb
, 0, tvb_length( tvb
), "Bogus..");
762 tacplus_print_key_entry( gpointer data
, gpointer user_data
)
764 tacplus_key_entry
*tacplus_data
=(tacplus_key_entry
*)data
;
766 printf("%s:%s=%s\n", ep_address_to_str( tacplus_data
->s
),
767 ep_address_to_str( tacplus_data
->c
), tacplus_data
->k
);
769 printf("%s:%s\n", ep_address_to_str( tacplus_data
->s
),
770 ep_address_to_str( tacplus_data
->c
) );
775 cmp_conv_address( gconstpointer p1
, gconstpointer p2
)
777 const tacplus_key_entry
*a1
=(const tacplus_key_entry
*)p1
;
778 const tacplus_key_entry
*a2
=(const tacplus_key_entry
*)p2
;
782 tacplus_print_key_entry( p1, NULL );
784 tacplus_print_key_entry( p2, NULL );
786 ret
=CMP_ADDRESS( a1
->s
, a2
->s
);
788 ret
=CMP_ADDRESS( a1
->c
, a2
->c
);
791 printf("No Client found!"); */
793 /* printf("No Server found!"); */
799 find_key( address
*srv
, address
*cln
)
801 tacplus_key_entry data
;
806 /* printf("Looking for: ");
807 tacplus_print_key_entry( (gconstpointer)&data, NULL ); */
808 match
=g_slist_find_custom( tacplus_keys
, (gpointer
)&data
, cmp_conv_address
);
809 /* printf("Finished (%p)\n", match); */
811 return ((tacplus_key_entry
*)match
->data
)->k
;
813 return (tacplus_keys
?NULL
:tacplus_opt_key
);
817 mkipv4_address( address
**addr
, const char *str_addr
)
822 *addr
=(address
*)g_malloc( sizeof(address
) );
823 addr_data
=(char *)g_malloc( 4 );
824 ret
= inet_pton( AF_INET
, str_addr
, addr_data
);
826 SET_ADDRESS(*addr
, AT_IPv4
, 4, addr_data
);
828 SET_ADDRESS(*addr
, AT_STRINGZ
, (int)strlen(ADDR_INVLD
)+1, ADDR_INVLD
);
831 parse_tuple( char *key_from_option
)
834 tacplus_key_entry
*tacplus_data
=(tacplus_key_entry
*)g_malloc( sizeof(tacplus_key_entry
) );
836 printf("keys: %s\n", key_from_option );
838 client
=strchr(key_from_option
,'/');
840 g_free(tacplus_data
);
844 key
=strchr(client
,'=');
846 g_free(tacplus_data
);
851 printf("%s %s => %s\n", key_from_option, client, key );
853 mkipv4_address( &tacplus_data
->s
, key_from_option
);
854 mkipv4_address( &tacplus_data
->c
, client
);
855 tacplus_data
->k
=g_strdup(key
);
856 tacplus_keys
= g_slist_prepend( tacplus_keys
, tacplus_data
);
861 parse_tacplus_keys( const char *keys_from_option
)
863 char *key_copy
,*s
,*s1
;
867 g_slist_free( tacplus_keys
);
871 if( !strchr( keys_from_option
, '/' ) ){
872 /* option not in client/server=key format */
875 key_copy
=g_strdup(keys_from_option
);
878 if( (s1
=strchr( s
, ' ' )) != NULL
)
885 g_slist_foreach( tacplus_keys
, tacplus_print_key_entry
, GINT_TO_POINTER(1) );
890 dissect_tacplus(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
892 tvbuff_t
*new_tvb
=NULL
;
893 proto_tree
*tacplus_tree
;
894 proto_item
*ti
, *hidden_item
;
895 guint8 version
,flags
;
896 proto_tree
*flags_tree
;
900 gboolean request
=( pinfo
->destport
== TCP_PORT_TACACS
);
901 const char *key
=NULL
;
903 len
= tvb_get_ntohl(tvb
, 8);
905 if(len
> (guint
)tvb_length_remaining(tvb
, 12) &&
906 pinfo
->can_desegment
&& tacplus_preference_desegment
) {
907 pinfo
->desegment_offset
= 0;
908 pinfo
->desegment_len
= len
;
913 key
=find_key( &pinfo
->dst
, &pinfo
->src
);
915 key
=find_key( &pinfo
->src
, &pinfo
->dst
);
917 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TACACS+");
919 col_add_fstr( pinfo
->cinfo
, COL_INFO
, "%s: %s",
921 val_to_str(tvb_get_guint8(tvb
,1), tacplus_type_vals
, "Unknown (0x%02x)"));
925 ti
= proto_tree_add_item(tree
, proto_tacplus
, tvb
, 0, -1, ENC_NA
);
927 tacplus_tree
= proto_item_add_subtree(ti
, ett_tacplus
);
928 if (pinfo
->match_uint
== pinfo
->destport
)
930 hidden_item
= proto_tree_add_boolean(tacplus_tree
,
931 hf_tacplus_request
, tvb
, 0, 0, TRUE
);
935 hidden_item
= proto_tree_add_boolean(tacplus_tree
,
936 hf_tacplus_response
, tvb
, 0, 0, TRUE
);
938 PROTO_ITEM_SET_HIDDEN(hidden_item
);
940 version
= tvb_get_guint8(tvb
,0);
941 proto_tree_add_uint_format_value(tacplus_tree
, hf_tacplus_majvers
, tvb
, 0, 1,
944 (version
&0xf0)==0xc0?"TACACS+":"Unknown Version");
945 proto_tree_add_uint(tacplus_tree
, hf_tacplus_minvers
, tvb
, 0, 1,
947 proto_tree_add_item(tacplus_tree
, hf_tacplus_type
, tvb
, 1, 1,
949 proto_tree_add_item(tacplus_tree
, hf_tacplus_seqno
, tvb
, 2, 1,
951 flags
= tvb_get_guint8(tvb
,3);
952 tf
= proto_tree_add_uint_format_value(tacplus_tree
, hf_tacplus_flags
,
954 "0x%02x (%s payload, %s)", flags
,
955 (flags
&FLAGS_UNENCRYPTED
) ? "Unencrypted" : "Encrypted",
956 (flags
&FLAGS_SINGLE
) ? "Single connection" : "Multiple Connections" );
957 flags_tree
= proto_item_add_subtree(tf
, ett_tacplus_flags
);
958 proto_tree_add_boolean(flags_tree
, hf_tacplus_flags_payload_type
,
960 proto_tree_add_boolean(flags_tree
, hf_tacplus_flags_connection_type
,
962 proto_tree_add_item(tacplus_tree
, hf_tacplus_session_id
, tvb
, 4, 4,
965 tmp_pi
= proto_tree_add_uint(tacplus_tree
, hf_tacplus_packet_len
, tvb
, 8, 4, len
);
967 expert_add_info_format(pinfo
, tmp_pi
, &ei_tacplus_packet_len_invalid
, "Invalid length: %u", len
);
970 tmp_pi
= proto_tree_add_text(tacplus_tree
, tvb
, TAC_PLUS_HDR_SIZE
, len
, "%s%s",
971 ((flags
&FLAGS_UNENCRYPTED
)?"":"Encrypted "), request
?"Request":"Reply" );
973 if( flags
&FLAGS_UNENCRYPTED
) {
974 new_tvb
= tvb_new_subset( tvb
, TAC_PLUS_HDR_SIZE
, len
, len
);
978 tacplus_decrypted_tvb_setup( tvb
, &new_tvb
, pinfo
, len
, version
, key
);
982 /* Check to see if I've a decrypted tacacs packet */
983 if( !(flags
&FLAGS_UNENCRYPTED
) ){
984 tmp_pi
= proto_tree_add_text(tacplus_tree
, new_tvb
, 0, len
, "Decrypted %s",
985 request
?"Request":"Reply" );
987 dissect_tacplus_body( tvb
, new_tvb
, proto_item_add_subtree( tmp_pi
, ett_tacplus_body
));
993 tacplus_pref_cb(void)
995 parse_tacplus_keys( tacplus_opt_key
);
999 proto_register_tacplus(void)
1001 static hf_register_info hf
[] = {
1002 { &hf_tacplus_response
,
1003 { "Response", "tacplus.response",
1004 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1005 "TRUE if TACACS+ response", HFILL
}},
1006 { &hf_tacplus_request
,
1007 { "Request", "tacplus.request",
1008 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
1009 "TRUE if TACACS+ request", HFILL
}},
1010 { &hf_tacplus_majvers
,
1011 { "Major version", "tacplus.majvers",
1012 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1013 "Major version number", HFILL
}},
1014 { &hf_tacplus_minvers
,
1015 { "Minor version", "tacplus.minvers",
1016 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1017 "Minor version number", HFILL
}},
1019 { "Type", "tacplus.type",
1020 FT_UINT8
, BASE_DEC
, VALS(tacplus_type_vals
), 0x0,
1022 { &hf_tacplus_seqno
,
1023 { "Sequence number", "tacplus.seqno",
1024 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1026 { &hf_tacplus_flags
,
1027 { "Flags", "tacplus.flags",
1028 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1030 { &hf_tacplus_flags_payload_type
,
1031 { "Unencrypted", "tacplus.flags.unencrypted",
1032 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), FLAGS_UNENCRYPTED
,
1033 "Is payload unencrypted?", HFILL
}},
1034 { &hf_tacplus_flags_connection_type
,
1035 { "Single Connection", "tacplus.flags.singleconn",
1036 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), FLAGS_SINGLE
,
1037 "Is this a single connection?", HFILL
}},
1038 { &hf_tacplus_acct_flags
,
1039 { "Flags", "tacplus.acct.flags",
1040 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1042 { &hf_tacplus_acct_flags_more
,
1043 { "More", "tacplus.acct.flags.more",
1044 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_MORE
,
1046 { &hf_tacplus_acct_flags_start
,
1047 { "Start", "tacplus.acct.flags.start",
1048 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_START
,
1050 { &hf_tacplus_acct_flags_stop
,
1051 { "Stop", "tacplus.acct.flags.stop",
1052 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_STOP
,
1054 { &hf_tacplus_acct_flags_watchdog
,
1055 { "Watchdog", "tacplus.acct.flags.watchdog",
1056 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_WATCHDOG
,
1058 { &hf_tacplus_session_id
,
1059 { "Session ID", "tacplus.session_id",
1060 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1062 { &hf_tacplus_packet_len
,
1063 { "Packet length", "tacplus.packet_len",
1064 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1066 { &hf_tacplus_auth_password
,
1067 { "Password", "tacplus.auth_password",
1068 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1071 { "Port", "tacplus.port",
1072 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1074 { &hf_tacplus_remote_address
,
1075 { "Remote Address", "tacplus.remote_address",
1076 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1078 { &hf_tacplus_chap_challenge
,
1079 { "Challenge", "tacplus.chap.challenge",
1080 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1082 { &hf_tacplus_chap_response
,
1083 { "Response", "tacplus.chap.response",
1084 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1086 { &hf_tacplus_mschap_challenge
,
1087 { "Challenge", "tacplus.mschap.challenge",
1088 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1090 { &hf_tacplus_mschap_response
,
1091 { "Response", "tacplus.mschap.response",
1092 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1094 { &hf_tacplus_arap_nas_challenge
,
1095 { "Nas Challenge", "tacplus.arap.nas_challenge",
1096 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1098 { &hf_tacplus_arap_remote_challenge
,
1099 { "Remote Challenge", "tacplus.arap.remote_challenge",
1100 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1102 { &hf_tacplus_arap_remote_response
,
1103 { "Remote Response", "tacplus.arap.remote_response",
1104 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1106 { &hf_tacplus_privilege_level
,
1107 { "Privilege Level", "tacplus.privilege_level",
1108 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1110 { &hf_tacplus_authentication_type
,
1111 { "Authentication type", "tacplus.authentication_type",
1112 FT_UINT8
, BASE_DEC
, VALS(tacplus_authen_type_vals
), 0x0,
1114 { &hf_tacplus_service
,
1115 { "Service", "tacplus.service",
1116 FT_UINT8
, BASE_DEC
, VALS(tacplus_authen_service_vals
), 0x0,
1118 { &hf_tacplus_user_len
,
1119 { "User len", "tacplus.user_len",
1120 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1123 { "User", "tacplus.user",
1124 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1126 { &hf_tacplus_port_len
,
1127 { "Port len", "tacplus.port_len",
1128 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1130 { &hf_tacplus_remote_address_len
,
1131 { "Remaddr len", "tacplus.address_len",
1132 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1134 { &hf_tacplus_arg_length
,
1135 { "Length", "tacplus.arg_length",
1136 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1138 { &hf_tacplus_arg_value
,
1139 { "Value", "tacplus.arg_value",
1140 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1142 { &hf_tacplus_chap_id
,
1143 { "ID", "tacplus.chap.id",
1144 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1146 { &hf_tacplus_mschap_id
,
1147 { "ID", "tacplus.mschap.id",
1148 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1150 { &hf_tacplus_authen_action
,
1151 { "Action", "tacplus.authen_action",
1152 FT_UINT8
, BASE_DEC
, VALS(tacplus_authen_action_vals
), 0x0,
1154 { &hf_tacplus_body_authen_req_cont_flags
,
1155 { "Flags", "tacplus.body_authen_req_cont.flags",
1156 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1158 { &hf_tacplus_body_authen_req_cont_user_length
,
1159 { "User length", "tacplus.body_authen_req_cont.user_length",
1160 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1162 { &hf_tacplus_body_authen_req_cont_data_length
,
1163 { "Data length", "tacplus.body_authen_req_cont.data_length",
1164 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1166 { &hf_tacplus_body_authen_req_cont_user
,
1167 { "User", "tacplus.body_authen_req_cont.user",
1168 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1170 { &hf_tacplus_body_authen_rep_status
,
1171 { "Status", "tacplus.body_authen_rep.status",
1172 FT_UINT8
, BASE_HEX
, VALS(tacplus_reply_status_vals
), 0x0,
1174 { &hf_tacplus_body_authen_rep_flags
,
1175 { "Flags", "tacplus.body_authen_rep.flags",
1176 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1178 { &hf_tacplus_body_authen_rep_server_msg_len
,
1179 { "Server message length", "tacplus.body_authen_rep.server_msg_len",
1180 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1182 { &hf_tacplus_body_authen_rep_server_msg
,
1183 { "Server message", "tacplus.body_authen_rep.server_msg",
1184 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1186 { &hf_tacplus_body_authen_rep_server_data_len
,
1187 { "Data length", "tacplus.body_authen_rep_server.data_len",
1188 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1190 { &hf_tacplus_body_author_req_auth_method
,
1191 { "Auth Method", "tacplus.body_author_req.auth_method",
1192 FT_UINT8
, BASE_HEX
, VALS(tacplus_authen_method
), 0x0,
1194 { &hf_tacplus_body_author_req_arg_count
,
1195 { "Arg count", "tacplus.body_author_req.arg_count",
1196 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1198 { &hf_tacplus_body_author_rep_auth_status
,
1199 { "Auth Status", "tacplus.body_author_rep.auth_status",
1200 FT_UINT8
, BASE_HEX
, VALS(tacplus_author_status
), 0x0,
1202 { &hf_tacplus_body_author_rep_server_msg_len
,
1203 { "Server Msg length", "tacplus.body_author_rep_server.msg_len",
1204 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1206 { &hf_tacplus_body_author_rep_server_data_len
,
1207 { "Data length", "tacplus.body_author_rep_server.data_len",
1208 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1210 { &hf_tacplus_body_author_rep_arg_count
,
1211 { "Arg count", "tacplus.body_author_rep.arg_count",
1212 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1214 { &hf_tacplus_acct_authen_method
,
1215 { "Auth Method", "tacplus.acct.auth_method",
1216 FT_UINT8
, BASE_HEX
, VALS(tacplus_authen_method
), 0x0,
1218 { &hf_tacplus_acct_arg_count
,
1219 { "Arg count", "tacplus.acct.arg_count",
1220 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1222 { &hf_tacplus_body_acct_status
,
1223 { "Status", "tacplus.body_acct.status",
1224 FT_UINT8
, BASE_HEX
, VALS(tacplus_acct_status
), 0x0,
1226 { &hf_tacplus_body_acct_server_msg_len
,
1227 { "Server Msg length", "tacplus.body_acct.msg_len",
1228 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1230 { &hf_tacplus_body_acct_data_len
,
1231 { "Data length", "tacplus.body_acct.data_len",
1232 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1234 { &hf_tacplus_body_acct_server_msg
,
1235 { "Server message", "tacplus.body_acct.server_msg",
1236 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1238 { &hf_tacplus_body_acct_data
,
1239 { "Data", "tacplus.body_acct.data",
1240 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1243 static gint
*ett
[] = {
1246 &ett_tacplus_acct_flags
,
1248 &ett_tacplus_body_chap
,
1251 static ei_register_info ei
[] = {
1252 { &ei_tacplus_packet_len_invalid
, { "tacplus.packet_len.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid length", EXPFILL
}},
1255 module_t
*tacplus_module
;
1256 expert_module_t
* expert_tacplus
;
1258 proto_tacplus
= proto_register_protocol("TACACS+", "TACACS+", "tacplus");
1259 proto_register_field_array(proto_tacplus
, hf
, array_length(hf
));
1260 proto_register_subtree_array(ett
, array_length(ett
));
1261 expert_tacplus
= expert_register_protocol(proto_tacplus
);
1262 expert_register_field_array(expert_tacplus
, ei
, array_length(ei
));
1263 tacplus_module
= prefs_register_protocol (proto_tacplus
, tacplus_pref_cb
);
1265 prefs_register_bool_preference(tacplus_module
, "desegment", "Reassemble TACACS+ messages spanning multiple TCP segments.", "Whether the TACACS+ dissector should reassemble 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
);
1267 prefs_register_string_preference ( tacplus_module
, "key",
1268 "TACACS+ Encryption Key", "TACACS+ Encryption Key", &tacplus_opt_key
);
1272 proto_reg_handoff_tacplus(void)
1274 dissector_handle_t tacplus_handle
;
1276 tacplus_handle
= create_dissector_handle(dissect_tacplus
,
1278 dissector_add_uint("tcp.port", TCP_PORT_TACACS
, tacplus_handle
);
1285 md5_xor( guint8
*data
, const char *key
, int data_len
, guint8
*session_id
, guint8 version
, guint8 seq_no
)
1289 md5_byte_t
*md5_buff
;
1290 md5_byte_t hash
[MD5_LEN
]; /* the md5 hash */
1292 md5_state_t mdcontext
;
1294 md5_len
= 4 /* sizeof(session_id) */ + strlen(key
)
1295 + sizeof(version
) + sizeof(seq_no
);
1297 md5_buff
= (md5_byte_t
*)wmem_alloc(wmem_packet_scope(), md5_len
+MD5_LEN
);
1301 memcpy(mdp
, session_id
, 4);
1303 memcpy(mdp
, key
, strlen(key
));
1309 md5_init(&mdcontext
);
1310 md5_append(&mdcontext
, md5_buff
, md5_len
);
1311 md5_finish(&mdcontext
,hash
);
1313 for (i
= 0; i
< data_len
; i
+= 16) {
1315 for (j
= 0; j
< 16; j
++) {
1316 if ((i
+ j
) >= data_len
) {
1317 i
= data_len
+1; /* To exit from the external loop */
1320 data
[i
+ j
] ^= hash
[j
];
1322 memcpy(mdp
, hash
, MD5_LEN
);
1323 md5_init(&mdcontext
);
1324 md5_append(&mdcontext
, md5_buff
, md5_len
);
1325 md5_finish(&mdcontext
,hash
);