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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * Copied from old packet-tacacs.c
14 * SPDX-License-Identifier: GPL-2.0-or-later
18 /* rfc-1492 for tacacs and xtacacs
19 * draft-grant-tacacs-02.txt for tacacs+ (tacplus)
20 * https://tools.ietf.org/html/draft-grant-tacacs-02
25 #include <epan/packet.h>
26 #include <epan/prefs.h>
27 #include <epan/expert.h>
28 #include <epan/addr_resolv.h>
29 #include <wsutil/wsgcrypt.h>
31 #include <wsutil/array.h>
33 #include "packet-tcp.h"
34 #include "packet-tacacs.h"
36 void proto_reg_handoff_tacacs(void);
37 void proto_register_tacacs(void);
38 static dissector_handle_t tacacs_handle
;
40 void proto_reg_handoff_tacplus(void);
41 void proto_register_tacplus(void);
42 static dissector_handle_t tacplus_handle
;
44 static void md5_xor( uint8_t *data
, const char *key
, int data_len
, uint8_t *session_id
, uint8_t version
, uint8_t seq_no
);
45 static int dissect_tacplus_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
);
47 static int proto_tacacs
;
48 static int hf_tacacs_version
;
49 static int hf_tacacs_type
;
50 static int hf_tacacs_nonce
;
51 static int hf_tacacs_userlen
;
52 static int hf_tacacs_passlen
;
53 static int hf_tacacs_response
;
54 static int hf_tacacs_reason
;
55 static int hf_tacacs_result1
;
56 static int hf_tacacs_destaddr
;
57 static int hf_tacacs_destport
;
58 static int hf_tacacs_line
;
59 static int hf_tacacs_result2
;
60 static int hf_tacacs_result3
;
61 static int hf_tacacs_username
;
62 static int hf_tacacs_password
;
64 static int ett_tacacs
;
66 static bool tacplus_preference_desegment
= true;
68 static const char *tacplus_opt_key
;
69 static GSList
*tacplus_keys
;
71 #define ADDR_INVLD "invalid"
73 #define VERSION_TACACS 0x00
74 #define VERSION_XTACACS 0x80
76 static const value_string tacacs_version_vals
[] = {
77 { VERSION_TACACS
, "TACACS" },
78 { VERSION_XTACACS
, "XTACACS" },
82 #define TACACS_LOGIN 1
83 #define TACACS_RESPONSE 2
84 #define TACACS_CHANGE 3
85 #define TACACS_FOLLOW 4
86 #define TACACS_CONNECT 5
87 #define TACACS_SUPERUSER 6
88 #define TACACS_LOGOUT 7
89 #define TACACS_RELOAD 8
90 #define TACACS_SLIP_ON 9
91 #define TACACS_SLIP_OFF 10
92 #define TACACS_SLIP_ADDR 11
93 static const value_string tacacs_type_vals
[] = {
94 { TACACS_LOGIN
, "Login" },
95 { TACACS_RESPONSE
, "Response" },
96 { TACACS_CHANGE
, "Change" },
97 { TACACS_FOLLOW
, "Follow" },
98 { TACACS_CONNECT
, "Connect" },
99 { TACACS_SUPERUSER
, "Superuser" },
100 { TACACS_LOGOUT
, "Logout" },
101 { TACACS_RELOAD
, "Reload" },
102 { TACACS_SLIP_ON
, "SLIP on" },
103 { TACACS_SLIP_OFF
, "SLIP off" },
104 { TACACS_SLIP_ADDR
, "SLIP Addr" },
107 static const value_string tacacs_reason_vals
[] = {
119 static const value_string tacacs_resp_vals
[] = {
120 { 0 , "this is not a response" },
126 #define UDP_PORT_TACACS 49
127 #define TCP_PORT_TACACS 49
130 dissect_tacacs(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
132 proto_tree
*tacacs_tree
;
134 uint32_t version
,type
,userlen
,passlen
;
136 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TACACS");
137 col_clear(pinfo
->cinfo
, COL_INFO
);
139 version
= tvb_get_uint8(tvb
,0);
141 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "XTACACS");
144 type
= tvb_get_uint8(tvb
,1);
145 col_add_str(pinfo
->cinfo
, COL_INFO
,
146 val_to_str(type
, tacacs_type_vals
, "Unknown (0x%02x)"));
150 ti
= proto_tree_add_protocol_format(tree
, proto_tacacs
,
151 tvb
, 0, -1, version
==0?"TACACS":"XTACACS");
152 tacacs_tree
= proto_item_add_subtree(ti
, ett_tacacs
);
154 proto_tree_add_uint(tacacs_tree
, hf_tacacs_version
, tvb
, 0, 1, version
);
155 proto_tree_add_uint(tacacs_tree
, hf_tacacs_type
, tvb
, 1, 1, type
);
156 proto_tree_add_item(tacacs_tree
, hf_tacacs_nonce
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
160 if (type
!=TACACS_RESPONSE
)
162 proto_tree_add_item_ret_uint(tacacs_tree
, hf_tacacs_userlen
, tvb
, 4, 1, ENC_NA
, &userlen
);
163 proto_tree_add_item_ret_uint(tacacs_tree
, hf_tacacs_passlen
, tvb
, 5, 1, ENC_NA
, &passlen
);
164 proto_tree_add_item(tacacs_tree
, hf_tacacs_username
, tvb
, 6, userlen
, ENC_ASCII
);
165 proto_tree_add_item(tacacs_tree
, hf_tacacs_password
, tvb
, 6+userlen
, passlen
, ENC_ASCII
);
169 proto_tree_add_item(tacacs_tree
, hf_tacacs_response
, tvb
, 4, 1, ENC_BIG_ENDIAN
);
170 proto_tree_add_item(tacacs_tree
, hf_tacacs_reason
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
175 proto_tree_add_item_ret_uint(tacacs_tree
, hf_tacacs_userlen
, tvb
, 4, 1, ENC_NA
, &userlen
);
176 proto_tree_add_item_ret_uint(tacacs_tree
, hf_tacacs_passlen
, tvb
, 5, 1, ENC_NA
, &passlen
);
177 proto_tree_add_item(tacacs_tree
, hf_tacacs_response
, tvb
, 6, 1, ENC_BIG_ENDIAN
);
178 proto_tree_add_item(tacacs_tree
, hf_tacacs_reason
, tvb
, 7, 1, ENC_BIG_ENDIAN
);
179 proto_tree_add_item(tacacs_tree
, hf_tacacs_result1
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
180 proto_tree_add_item(tacacs_tree
, hf_tacacs_destaddr
, tvb
, 12, 4, ENC_BIG_ENDIAN
);
181 proto_tree_add_item(tacacs_tree
, hf_tacacs_destport
, tvb
, 16, 2, ENC_BIG_ENDIAN
);
182 proto_tree_add_item(tacacs_tree
, hf_tacacs_line
, tvb
, 18, 2, ENC_BIG_ENDIAN
);
183 proto_tree_add_item(tacacs_tree
, hf_tacacs_result2
, tvb
, 20, 4, ENC_BIG_ENDIAN
);
184 proto_tree_add_item(tacacs_tree
, hf_tacacs_result3
, tvb
, 24, 2, ENC_BIG_ENDIAN
);
185 if (type
!=TACACS_RESPONSE
)
187 proto_tree_add_item(tacacs_tree
, hf_tacacs_username
, tvb
, 26, userlen
, ENC_ASCII
);
188 proto_tree_add_item(tacacs_tree
, hf_tacacs_password
, tvb
, 26+userlen
, passlen
, ENC_ASCII
);
192 return tvb_captured_length(tvb
);
196 proto_register_tacacs(void)
198 static hf_register_info hf
[] = {
199 { &hf_tacacs_version
,
200 { "Version", "tacacs.version",
201 FT_UINT8
, BASE_HEX
, VALS(tacacs_version_vals
), 0x0,
204 { "Type", "tacacs.type",
205 FT_UINT8
, BASE_DEC
, VALS(tacacs_type_vals
), 0x0,
208 { "Nonce", "tacacs.nonce",
209 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
211 { &hf_tacacs_userlen
,
212 { "Username length", "tacacs.userlen",
213 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
215 { &hf_tacacs_passlen
,
216 { "Password length", "tacacs.passlen",
217 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
219 { &hf_tacacs_response
,
220 { "Response", "tacacs.response",
221 FT_UINT8
, BASE_DEC
, VALS(tacacs_resp_vals
), 0x0,
224 { "Reason", "tacacs.reason",
225 FT_UINT8
, BASE_DEC
, VALS(tacacs_reason_vals
), 0x0,
227 { &hf_tacacs_result1
,
228 { "Result 1", "tacacs.result1",
229 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
231 { &hf_tacacs_destaddr
,
232 { "Destination address", "tacacs.destaddr",
233 FT_IPv4
, BASE_NONE
, NULL
, 0x0,
235 { &hf_tacacs_destport
,
236 { "Destination port", "tacacs.destport",
237 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
240 { "Line", "tacacs.line",
241 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
243 { &hf_tacacs_result2
,
244 { "Result 2", "tacacs.result2",
245 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
247 { &hf_tacacs_result3
,
248 { "Result 3", "tacacs.result3",
249 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
251 { &hf_tacacs_username
,
252 { "Username", "tacacs.username",
253 FT_STRING
, BASE_NONE
, NULL
, 0x0,
255 { &hf_tacacs_password
,
256 { "Password", "tacacs.password",
257 FT_STRING
, BASE_NONE
, NULL
, 0x0,
261 static int *ett
[] = {
264 proto_tacacs
= proto_register_protocol("TACACS", "TACACS", "tacacs");
265 proto_register_field_array(proto_tacacs
, hf
, array_length(hf
));
266 proto_register_subtree_array(ett
, array_length(ett
));
267 tacacs_handle
= register_dissector("tacacs", dissect_tacacs
, proto_tacacs
);
271 proto_reg_handoff_tacacs(void)
273 dissector_add_uint_with_preference("udp.port", UDP_PORT_TACACS
, tacacs_handle
);
276 static int proto_tacplus
;
277 static int hf_tacplus_response
;
278 static int hf_tacplus_request
;
279 static int hf_tacplus_majvers
;
280 static int hf_tacplus_minvers
;
281 static int hf_tacplus_type
;
282 static int hf_tacplus_seqno
;
283 static int hf_tacplus_flags
;
284 static int hf_tacplus_flags_payload_type
;
285 static int hf_tacplus_flags_connection_type
;
286 static int hf_tacplus_acct_flags
;
287 static int hf_tacplus_acct_flags_more
;
288 static int hf_tacplus_acct_flags_start
;
289 static int hf_tacplus_acct_flags_stop
;
290 static int hf_tacplus_acct_flags_watchdog
;
291 static int hf_tacplus_session_id
;
292 static int hf_tacplus_packet_len
;
293 static int hf_tacplus_auth_password
;
294 static int hf_tacplus_port
;
295 static int hf_tacplus_remote_address
;
296 static int hf_tacplus_chap_challenge
;
297 static int hf_tacplus_chap_response
;
298 static int hf_tacplus_mschap_challenge
;
299 static int hf_tacplus_mschap_response
;
300 static int hf_tacplus_arap_nas_challenge
;
301 static int hf_tacplus_arap_remote_challenge
;
302 static int hf_tacplus_arap_remote_response
;
303 static int hf_tacplus_privilege_level
;
304 static int hf_tacplus_authentication_type
;
305 static int hf_tacplus_service
;
306 static int hf_tacplus_user_len
;
307 static int hf_tacplus_user
;
308 static int hf_tacplus_port_len
;
309 static int hf_tacplus_remote_address_len
;
310 static int hf_tacplus_arg_length
;
311 static int hf_tacplus_arg_value
;
312 static int hf_tacplus_chap_id
;
313 static int hf_tacplus_mschap_id
;
314 static int hf_tacplus_authen_action
;
315 static int hf_tacplus_body_authen_req_cont_flags
;
316 static int hf_tacplus_body_authen_req_cont_user_length
;
317 static int hf_tacplus_body_authen_req_cont_user
;
318 static int hf_tacplus_body_authen_req_cont_data_length
;
319 static int hf_tacplus_body_authen_rep_status
;
320 static int hf_tacplus_body_authen_rep_flags
;
321 static int hf_tacplus_body_authen_rep_server_msg_len
;
322 static int hf_tacplus_body_authen_rep_server_msg
;
323 static int hf_tacplus_body_authen_rep_server_data_len
;
324 static int hf_tacplus_body_author_req_auth_method
;
325 static int hf_tacplus_body_author_req_arg_count
;
326 static int hf_tacplus_body_author_rep_auth_status
;
327 static int hf_tacplus_body_author_rep_server_msg_len
;
328 static int hf_tacplus_body_author_rep_server_data_len
;
329 static int hf_tacplus_body_author_rep_arg_count
;
330 static int hf_tacplus_acct_authen_method
;
331 static int hf_tacplus_acct_arg_count
;
332 static int hf_tacplus_body_acct_status
;
333 static int hf_tacplus_body_acct_server_msg_len
;
334 static int hf_tacplus_body_acct_server_msg
;
335 static int hf_tacplus_body_acct_data_len
;
336 static int hf_tacplus_body_acct_data
;
337 static int hf_tacplus_data
;
338 /* Generated from convert_proto_tree_add_text.pl */
339 static int hf_tacplus_ascii_length
;
340 static int hf_tacplus_arap_data_length
;
341 static int hf_tacplus_mschap_data_length
;
342 static int hf_tacplus_chap_data_length
;
343 static int hf_tacplus_password_length
;
344 static int hf_tacplus_data_length
;
346 static int ett_tacplus
;
347 static int ett_tacplus_body
;
348 static int ett_tacplus_body_chap
;
349 static int ett_tacplus_flags
;
350 static int ett_tacplus_acct_flags
;
352 static expert_field ei_tacplus_packet_len_invalid
;
353 static expert_field ei_tacplus_unencrypted
;
354 static expert_field ei_tacplus_bogus_data
;
356 typedef struct _tacplus_key_entry
{
357 address
*s
; /* Server address */
358 address
*c
; /* client address */
363 tacplus_decrypted_tvb_setup( tvbuff_t
*tvb
, tvbuff_t
**dst_tvb
, packet_info
*pinfo
, uint32_t len
, uint8_t version
, const char *key
)
366 uint8_t session_id
[4];
368 /* TODO Check the possibility to use pinfo->decrypted_data */
369 /* session_id is in NETWORK Byte Order, and is used as byte array in the md5_xor */
371 tvb_memcpy(tvb
, session_id
, 4,4);
373 buff
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, TAC_PLUS_HDR_SIZE
, len
);
376 md5_xor( buff
, key
, len
, session_id
,version
, tvb_get_uint8(tvb
,2) );
378 /* Allocate a new tvbuff, referring to the decrypted data. */
379 *dst_tvb
= tvb_new_child_real_data(tvb
, buff
, len
, len
);
381 /* Add the decrypted data to the data source list. */
382 add_new_data_source(pinfo
, *dst_tvb
, "TACACS+ Decrypted");
387 dissect_tacplus_args_list( tvbuff_t
*tvb
, proto_tree
*tree
, int data_off
, int len_off
, int arg_cnt
)
392 for(i
=0;i
<arg_cnt
;i
++){
393 len
=tvb_get_uint8(tvb
,len_off
+i
);
394 proto_tree_add_uint_format(tree
, hf_tacplus_arg_length
, tvb
, len_off
+i
, 1, len
,
395 "Arg[%d] length: %d", i
, len
);
396 value
=tvb_get_string_enc(wmem_packet_scope(), tvb
, data_off
, len
, ENC_ASCII
|ENC_NA
);
397 proto_tree_add_string_format(tree
, hf_tacplus_arg_value
, tvb
, data_off
, len
, value
,
398 "Arg[%d] value: %s", i
, value
);
405 proto_tree_add_tacplus_common_fields( tvbuff_t
*tvb
, proto_tree
*tree
, int offset
, int var_off
)
409 proto_tree_add_item(tree
, hf_tacplus_privilege_level
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
413 proto_tree_add_item(tree
, hf_tacplus_authentication_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
417 proto_tree_add_item(tree
, hf_tacplus_service
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
420 /* user_len && user */
421 val
=tvb_get_uint8(tvb
,offset
);
422 proto_tree_add_uint(tree
, hf_tacplus_user_len
, tvb
, offset
, 1, val
);
425 proto_tree_add_item(tree
, hf_tacplus_user
, tvb
, var_off
, val
, ENC_ASCII
);
431 /* port_len && port */
432 val
=tvb_get_uint8(tvb
,offset
);
433 proto_tree_add_uint(tree
, hf_tacplus_port_len
, tvb
, offset
, 1, val
);
435 proto_tree_add_item(tree
, hf_tacplus_port
, tvb
, var_off
, val
, ENC_ASCII
);
440 /* rem_addr_len && rem_addr */
441 val
=tvb_get_uint8(tvb
,offset
);
442 proto_tree_add_uint(tree
, hf_tacplus_remote_address_len
, tvb
, offset
, 1, val
);
444 proto_tree_add_item(tree
, hf_tacplus_remote_address
, tvb
, var_off
, val
, ENC_ASCII
);
451 dissect_tacplus_body_authen_req_login( tvbuff_t
* tvb
, proto_tree
*tree
, int var_off
)
454 val
=tvb_get_uint8( tvb
, AUTHEN_S_DATA_LEN_OFF
);
456 switch ( tvb_get_uint8(tvb
, AUTHEN_S_AUTHEN_TYPE_OFF
) ) { /* authen_type */
458 case TAC_PLUS_AUTHEN_TYPE_ASCII
:
459 proto_tree_add_item(tree
, hf_tacplus_ascii_length
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, ENC_BIG_ENDIAN
);
461 proto_tree_add_item( tree
, hf_tacplus_data
, tvb
, var_off
, val
, ENC_NA
);
464 case TAC_PLUS_AUTHEN_TYPE_PAP
:
465 proto_tree_add_item(tree
, hf_tacplus_password_length
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, ENC_BIG_ENDIAN
);
467 proto_tree_add_item(tree
, hf_tacplus_auth_password
, tvb
, var_off
, val
, ENC_ASCII
);
471 case TAC_PLUS_AUTHEN_TYPE_CHAP
:
472 proto_tree_add_item(tree
, hf_tacplus_chap_data_length
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, ENC_BIG_ENDIAN
);
475 uint8_t chal_len
=val
-(1+16); /* Response field alwayes 16 octets */
476 pt
= proto_tree_add_subtree(tree
, tvb
, var_off
, val
, ett_tacplus_body_chap
, NULL
, "CHAP Data" );
477 proto_tree_add_item(pt
, hf_tacplus_chap_id
, tvb
, var_off
, 1, ENC_BIG_ENDIAN
);
479 proto_tree_add_item(pt
, hf_tacplus_chap_challenge
, tvb
, var_off
, chal_len
, ENC_ASCII
);
481 proto_tree_add_item(pt
, hf_tacplus_chap_response
, tvb
, var_off
, 16, ENC_ASCII
);
484 case TAC_PLUS_AUTHEN_TYPE_MSCHAP
:
485 proto_tree_add_item(tree
, hf_tacplus_mschap_data_length
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, ENC_BIG_ENDIAN
);
488 uint8_t chal_len
=val
-(1+49); /* Response field alwayes 49 octets */
489 pt
= proto_tree_add_subtree(tree
, tvb
, var_off
, val
, ett_tacplus_body_chap
, NULL
, "MSCHAP Data" );
490 proto_tree_add_item(pt
, hf_tacplus_mschap_id
, tvb
, var_off
, 1, ENC_BIG_ENDIAN
);
492 proto_tree_add_item(pt
, hf_tacplus_mschap_challenge
, tvb
, var_off
, chal_len
, ENC_ASCII
);
494 proto_tree_add_item(pt
, hf_tacplus_mschap_response
, tvb
, var_off
, 49, ENC_ASCII
);
497 case TAC_PLUS_AUTHEN_TYPE_ARAP
:
498 proto_tree_add_item(tree
, hf_tacplus_arap_data_length
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, ENC_BIG_ENDIAN
);
501 pt
= proto_tree_add_subtree(tree
, tvb
, var_off
, val
, ett_tacplus_body_chap
, NULL
, "ARAP Data" );
502 proto_tree_add_item(pt
, hf_tacplus_arap_nas_challenge
, tvb
, var_off
, 8, ENC_ASCII
);
504 proto_tree_add_item(pt
, hf_tacplus_arap_remote_challenge
, tvb
, var_off
, 8, ENC_ASCII
);
506 proto_tree_add_item(pt
, hf_tacplus_arap_remote_response
, tvb
, var_off
, 8, ENC_ASCII
);
510 default: /* Should not be reached */
511 proto_tree_add_item(tree
, hf_tacplus_data_length
, tvb
, AUTHEN_S_DATA_LEN_OFF
, 1, ENC_BIG_ENDIAN
);
513 proto_tree_add_item( tree
, hf_tacplus_data
, tvb
, var_off
, val
, ENC_NA
);
519 dissect_tacplus_body_authen_req( tvbuff_t
* tvb
, proto_tree
*tree
)
522 int var_off
=AUTHEN_S_VARDATA_OFF
;
525 val
=tvb_get_uint8( tvb
, AUTHEN_S_ACTION_OFF
);
526 proto_tree_add_item(tree
, hf_tacplus_authen_action
, tvb
, AUTHEN_S_ACTION_OFF
, 1, ENC_BIG_ENDIAN
);
527 var_off
=proto_tree_add_tacplus_common_fields( tvb
, tree
, AUTHEN_S_PRIV_LVL_OFF
, AUTHEN_S_VARDATA_OFF
);
530 case TAC_PLUS_AUTHEN_LOGIN
:
531 dissect_tacplus_body_authen_req_login( tvb
, tree
, var_off
);
533 case TAC_PLUS_AUTHEN_SENDAUTH
:
539 dissect_tacplus_body_authen_req_cont( tvbuff_t
*tvb
, proto_tree
*tree
)
542 int var_off
=AUTHEN_C_VARDATA_OFF
;
545 val
=tvb_get_uint8( tvb
, AUTHEN_C_FLAGS_OFF
);
546 ti
= proto_tree_add_item(tree
, hf_tacplus_body_authen_req_cont_flags
, tvb
, AUTHEN_C_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
547 if (val
&TAC_PLUS_CONTINUE_FLAG_ABORT
)
548 proto_item_append_text(ti
, "(Abort)");
550 val
=tvb_get_ntohs( tvb
, AUTHEN_C_USER_LEN_OFF
);
551 proto_tree_add_uint(tree
, hf_tacplus_body_authen_req_cont_user_length
, tvb
, AUTHEN_C_USER_LEN_OFF
, 2, val
);
553 proto_tree_add_item(tree
, hf_tacplus_body_authen_req_cont_user
, tvb
, var_off
, val
, ENC_ASCII
);
557 val
=tvb_get_ntohs( tvb
, AUTHEN_C_DATA_LEN_OFF
);
558 proto_tree_add_uint(tree
, hf_tacplus_body_authen_req_cont_data_length
, tvb
, AUTHEN_C_DATA_LEN_OFF
, 2, val
);
560 proto_tree_add_item( tree
, hf_tacplus_data
, tvb
, var_off
, val
, ENC_NA
);
567 dissect_tacplus_body_authen_rep( tvbuff_t
*tvb
, proto_tree
*tree
)
570 int var_off
=AUTHEN_R_VARDATA_OFF
;
573 proto_tree_add_item(tree
, hf_tacplus_body_authen_rep_status
, tvb
, AUTHEN_R_STATUS_OFF
, 1, ENC_BIG_ENDIAN
);
575 val
=tvb_get_uint8( tvb
, AUTHEN_R_FLAGS_OFF
);
576 ti
= proto_tree_add_item(tree
, hf_tacplus_body_authen_rep_flags
, tvb
, AUTHEN_R_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
577 if (val
&TAC_PLUS_REPLY_FLAG_NOECHO
)
578 proto_item_append_text(ti
, "(NoEcho)");
580 val
=tvb_get_ntohs(tvb
, AUTHEN_R_SRV_MSG_LEN_OFF
);
581 proto_tree_add_uint(tree
, hf_tacplus_body_authen_rep_server_msg_len
, tvb
, AUTHEN_R_SRV_MSG_LEN_OFF
, 2, val
);
584 proto_tree_add_item(tree
, hf_tacplus_body_authen_rep_server_msg
, tvb
, var_off
, val
, ENC_ASCII
);
588 val
=tvb_get_ntohs(tvb
, AUTHEN_R_DATA_LEN_OFF
);
589 proto_tree_add_uint(tree
, hf_tacplus_body_authen_rep_server_data_len
, tvb
, AUTHEN_R_DATA_LEN_OFF
, 2, val
);
591 proto_tree_add_item(tree
, hf_tacplus_data
, tvb
, var_off
, val
, ENC_NA
);
596 dissect_tacplus_body_author_req( tvbuff_t
* tvb
, proto_tree
*tree
)
601 proto_tree_add_item(tree
, hf_tacplus_body_author_req_auth_method
, tvb
, AUTHOR_Q_AUTH_METH_OFF
, 1, ENC_BIG_ENDIAN
);
603 val
= tvb_get_uint8( tvb
, AUTHOR_Q_ARGC_OFF
);
604 var_off
=proto_tree_add_tacplus_common_fields( tvb
, tree
,
605 AUTHOR_Q_PRIV_LVL_OFF
,
606 AUTHOR_Q_VARDATA_OFF
+ val
);
608 proto_tree_add_item(tree
, hf_tacplus_body_author_req_arg_count
, tvb
, AUTHOR_Q_ARGC_OFF
, 1, ENC_BIG_ENDIAN
);
610 /* var_off points after rem_addr */
612 dissect_tacplus_args_list( tvb
, tree
, var_off
, AUTHOR_Q_VARDATA_OFF
, val
);
616 dissect_tacplus_body_author_rep( tvbuff_t
* tvb
, proto_tree
*tree
)
618 int offset
=AUTHOR_R_VARDATA_OFF
;
621 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_auth_status
, tvb
, AUTHOR_R_STATUS_OFF
, 1, ENC_BIG_ENDIAN
);
623 val
=tvb_get_ntohs( tvb
, AUTHOR_R_SRV_MSG_LEN_OFF
);
625 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_server_msg_len
, tvb
, AUTHOR_R_SRV_MSG_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
627 val
=tvb_get_ntohs( tvb
, AUTHOR_R_DATA_LEN_OFF
);
629 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_server_data_len
, tvb
, AUTHOR_R_DATA_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
631 val
=tvb_get_uint8( tvb
, AUTHOR_R_ARGC_OFF
);
633 proto_tree_add_item(tree
, hf_tacplus_body_author_rep_arg_count
, tvb
, AUTHOR_R_ARGC_OFF
, 1, ENC_BIG_ENDIAN
);
635 dissect_tacplus_args_list( tvb
, tree
, offset
, AUTHOR_R_VARDATA_OFF
, val
);
639 dissect_tacplus_body_acct_req( tvbuff_t
* tvb
, proto_tree
*tree
)
644 proto_tree
*flags_tree
;
646 tf
= proto_tree_add_item( tree
, hf_tacplus_acct_flags
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
648 flags_tree
= proto_item_add_subtree( tf
, ett_tacplus_acct_flags
);
649 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_more
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
650 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_start
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
651 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_stop
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
652 proto_tree_add_item(flags_tree
, hf_tacplus_acct_flags_watchdog
, tvb
, ACCT_Q_FLAGS_OFF
, 1, ENC_BIG_ENDIAN
);
654 proto_tree_add_item(tree
, hf_tacplus_acct_authen_method
, tvb
, ACCT_Q_METHOD_OFF
, 1, ENC_BIG_ENDIAN
);
655 val
=tvb_get_uint8( tvb
, ACCT_Q_ARG_CNT_OFF
);
658 var_off
=proto_tree_add_tacplus_common_fields( tvb
, tree
,
660 ACCT_Q_VARDATA_OFF
+val
663 proto_tree_add_item(tree
, hf_tacplus_acct_arg_count
, tvb
, ACCT_Q_ARG_CNT_OFF
, 1, ENC_BIG_ENDIAN
);
665 dissect_tacplus_args_list( tvb
, tree
, var_off
, ACCT_Q_VARDATA_OFF
, val
);
671 dissect_tacplus_body_acct_rep( tvbuff_t
* tvb
, proto_tree
*tree
)
673 int val
, var_off
=ACCT_R_VARDATA_OFF
;
676 proto_tree_add_item(tree
, hf_tacplus_body_acct_status
, tvb
, ACCT_R_STATUS_OFF
, 1, ENC_BIG_ENDIAN
);
679 val
=tvb_get_ntohs( tvb
, ACCT_R_SRV_MSG_LEN_OFF
);
680 proto_tree_add_item(tree
, hf_tacplus_body_acct_server_msg_len
, tvb
, ACCT_R_SRV_MSG_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
682 proto_tree_add_item(tree
, hf_tacplus_body_acct_server_msg
, tvb
, var_off
, val
, ENC_ASCII
);
687 val
=tvb_get_ntohs( tvb
, ACCT_R_DATA_LEN_OFF
);
688 proto_tree_add_item(tree
, hf_tacplus_body_acct_data_len
, tvb
, ACCT_R_DATA_LEN_OFF
, 2, ENC_BIG_ENDIAN
);
690 proto_tree_add_item(tree
, hf_tacplus_body_acct_data
, tvb
, var_off
, val
, ENC_ASCII
);
697 dissect_tacplus_body(tvbuff_t
* hdr_tvb
, packet_info
*pinfo
, tvbuff_t
* tvb
, proto_tree
* tree
)
699 int type
= tvb_get_uint8( hdr_tvb
, H_TYPE_OFF
);
700 int seq_no
= tvb_get_uint8( hdr_tvb
, H_SEQ_NO_OFF
);
703 case TAC_PLUS_AUTHEN
:
704 if ( seq_no
& 0x01) {
706 dissect_tacplus_body_authen_req( tvb
, tree
);
708 dissect_tacplus_body_authen_req_cont( tvb
, tree
);
710 dissect_tacplus_body_authen_rep( tvb
, tree
);
713 case TAC_PLUS_AUTHOR
:
715 dissect_tacplus_body_author_req( tvb
, tree
);
717 dissect_tacplus_body_author_rep( tvb
, tree
);
721 dissect_tacplus_body_acct_req( tvb
, tree
);
723 dissect_tacplus_body_acct_rep( tvb
, tree
);
726 proto_tree_add_expert( tree
, pinfo
, &ei_tacplus_bogus_data
, tvb
, 0, -1);
733 tacplus_print_key_entry( void *data
, void *user_data
)
735 tacplus_key_entry
*tacplus_data
=(tacplus_key_entry
*)data
;
738 s_str
= address_to_str( NULL
, tacplus_data
->s
);
739 c_str
= address_to_str( NULL
, tacplus_data
->c
);
741 ws_debug_printf("%s:%s=%s\n", s_str
, c_str
, tacplus_data
->k
);
743 ws_debug_printf("%s:%s\n", s_str
, c_str
);
745 wmem_free(NULL
, s_str
);
746 wmem_free(NULL
, c_str
);
750 cmp_conv_address( const void *p1
, const void *p2
)
752 const tacplus_key_entry
*a1
=(const tacplus_key_entry
*)p1
;
753 const tacplus_key_entry
*a2
=(const tacplus_key_entry
*)p2
;
756 ws_debug_printf("p1=>");
757 tacplus_print_key_entry( p1, NULL );
758 ws_debug_printf("p2=>");
759 tacplus_print_key_entry( p2, NULL );
761 ret
=cmp_address( a1
->s
, a2
->s
);
763 ret
=cmp_address( a1
->c
, a2
->c
);
766 ws_debug_printf("No Client found!"); */
768 /* ws_debug_printf("No Server found!"); */
774 find_key( address
*srv
, address
*cln
)
776 tacplus_key_entry data
;
781 /* ws_debug_printf("Looking for: ");
782 tacplus_print_key_entry( (const void *)&data, NULL ); */
783 match
=g_slist_find_custom( tacplus_keys
, (void *)&data
, cmp_conv_address
);
784 /* ws_debug_printf("Finished (%p)\n", match); */
786 return ((tacplus_key_entry
*)match
->data
)->k
;
788 return (tacplus_keys
?NULL
:tacplus_opt_key
);
792 mkipv4_address( address
**addr
, const char *str_addr
)
797 *addr
=g_new(address
, 1);
798 addr_data
=(char *)g_malloc( 4 );
799 ret
= str_to_ip(str_addr
, addr_data
);
801 set_address(*addr
, AT_IPv4
, 4, addr_data
);
803 g_free(addr_data
); /* not set, not used */
804 set_address(*addr
, AT_STRINGZ
, (int)strlen(ADDR_INVLD
)+1, ADDR_INVLD
);
808 parse_tuple( char *key_from_option
)
811 tacplus_key_entry
*tacplus_data
=g_new(tacplus_key_entry
, 1);
813 ws_debug_printf("keys: %s\n", key_from_option );
815 client
=strchr(key_from_option
,'/');
817 g_free(tacplus_data
);
821 key
=strchr(client
,'=');
823 g_free(tacplus_data
);
828 ws_debug_printf("%s %s => %s\n", key_from_option, client, key );
830 mkipv4_address( &tacplus_data
->s
, key_from_option
);
831 mkipv4_address( &tacplus_data
->c
, client
);
832 tacplus_data
->k
=g_strdup(key
);
833 tacplus_keys
= g_slist_prepend( tacplus_keys
, tacplus_data
);
838 parse_tacplus_keys( const char *keys_from_option
)
840 char *key_copy
,*s
,*s1
;
844 g_slist_free( tacplus_keys
);
848 if( !strchr( keys_from_option
, '/' ) ){
849 /* option not in client/server=key format */
852 key_copy
=g_strdup(keys_from_option
);
855 if( (s1
=strchr( s
, ' ' )) != NULL
)
862 g_slist_foreach( tacplus_keys
, tacplus_print_key_entry
, GINT_TO_POINTER(1) );
867 get_tacplus_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
869 return (unsigned)tvb_get_ntohl(tvb
, offset
+H_LENGTH_OFF
) + TAC_PLUS_HDR_SIZE
;
873 dissect_tacplus(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
875 tcp_dissect_pdus(tvb
, pinfo
, tree
, tacplus_preference_desegment
, TAC_PLUS_HDR_SIZE
, get_tacplus_message_len
, dissect_tacplus_message
, data
);
876 return tvb_captured_length(tvb
);
880 dissect_tacplus_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
882 tvbuff_t
*new_tvb
=NULL
;
883 proto_tree
*tacplus_tree
, *body_tree
;
884 proto_item
*ti
, *hidden_item
;
885 uint8_t version
,flags
;
886 proto_tree
*flags_tree
;
890 bool request
=( pinfo
->destport
== TCP_PORT_TACACS
);
891 const char *key
=NULL
;
893 len
= tvb_get_ntohl(tvb
, 8);
896 key
=find_key( &pinfo
->dst
, &pinfo
->src
);
898 key
=find_key( &pinfo
->src
, &pinfo
->dst
);
900 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TACACS+");
902 col_add_fstr( pinfo
->cinfo
, COL_INFO
, "%s: %s",
904 val_to_str(tvb_get_uint8(tvb
,1), tacplus_type_vals
, "Unknown (0x%02x)"));
908 ti
= proto_tree_add_item(tree
, proto_tacplus
, tvb
, 0, -1, ENC_NA
);
910 tacplus_tree
= proto_item_add_subtree(ti
, ett_tacplus
);
911 if (pinfo
->match_uint
== pinfo
->destport
)
913 hidden_item
= proto_tree_add_boolean(tacplus_tree
,
914 hf_tacplus_request
, tvb
, 0, 0, true);
918 hidden_item
= proto_tree_add_boolean(tacplus_tree
,
919 hf_tacplus_response
, tvb
, 0, 0, true);
921 proto_item_set_hidden(hidden_item
);
923 version
= tvb_get_uint8(tvb
,0);
924 proto_tree_add_uint_format_value(tacplus_tree
, hf_tacplus_majvers
, tvb
, 0, 1,
927 (version
&0xf0)==0xc0?"TACACS+":"Unknown Version");
928 proto_tree_add_uint(tacplus_tree
, hf_tacplus_minvers
, tvb
, 0, 1,
930 proto_tree_add_item(tacplus_tree
, hf_tacplus_type
, tvb
, 1, 1,
932 proto_tree_add_item(tacplus_tree
, hf_tacplus_seqno
, tvb
, 2, 1,
934 flags
= tvb_get_uint8(tvb
,3);
935 tf
= proto_tree_add_uint_format_value(tacplus_tree
, hf_tacplus_flags
,
937 "0x%02x (%s payload, %s)", flags
,
938 (flags
&FLAGS_UNENCRYPTED
) ? "Unencrypted" : "Encrypted",
939 (flags
&FLAGS_SINGLE
) ? "Single connection" : "Multiple Connections" );
940 flags_tree
= proto_item_add_subtree(tf
, ett_tacplus_flags
);
941 tmp_pi
= proto_tree_add_boolean(flags_tree
, hf_tacplus_flags_payload_type
,
943 if (flags
&FLAGS_UNENCRYPTED
) {
944 expert_add_info(pinfo
, tmp_pi
, &ei_tacplus_unencrypted
);
946 proto_tree_add_boolean(flags_tree
, hf_tacplus_flags_connection_type
,
948 proto_tree_add_item(tacplus_tree
, hf_tacplus_session_id
, tvb
, 4, 4,
951 tmp_pi
= proto_tree_add_uint(tacplus_tree
, hf_tacplus_packet_len
, tvb
, 8, 4, len
);
953 expert_add_info_format(pinfo
, tmp_pi
, &ei_tacplus_packet_len_invalid
, "Invalid length: %u", len
);
956 body_tree
= proto_tree_add_subtree_format(tacplus_tree
, tvb
, TAC_PLUS_HDR_SIZE
, len
,
957 ett_tacplus_body
, NULL
, "%s%s", ((flags
&FLAGS_UNENCRYPTED
)?"":"Encrypted "), request
?"Request":"Reply" );
959 if( flags
&FLAGS_UNENCRYPTED
) {
960 new_tvb
= tvb_new_subset_length( tvb
, TAC_PLUS_HDR_SIZE
, len
);
964 tacplus_decrypted_tvb_setup( tvb
, &new_tvb
, pinfo
, len
, version
, key
);
968 /* Check to see if I've a decrypted tacacs packet */
969 if( !(flags
&FLAGS_UNENCRYPTED
) ){
970 body_tree
= proto_tree_add_subtree_format(tacplus_tree
, new_tvb
, 0, len
,
971 ett_tacplus_body
, NULL
, "Decrypted %s", request
?"Request":"Reply" );
973 dissect_tacplus_body( tvb
, pinfo
, new_tvb
, body_tree
);
976 return tvb_captured_length(tvb
);
980 tacplus_pref_cb(void)
982 parse_tacplus_keys( tacplus_opt_key
);
986 proto_register_tacplus(void)
988 static hf_register_info hf
[] = {
989 { &hf_tacplus_response
,
990 { "Response", "tacplus.response",
991 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
992 "true if TACACS+ response", HFILL
}},
993 { &hf_tacplus_request
,
994 { "Request", "tacplus.request",
995 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
996 "true if TACACS+ request", HFILL
}},
997 { &hf_tacplus_majvers
,
998 { "Major version", "tacplus.majvers",
999 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1000 "Major version number", HFILL
}},
1001 { &hf_tacplus_minvers
,
1002 { "Minor version", "tacplus.minvers",
1003 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1004 "Minor version number", HFILL
}},
1006 { "Type", "tacplus.type",
1007 FT_UINT8
, BASE_DEC
, VALS(tacplus_type_vals
), 0x0,
1009 { &hf_tacplus_seqno
,
1010 { "Sequence number", "tacplus.seqno",
1011 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1013 { &hf_tacplus_flags
,
1014 { "Flags", "tacplus.flags",
1015 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1017 { &hf_tacplus_flags_payload_type
,
1018 { "Unencrypted", "tacplus.flags.unencrypted",
1019 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), FLAGS_UNENCRYPTED
,
1020 "Is payload unencrypted? (deprecated)", HFILL
}},
1021 { &hf_tacplus_flags_connection_type
,
1022 { "Single Connection", "tacplus.flags.singleconn",
1023 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), FLAGS_SINGLE
,
1024 "Is this a single connection?", HFILL
}},
1025 { &hf_tacplus_acct_flags
,
1026 { "Flags", "tacplus.acct.flags",
1027 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1029 { &hf_tacplus_acct_flags_more
,
1030 { "More", "tacplus.acct.flags.more",
1031 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_MORE
,
1033 { &hf_tacplus_acct_flags_start
,
1034 { "Start", "tacplus.acct.flags.start",
1035 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_START
,
1037 { &hf_tacplus_acct_flags_stop
,
1038 { "Stop", "tacplus.acct.flags.stop",
1039 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_STOP
,
1041 { &hf_tacplus_acct_flags_watchdog
,
1042 { "Watchdog", "tacplus.acct.flags.watchdog",
1043 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), TAC_PLUS_ACCT_FLAG_WATCHDOG
,
1045 { &hf_tacplus_session_id
,
1046 { "Session ID", "tacplus.session_id",
1047 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1049 { &hf_tacplus_packet_len
,
1050 { "Packet length", "tacplus.packet_len",
1051 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
1053 { &hf_tacplus_auth_password
,
1054 { "Password", "tacplus.auth_password",
1055 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1058 { "Port", "tacplus.port",
1059 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1061 { &hf_tacplus_remote_address
,
1062 { "Remote Address", "tacplus.remote_address",
1063 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1065 { &hf_tacplus_chap_challenge
,
1066 { "Challenge", "tacplus.chap.challenge",
1067 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1069 { &hf_tacplus_chap_response
,
1070 { "Response", "tacplus.chap.response",
1071 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1073 { &hf_tacplus_mschap_challenge
,
1074 { "Challenge", "tacplus.mschap.challenge",
1075 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1077 { &hf_tacplus_mschap_response
,
1078 { "Response", "tacplus.mschap.response",
1079 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1081 { &hf_tacplus_arap_nas_challenge
,
1082 { "Nas Challenge", "tacplus.arap.nas_challenge",
1083 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1085 { &hf_tacplus_arap_remote_challenge
,
1086 { "Remote Challenge", "tacplus.arap.remote_challenge",
1087 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1089 { &hf_tacplus_arap_remote_response
,
1090 { "Remote Response", "tacplus.arap.remote_response",
1091 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1093 { &hf_tacplus_privilege_level
,
1094 { "Privilege Level", "tacplus.privilege_level",
1095 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1097 { &hf_tacplus_authentication_type
,
1098 { "Authentication type", "tacplus.authentication_type",
1099 FT_UINT8
, BASE_DEC
, VALS(tacplus_authen_type_vals
), 0x0,
1101 { &hf_tacplus_service
,
1102 { "Service", "tacplus.service",
1103 FT_UINT8
, BASE_DEC
, VALS(tacplus_authen_service_vals
), 0x0,
1105 { &hf_tacplus_user_len
,
1106 { "User len", "tacplus.user_len",
1107 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1110 { "User", "tacplus.user",
1111 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1113 { &hf_tacplus_port_len
,
1114 { "Port len", "tacplus.port_len",
1115 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1117 { &hf_tacplus_remote_address_len
,
1118 { "Remaddr len", "tacplus.address_len",
1119 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1121 { &hf_tacplus_arg_length
,
1122 { "Length", "tacplus.arg_length",
1123 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1125 { &hf_tacplus_arg_value
,
1126 { "Value", "tacplus.arg_value",
1127 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
1129 { &hf_tacplus_chap_id
,
1130 { "ID", "tacplus.chap.id",
1131 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1133 { &hf_tacplus_mschap_id
,
1134 { "ID", "tacplus.mschap.id",
1135 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1137 { &hf_tacplus_authen_action
,
1138 { "Action", "tacplus.authen_action",
1139 FT_UINT8
, BASE_DEC
, VALS(tacplus_authen_action_vals
), 0x0,
1141 { &hf_tacplus_body_authen_req_cont_flags
,
1142 { "Flags", "tacplus.body_authen_req_cont.flags",
1143 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1145 { &hf_tacplus_body_authen_req_cont_user_length
,
1146 { "User length", "tacplus.body_authen_req_cont.user_length",
1147 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1149 { &hf_tacplus_body_authen_req_cont_data_length
,
1150 { "Data length", "tacplus.body_authen_req_cont.data_length",
1151 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1153 { &hf_tacplus_body_authen_req_cont_user
,
1154 { "User", "tacplus.body_authen_req_cont.user",
1155 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1157 { &hf_tacplus_body_authen_rep_status
,
1158 { "Status", "tacplus.body_authen_rep.status",
1159 FT_UINT8
, BASE_HEX
, VALS(tacplus_reply_status_vals
), 0x0,
1161 { &hf_tacplus_body_authen_rep_flags
,
1162 { "Flags", "tacplus.body_authen_rep.flags",
1163 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1165 { &hf_tacplus_body_authen_rep_server_msg_len
,
1166 { "Server message length", "tacplus.body_authen_rep.server_msg_len",
1167 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1169 { &hf_tacplus_body_authen_rep_server_msg
,
1170 { "Server message", "tacplus.body_authen_rep.server_msg",
1171 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1173 { &hf_tacplus_body_authen_rep_server_data_len
,
1174 { "Data length", "tacplus.body_authen_rep_server.data_len",
1175 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1177 { &hf_tacplus_body_author_req_auth_method
,
1178 { "Auth Method", "tacplus.body_author_req.auth_method",
1179 FT_UINT8
, BASE_HEX
, VALS(tacplus_authen_method
), 0x0,
1181 { &hf_tacplus_body_author_req_arg_count
,
1182 { "Arg count", "tacplus.body_author_req.arg_count",
1183 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1185 { &hf_tacplus_body_author_rep_auth_status
,
1186 { "Auth Status", "tacplus.body_author_rep.auth_status",
1187 FT_UINT8
, BASE_HEX
, VALS(tacplus_author_status
), 0x0,
1189 { &hf_tacplus_body_author_rep_server_msg_len
,
1190 { "Server Msg length", "tacplus.body_author_rep_server.msg_len",
1191 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1193 { &hf_tacplus_body_author_rep_server_data_len
,
1194 { "Data length", "tacplus.body_author_rep_server.data_len",
1195 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1197 { &hf_tacplus_body_author_rep_arg_count
,
1198 { "Arg count", "tacplus.body_author_rep.arg_count",
1199 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1201 { &hf_tacplus_acct_authen_method
,
1202 { "Auth Method", "tacplus.acct.auth_method",
1203 FT_UINT8
, BASE_HEX
, VALS(tacplus_authen_method
), 0x0,
1205 { &hf_tacplus_acct_arg_count
,
1206 { "Arg count", "tacplus.acct.arg_count",
1207 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1209 { &hf_tacplus_body_acct_status
,
1210 { "Status", "tacplus.body_acct.status",
1211 FT_UINT8
, BASE_HEX
, VALS(tacplus_acct_status
), 0x0,
1213 { &hf_tacplus_body_acct_server_msg_len
,
1214 { "Server Msg length", "tacplus.body_acct.msg_len",
1215 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1217 { &hf_tacplus_body_acct_data_len
,
1218 { "Data length", "tacplus.body_acct.data_len",
1219 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
1221 { &hf_tacplus_body_acct_server_msg
,
1222 { "Server message", "tacplus.body_acct.server_msg",
1223 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1225 { &hf_tacplus_body_acct_data
,
1226 { "Data", "tacplus.body_acct.data",
1227 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1230 { "Data", "tacplus.data",
1231 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1234 /* Generated from convert_proto_tree_add_text.pl */
1235 { &hf_tacplus_ascii_length
, { "ASCII Data Length", "tacplus.ascii_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1236 { &hf_tacplus_password_length
, { "Password Length", "tacplus.password_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1237 { &hf_tacplus_chap_data_length
, { "CHAP Data Length", "tacplus.chap_data_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1238 { &hf_tacplus_mschap_data_length
, { "MSCHAP Data Length", "tacplus.mschap_data_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1239 { &hf_tacplus_arap_data_length
, { "ARAP Data Length", "tacplus.arap_data_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1240 { &hf_tacplus_data_length
, { "Data", "tacplus.data_length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1243 static int *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
}},
1253 { &ei_tacplus_unencrypted
, { "tacplus.flags.unencrypted.deprecated", PI_SECURITY
, PI_WARN
, "Unencrypted payload option MUST NOT be used in production", EXPFILL
}},
1254 { &ei_tacplus_bogus_data
, { "tacplus.bogus_data", PI_PROTOCOL
, PI_WARN
, "Bogus data", EXPFILL
}},
1257 module_t
*tacplus_module
;
1258 expert_module_t
* expert_tacplus
;
1260 proto_tacplus
= proto_register_protocol("TACACS+", "TACACS+", "tacplus");
1261 proto_register_field_array(proto_tacplus
, hf
, array_length(hf
));
1262 proto_register_subtree_array(ett
, array_length(ett
));
1263 tacplus_handle
= register_dissector("tacplus", dissect_tacplus
, proto_tacplus
);
1264 expert_tacplus
= expert_register_protocol(proto_tacplus
);
1265 expert_register_field_array(expert_tacplus
, ei
, array_length(ei
));
1266 tacplus_module
= prefs_register_protocol (proto_tacplus
, tacplus_pref_cb
);
1268 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
);
1270 prefs_register_string_preference ( tacplus_module
, "key",
1271 "TACACS+ Encryption Key", "TACACS+ Encryption Key", &tacplus_opt_key
);
1275 proto_reg_handoff_tacplus(void)
1277 dissector_add_uint_with_preference("tcp.port", TCP_PORT_TACACS
, tacplus_handle
);
1281 md5_xor( uint8_t *data
, const char *key
, int data_len
, uint8_t *session_id
, uint8_t version
, uint8_t seq_no
)
1286 uint8_t hash
[HASH_MD5_LENGTH
]; /* the md5 hash */
1289 md5_len
= 4 /* sizeof(session_id) */ + strlen(key
)
1290 + sizeof(version
) + sizeof(seq_no
);
1292 md5_buff
= (uint8_t*)wmem_alloc(wmem_packet_scope(), md5_len
+ HASH_MD5_LENGTH
);
1296 memcpy(mdp
, session_id
, 4);
1298 memcpy(mdp
, key
, strlen(key
));
1304 gcry_md_hash_buffer(GCRY_MD_MD5
, hash
, md5_buff
, md5_len
);
1305 md5_len
+= HASH_MD5_LENGTH
;
1306 for (i
= 0; i
< data_len
; i
+= 16) {
1308 for (j
= 0; j
< 16; j
++) {
1309 if ((i
+ j
) >= data_len
) {
1310 i
= data_len
+1; /* To exit from the external loop */
1313 data
[i
+ j
] ^= hash
[j
];
1315 memcpy(mdp
, hash
, HASH_MD5_LENGTH
);
1316 gcry_md_hash_buffer(GCRY_MD_MD5
, hash
, md5_buff
, md5_len
);
1321 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1326 * indent-tabs-mode: t
1329 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1330 * :indentSize=8:tabSize=8:noTabs=false: