Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-tacacs.c
blob5db16a83d454b9b17e2b7bc43d10bccaccb01734
1 /* packet-tacacs.c
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
23 #include "config.h"
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>
30 #include <epan/tfs.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" },
79 { 0, NULL }
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" },
105 { 0, NULL }};
107 static const value_string tacacs_reason_vals[] = {
108 { 0 , "none" },
109 { 1 , "expiring" },
110 { 2 , "password" },
111 { 3 , "denied" },
112 { 4 , "quit" },
113 { 5 , "idle" },
114 { 6 , "drop" },
115 { 7 , "bad" },
116 { 0 , NULL }
119 static const value_string tacacs_resp_vals[] = {
120 { 0 , "this is not a response" },
121 { 1 , "accepted" },
122 { 2 , "rejected" },
123 { 0 , NULL }
126 #define UDP_PORT_TACACS 49
127 #define TCP_PORT_TACACS 49
129 static int
130 dissect_tacacs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
132 proto_tree *tacacs_tree;
133 proto_item *ti;
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);
140 if (version != 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)"));
148 /* if (tree) */
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);
158 if (version==0)
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);
167 else
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);
173 else
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);
195 void
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,
202 NULL, HFILL }},
203 { &hf_tacacs_type,
204 { "Type", "tacacs.type",
205 FT_UINT8, BASE_DEC, VALS(tacacs_type_vals), 0x0,
206 NULL, HFILL }},
207 { &hf_tacacs_nonce,
208 { "Nonce", "tacacs.nonce",
209 FT_UINT16, BASE_HEX, NULL, 0x0,
210 NULL, HFILL }},
211 { &hf_tacacs_userlen,
212 { "Username length", "tacacs.userlen",
213 FT_UINT8, BASE_DEC, NULL, 0x0,
214 NULL, HFILL }},
215 { &hf_tacacs_passlen,
216 { "Password length", "tacacs.passlen",
217 FT_UINT8, BASE_DEC, NULL, 0x0,
218 NULL, HFILL }},
219 { &hf_tacacs_response,
220 { "Response", "tacacs.response",
221 FT_UINT8, BASE_DEC, VALS(tacacs_resp_vals), 0x0,
222 NULL, HFILL }},
223 { &hf_tacacs_reason,
224 { "Reason", "tacacs.reason",
225 FT_UINT8, BASE_DEC, VALS(tacacs_reason_vals), 0x0,
226 NULL, HFILL }},
227 { &hf_tacacs_result1,
228 { "Result 1", "tacacs.result1",
229 FT_UINT32, BASE_HEX, NULL, 0x0,
230 NULL, HFILL }},
231 { &hf_tacacs_destaddr,
232 { "Destination address", "tacacs.destaddr",
233 FT_IPv4, BASE_NONE, NULL, 0x0,
234 NULL, HFILL }},
235 { &hf_tacacs_destport,
236 { "Destination port", "tacacs.destport",
237 FT_UINT16, BASE_DEC, NULL, 0x0,
238 NULL, HFILL }},
239 { &hf_tacacs_line,
240 { "Line", "tacacs.line",
241 FT_UINT16, BASE_DEC, NULL, 0x0,
242 NULL, HFILL }},
243 { &hf_tacacs_result2,
244 { "Result 2", "tacacs.result2",
245 FT_UINT32, BASE_HEX, NULL, 0x0,
246 NULL, HFILL }},
247 { &hf_tacacs_result3,
248 { "Result 3", "tacacs.result3",
249 FT_UINT16, BASE_HEX, NULL, 0x0,
250 NULL, HFILL }},
251 { &hf_tacacs_username,
252 { "Username", "tacacs.username",
253 FT_STRING, BASE_NONE, NULL, 0x0,
254 NULL, HFILL }},
255 { &hf_tacacs_password,
256 { "Password", "tacacs.password",
257 FT_STRING, BASE_NONE, NULL, 0x0,
258 NULL, HFILL }},
261 static int *ett[] = {
262 &ett_tacacs,
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);
270 void
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 */
359 char *k; /* Key */
360 } tacplus_key_entry;
362 static int
363 tacplus_decrypted_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, uint32_t len, uint8_t version, const char *key )
365 uint8_t *buff;
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");
384 return 0;
386 static void
387 dissect_tacplus_args_list( tvbuff_t *tvb, proto_tree *tree, int data_off, int len_off, int arg_cnt )
389 int i;
390 int len;
391 uint8_t *value;
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);
399 data_off+=len;
404 static int
405 proto_tree_add_tacplus_common_fields( tvbuff_t *tvb, proto_tree *tree, int offset, int var_off )
407 int val;
408 /* priv_lvl */
409 proto_tree_add_item(tree, hf_tacplus_privilege_level, tvb, offset, 1, ENC_BIG_ENDIAN);
410 offset++;
412 /* authen_type */
413 proto_tree_add_item(tree, hf_tacplus_authentication_type, tvb, offset, 1, ENC_BIG_ENDIAN);
414 offset++;
416 /* service */
417 proto_tree_add_item(tree, hf_tacplus_service, tvb, offset, 1, ENC_BIG_ENDIAN);
418 offset++;
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);
424 if( val ){
425 proto_tree_add_item(tree, hf_tacplus_user, tvb, var_off, val, ENC_ASCII);
426 var_off+=val;
428 offset++;
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);
434 if( val ){
435 proto_tree_add_item(tree, hf_tacplus_port, tvb, var_off, val, ENC_ASCII);
436 var_off+=val;
438 offset++;
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);
443 if( val ){
444 proto_tree_add_item(tree, hf_tacplus_remote_address, tvb, var_off, val, ENC_ASCII);
445 var_off+=val;
447 return var_off;
450 static void
451 dissect_tacplus_body_authen_req_login( tvbuff_t* tvb, proto_tree *tree, int var_off )
453 uint8_t val;
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);
460 if( val )
461 proto_tree_add_item( tree, hf_tacplus_data, tvb, var_off, val, ENC_NA);
462 break;
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);
466 if( val ) {
467 proto_tree_add_item(tree, hf_tacplus_auth_password, tvb, var_off, val, ENC_ASCII);
469 break;
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);
473 if( val ) {
474 proto_tree *pt;
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);
478 var_off++;
479 proto_tree_add_item(pt, hf_tacplus_chap_challenge, tvb, var_off, chal_len, ENC_ASCII);
480 var_off+=chal_len;
481 proto_tree_add_item(pt, hf_tacplus_chap_response, tvb, var_off, 16, ENC_ASCII);
483 break;
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);
486 if( val ) {
487 proto_tree *pt;
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);
491 var_off++;
492 proto_tree_add_item(pt, hf_tacplus_mschap_challenge, tvb, var_off, chal_len, ENC_ASCII);
493 var_off+=chal_len;
494 proto_tree_add_item(pt, hf_tacplus_mschap_response, tvb, var_off, 49, ENC_ASCII);
496 break;
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);
499 if( val ) {
500 proto_tree *pt;
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);
503 var_off+=8;
504 proto_tree_add_item(pt, hf_tacplus_arap_remote_challenge, tvb, var_off, 8, ENC_ASCII);
505 var_off+=8;
506 proto_tree_add_item(pt, hf_tacplus_arap_remote_response, tvb, var_off, 8, ENC_ASCII);
508 break;
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);
512 if( val ){
513 proto_tree_add_item( tree, hf_tacplus_data, tvb, var_off, val, ENC_NA);
518 static void
519 dissect_tacplus_body_authen_req( tvbuff_t* tvb, proto_tree *tree )
521 uint8_t val;
522 int var_off=AUTHEN_S_VARDATA_OFF;
524 /* Action */
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 );
529 switch( val ) {
530 case TAC_PLUS_AUTHEN_LOGIN:
531 dissect_tacplus_body_authen_req_login( tvb, tree, var_off );
532 break;
533 case TAC_PLUS_AUTHEN_SENDAUTH:
534 break;
538 static void
539 dissect_tacplus_body_authen_req_cont( tvbuff_t *tvb, proto_tree *tree )
541 int val;
542 int var_off=AUTHEN_C_VARDATA_OFF;
543 proto_item* ti;
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);
552 if( val ){
553 proto_tree_add_item(tree, hf_tacplus_body_authen_req_cont_user, tvb, var_off, val, ENC_ASCII);
554 var_off+=val;
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);
559 if( val ){
560 proto_tree_add_item( tree, hf_tacplus_data, tvb, var_off, val, ENC_NA );
565 /* Server REPLY */
566 static void
567 dissect_tacplus_body_authen_rep( tvbuff_t *tvb, proto_tree *tree )
569 int val;
570 int var_off=AUTHEN_R_VARDATA_OFF;
571 proto_item* ti;
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);
583 if( val ) {
584 proto_tree_add_item(tree, hf_tacplus_body_authen_rep_server_msg, tvb, var_off, val, ENC_ASCII);
585 var_off+=val;
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);
590 if( val ){
591 proto_tree_add_item(tree, hf_tacplus_data, tvb, var_off, val, ENC_NA );
595 static void
596 dissect_tacplus_body_author_req( tvbuff_t* tvb, proto_tree *tree )
598 int val;
599 int var_off;
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 );
615 static void
616 dissect_tacplus_body_author_rep( tvbuff_t* tvb, proto_tree *tree )
618 int offset=AUTHOR_R_VARDATA_OFF;
619 int val;
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 );
624 offset+=val;
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 );
628 offset+=val;
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);
632 offset+=val;
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 );
638 static void
639 dissect_tacplus_body_acct_req( tvbuff_t* tvb, proto_tree *tree )
641 int val, var_off;
643 proto_item *tf;
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 );
657 /* authen_type */
658 var_off=proto_tree_add_tacplus_common_fields( tvb, tree ,
659 ACCT_Q_PRIV_LVL_OFF,
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 );
670 static void
671 dissect_tacplus_body_acct_rep( tvbuff_t* tvb, proto_tree *tree )
673 int val, var_off=ACCT_R_VARDATA_OFF;
675 /* Status */
676 proto_tree_add_item(tree, hf_tacplus_body_acct_status, tvb, ACCT_R_STATUS_OFF, 1, ENC_BIG_ENDIAN);
678 /* Server Message */
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);
681 if( val ) {
682 proto_tree_add_item(tree, hf_tacplus_body_acct_server_msg, tvb, var_off, val, ENC_ASCII);
683 var_off+=val;
686 /* Data */
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);
689 if( val ) {
690 proto_tree_add_item(tree, hf_tacplus_body_acct_data, tvb, var_off, val, ENC_ASCII);
696 static void
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 );
702 switch (type) {
703 case TAC_PLUS_AUTHEN:
704 if ( seq_no & 0x01) {
705 if ( seq_no == 1 )
706 dissect_tacplus_body_authen_req( tvb, tree );
707 else
708 dissect_tacplus_body_authen_req_cont( tvb, tree );
709 } else {
710 dissect_tacplus_body_authen_rep( tvb, tree );
712 break;
713 case TAC_PLUS_AUTHOR:
714 if ( seq_no & 0x01)
715 dissect_tacplus_body_author_req( tvb, tree );
716 else
717 dissect_tacplus_body_author_rep( tvb, tree );
718 break;
719 case TAC_PLUS_ACCT:
720 if ( seq_no & 0x01)
721 dissect_tacplus_body_acct_req( tvb, tree );
722 else
723 dissect_tacplus_body_acct_rep( tvb, tree );
724 break;
725 default:
726 proto_tree_add_expert( tree, pinfo, &ei_tacplus_bogus_data, tvb, 0, -1);
727 break;
731 #ifdef DEB_TACPLUS
732 static void
733 tacplus_print_key_entry( void *data, void *user_data )
735 tacplus_key_entry *tacplus_data=(tacplus_key_entry *)data;
736 char *s_str, *c_str;
738 s_str = address_to_str( NULL, tacplus_data->s );
739 c_str = address_to_str( NULL, tacplus_data->c );
740 if( user_data ) {
741 ws_debug_printf("%s:%s=%s\n", s_str, c_str, tacplus_data->k );
742 } else {
743 ws_debug_printf("%s:%s\n", s_str, c_str );
745 wmem_free(NULL, s_str);
746 wmem_free(NULL, c_str);
748 #endif
749 static int
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;
754 int32_t ret;
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 );
762 if( !ret ) {
763 ret=cmp_address( a1->c, a2->c );
765 if(ret)
766 ws_debug_printf("No Client found!"); */
767 } else {
768 /* ws_debug_printf("No Server found!"); */
770 return ret;
773 static const char*
774 find_key( address *srv, address *cln )
776 tacplus_key_entry data;
777 GSList *match;
779 data.s=srv;
780 data.c=cln;
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); */
785 if( match )
786 return ((tacplus_key_entry*)match->data)->k;
788 return (tacplus_keys?NULL:tacplus_opt_key);
791 static void
792 mkipv4_address( address **addr, const char *str_addr )
794 int ret;
795 char *addr_data;
797 *addr=g_new(address, 1);
798 addr_data=(char *)g_malloc( 4 );
799 ret = str_to_ip(str_addr, addr_data);
800 if (ret)
801 set_address(*addr, AT_IPv4, 4, addr_data);
802 else {
803 g_free(addr_data); /* not set, not used */
804 set_address(*addr, AT_STRINGZ, (int)strlen(ADDR_INVLD)+1, ADDR_INVLD);
807 static void
808 parse_tuple( char *key_from_option )
810 char *client,*key;
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,'/');
816 if(!client) {
817 g_free(tacplus_data);
818 return;
820 *client++='\0';
821 key=strchr(client,'=');
822 if(!key) {
823 g_free(tacplus_data);
824 return;
826 *key++='\0';
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 );
836 static
837 void
838 parse_tacplus_keys( const char *keys_from_option )
840 char *key_copy,*s,*s1;
842 /* Drop old keys */
843 if( tacplus_keys ) {
844 g_slist_free( tacplus_keys );
845 tacplus_keys=NULL;
848 if( !strchr( keys_from_option, '/' ) ){
849 /* option not in client/server=key format */
850 return ;
852 key_copy=g_strdup(keys_from_option);
853 s=key_copy;
854 while(s){
855 if( (s1=strchr( s, ' ' )) != NULL )
856 *s1++='\0';
857 parse_tuple( s );
858 s=s1;
860 g_free( key_copy );
861 #ifdef DEB_TACPLUS
862 g_slist_foreach( tacplus_keys, tacplus_print_key_entry, GINT_TO_POINTER(1) );
863 #endif
866 static unsigned
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;
872 static int
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);
879 static int
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;
887 proto_item *tf;
888 proto_item *tmp_pi;
889 uint32_t len;
890 bool request=( pinfo->destport == TCP_PORT_TACACS );
891 const char *key=NULL;
893 len = tvb_get_ntohl(tvb, 8);
895 if( request ) {
896 key=find_key( &pinfo->dst, &pinfo->src );
897 } else {
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",
903 request ? "Q" : "R",
904 val_to_str(tvb_get_uint8(tvb,1), tacplus_type_vals, "Unknown (0x%02x)"));
906 /* if (tree) */
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);
916 else
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,
925 version,
926 "%s",
927 (version&0xf0)==0xc0?"TACACS+":"Unknown Version");
928 proto_tree_add_uint(tacplus_tree, hf_tacplus_minvers, tvb, 0, 1,
929 version&0xf);
930 proto_tree_add_item(tacplus_tree, hf_tacplus_type, tvb, 1, 1,
931 ENC_BIG_ENDIAN);
932 proto_tree_add_item(tacplus_tree, hf_tacplus_seqno, tvb, 2, 1,
933 ENC_BIG_ENDIAN);
934 flags = tvb_get_uint8(tvb,3);
935 tf = proto_tree_add_uint_format_value(tacplus_tree, hf_tacplus_flags,
936 tvb, 3, 1, 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,
942 tvb, 3, 1, flags);
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,
947 tvb, 3, 1, flags);
948 proto_tree_add_item(tacplus_tree, hf_tacplus_session_id, tvb, 4, 4,
949 ENC_BIG_ENDIAN);
951 tmp_pi = proto_tree_add_uint(tacplus_tree, hf_tacplus_packet_len, tvb, 8, 4, len);
952 if ((int)len < 1) {
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 );
961 } else {
962 new_tvb=NULL;
963 if( key && *key ){
964 tacplus_decrypted_tvb_setup( tvb, &new_tvb, pinfo, len, version, key );
967 if( new_tvb ) {
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);
979 static void
980 tacplus_pref_cb(void)
982 parse_tacplus_keys( tacplus_opt_key );
985 void
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 }},
1005 { &hf_tacplus_type,
1006 { "Type", "tacplus.type",
1007 FT_UINT8, BASE_DEC, VALS(tacplus_type_vals), 0x0,
1008 NULL, HFILL }},
1009 { &hf_tacplus_seqno,
1010 { "Sequence number", "tacplus.seqno",
1011 FT_UINT8, BASE_DEC, NULL, 0x0,
1012 NULL, HFILL }},
1013 { &hf_tacplus_flags,
1014 { "Flags", "tacplus.flags",
1015 FT_UINT8, BASE_HEX, NULL, 0x0,
1016 NULL, HFILL }},
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,
1028 NULL, HFILL }},
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,
1032 NULL, HFILL }},
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,
1036 NULL, HFILL }},
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,
1040 NULL, HFILL }},
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,
1044 NULL, HFILL }},
1045 { &hf_tacplus_session_id,
1046 { "Session ID", "tacplus.session_id",
1047 FT_UINT32, BASE_DEC, NULL, 0x0,
1048 NULL, HFILL }},
1049 { &hf_tacplus_packet_len,
1050 { "Packet length", "tacplus.packet_len",
1051 FT_UINT32, BASE_DEC, NULL, 0x0,
1052 NULL, HFILL }},
1053 { &hf_tacplus_auth_password,
1054 { "Password", "tacplus.auth_password",
1055 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1056 NULL, HFILL }},
1057 { &hf_tacplus_port,
1058 { "Port", "tacplus.port",
1059 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1060 NULL, HFILL }},
1061 { &hf_tacplus_remote_address,
1062 { "Remote Address", "tacplus.remote_address",
1063 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1064 NULL, HFILL }},
1065 { &hf_tacplus_chap_challenge,
1066 { "Challenge", "tacplus.chap.challenge",
1067 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1068 NULL, HFILL }},
1069 { &hf_tacplus_chap_response,
1070 { "Response", "tacplus.chap.response",
1071 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1072 NULL, HFILL }},
1073 { &hf_tacplus_mschap_challenge,
1074 { "Challenge", "tacplus.mschap.challenge",
1075 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1076 NULL, HFILL }},
1077 { &hf_tacplus_mschap_response,
1078 { "Response", "tacplus.mschap.response",
1079 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1080 NULL, HFILL }},
1081 { &hf_tacplus_arap_nas_challenge,
1082 { "Nas Challenge", "tacplus.arap.nas_challenge",
1083 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1084 NULL, HFILL }},
1085 { &hf_tacplus_arap_remote_challenge,
1086 { "Remote Challenge", "tacplus.arap.remote_challenge",
1087 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1088 NULL, HFILL }},
1089 { &hf_tacplus_arap_remote_response,
1090 { "Remote Response", "tacplus.arap.remote_response",
1091 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1092 NULL, HFILL }},
1093 { &hf_tacplus_privilege_level,
1094 { "Privilege Level", "tacplus.privilege_level",
1095 FT_UINT8, BASE_DEC, NULL, 0x0,
1096 NULL, HFILL }},
1097 { &hf_tacplus_authentication_type,
1098 { "Authentication type", "tacplus.authentication_type",
1099 FT_UINT8, BASE_DEC, VALS(tacplus_authen_type_vals), 0x0,
1100 NULL, HFILL }},
1101 { &hf_tacplus_service,
1102 { "Service", "tacplus.service",
1103 FT_UINT8, BASE_DEC, VALS(tacplus_authen_service_vals), 0x0,
1104 NULL, HFILL }},
1105 { &hf_tacplus_user_len,
1106 { "User len", "tacplus.user_len",
1107 FT_UINT8, BASE_DEC, NULL, 0x0,
1108 NULL, HFILL }},
1109 { &hf_tacplus_user,
1110 { "User", "tacplus.user",
1111 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1112 NULL, HFILL }},
1113 { &hf_tacplus_port_len,
1114 { "Port len", "tacplus.port_len",
1115 FT_UINT8, BASE_DEC, NULL, 0x0,
1116 NULL, HFILL }},
1117 { &hf_tacplus_remote_address_len,
1118 { "Remaddr len", "tacplus.address_len",
1119 FT_UINT8, BASE_DEC, NULL, 0x0,
1120 NULL, HFILL }},
1121 { &hf_tacplus_arg_length,
1122 { "Length", "tacplus.arg_length",
1123 FT_UINT8, BASE_DEC, NULL, 0x0,
1124 NULL, HFILL }},
1125 { &hf_tacplus_arg_value,
1126 { "Value", "tacplus.arg_value",
1127 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1128 NULL, HFILL }},
1129 { &hf_tacplus_chap_id,
1130 { "ID", "tacplus.chap.id",
1131 FT_UINT8, BASE_DEC, NULL, 0x0,
1132 NULL, HFILL }},
1133 { &hf_tacplus_mschap_id,
1134 { "ID", "tacplus.mschap.id",
1135 FT_UINT8, BASE_DEC, NULL, 0x0,
1136 NULL, HFILL }},
1137 { &hf_tacplus_authen_action,
1138 { "Action", "tacplus.authen_action",
1139 FT_UINT8, BASE_DEC, VALS(tacplus_authen_action_vals), 0x0,
1140 NULL, HFILL }},
1141 { &hf_tacplus_body_authen_req_cont_flags,
1142 { "Flags", "tacplus.body_authen_req_cont.flags",
1143 FT_UINT8, BASE_HEX, NULL, 0x0,
1144 NULL, HFILL }},
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,
1148 NULL, HFILL }},
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,
1152 NULL, HFILL }},
1153 { &hf_tacplus_body_authen_req_cont_user,
1154 { "User", "tacplus.body_authen_req_cont.user",
1155 FT_STRING, BASE_NONE, NULL, 0x0,
1156 NULL, HFILL }},
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,
1160 NULL, HFILL }},
1161 { &hf_tacplus_body_authen_rep_flags,
1162 { "Flags", "tacplus.body_authen_rep.flags",
1163 FT_UINT8, BASE_HEX, NULL, 0x0,
1164 NULL, HFILL }},
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,
1168 NULL, HFILL }},
1169 { &hf_tacplus_body_authen_rep_server_msg,
1170 { "Server message", "tacplus.body_authen_rep.server_msg",
1171 FT_STRING, BASE_NONE, NULL, 0x0,
1172 NULL, HFILL }},
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,
1176 NULL, HFILL }},
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,
1180 NULL, HFILL }},
1181 { &hf_tacplus_body_author_req_arg_count,
1182 { "Arg count", "tacplus.body_author_req.arg_count",
1183 FT_UINT8, BASE_DEC, NULL, 0x0,
1184 NULL, HFILL }},
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,
1188 NULL, HFILL }},
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,
1192 NULL, HFILL }},
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,
1196 NULL, HFILL }},
1197 { &hf_tacplus_body_author_rep_arg_count,
1198 { "Arg count", "tacplus.body_author_rep.arg_count",
1199 FT_UINT8, BASE_DEC, NULL, 0x0,
1200 NULL, HFILL }},
1201 { &hf_tacplus_acct_authen_method,
1202 { "Auth Method", "tacplus.acct.auth_method",
1203 FT_UINT8, BASE_HEX, VALS(tacplus_authen_method), 0x0,
1204 NULL, HFILL }},
1205 { &hf_tacplus_acct_arg_count,
1206 { "Arg count", "tacplus.acct.arg_count",
1207 FT_UINT8, BASE_DEC, NULL, 0x0,
1208 NULL, HFILL }},
1209 { &hf_tacplus_body_acct_status,
1210 { "Status", "tacplus.body_acct.status",
1211 FT_UINT8, BASE_HEX, VALS(tacplus_acct_status), 0x0,
1212 NULL, HFILL }},
1213 { &hf_tacplus_body_acct_server_msg_len,
1214 { "Server Msg length", "tacplus.body_acct.msg_len",
1215 FT_UINT16, BASE_DEC, NULL, 0x0,
1216 NULL, HFILL }},
1217 { &hf_tacplus_body_acct_data_len,
1218 { "Data length", "tacplus.body_acct.data_len",
1219 FT_UINT16, BASE_DEC, NULL, 0x0,
1220 NULL, HFILL }},
1221 { &hf_tacplus_body_acct_server_msg,
1222 { "Server message", "tacplus.body_acct.server_msg",
1223 FT_STRING, BASE_NONE, NULL, 0x0,
1224 NULL, HFILL }},
1225 { &hf_tacplus_body_acct_data,
1226 { "Data", "tacplus.body_acct.data",
1227 FT_STRING, BASE_NONE, NULL, 0x0,
1228 NULL, HFILL }},
1229 { &hf_tacplus_data,
1230 { "Data", "tacplus.data",
1231 FT_BYTES, BASE_NONE, NULL, 0x0,
1232 NULL, HFILL }},
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[] = {
1244 &ett_tacplus,
1245 &ett_tacplus_flags,
1246 &ett_tacplus_acct_flags,
1247 &ett_tacplus_body,
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 );
1274 void
1275 proto_reg_handoff_tacplus(void)
1277 dissector_add_uint_with_preference("tcp.port", TCP_PORT_TACACS, tacplus_handle);
1280 static void
1281 md5_xor( uint8_t *data, const char *key, int data_len, uint8_t *session_id, uint8_t version, uint8_t seq_no )
1283 int i,j;
1284 size_t md5_len;
1285 uint8_t *md5_buff;
1286 uint8_t hash[HASH_MD5_LENGTH]; /* the md5 hash */
1287 uint8_t *mdp;
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);
1295 mdp = md5_buff;
1296 memcpy(mdp, session_id, 4);
1297 mdp += 4 ;
1298 memcpy(mdp, key, strlen(key));
1299 mdp += strlen(key);
1300 *mdp++ = version;
1301 *mdp++ = seq_no;
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 */
1311 break;
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
1323 * Local variables:
1324 * c-basic-offset: 8
1325 * tab-width: 8
1326 * indent-tabs-mode: t
1327 * End:
1329 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1330 * :indentSize=8:tabSize=8:noTabs=false: