Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-tacacs.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-tacacs.c
2
 * Routines for cisco tacacs/xtacacs/tacacs+ packet dissection
3
 * Copyright 2001, Paul Ionescu <paul@acorp.ro>
4
 *
5
 * Full Tacacs+ parsing with decryption by
6
 *   Emanuele Caratti <wiz@iol.it>
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * Copied from old packet-tacacs.c
13
 *
14
 * SPDX-License-Identifier: GPL-2.0-or-later
15
 */
16
17
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
21
 */
22
23
#include "config.h"
24
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>
32
33
#include "packet-tcp.h"
34
#include "packet-tacacs.h"
35
36
void proto_reg_handoff_tacacs(void);
37
void proto_register_tacacs(void);
38
static dissector_handle_t tacacs_handle;
39
40
void proto_reg_handoff_tacplus(void);
41
void proto_register_tacplus(void);
42
static dissector_handle_t tacplus_handle;
43
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);
46
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;
63
64
static int ett_tacacs;
65
66
static bool tacplus_preference_desegment = true;
67
68
static const char *tacplus_opt_key;
69
static GSList *tacplus_keys;
70
71
0
#define ADDR_INVLD "invalid"
72
73
#define VERSION_TACACS  0x00
74
#define VERSION_XTACACS 0x80
75
76
static const value_string tacacs_version_vals[] = {
77
  { VERSION_TACACS,  "TACACS" },
78
  { VERSION_XTACACS, "XTACACS" },
79
  { 0,               NULL }
80
};
81
82
#define TACACS_LOGIN    1
83
4
#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 }};
106
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 }
117
};
118
119
static const value_string tacacs_resp_vals[] = {
120
  { 0  , "this is not a response" },
121
  { 1  , "accepted" },
122
  { 2  , "rejected" },
123
  { 0  , NULL }
124
};
125
126
14
#define UDP_PORT_TACACS 49
127
145
#define TCP_PORT_TACACS 49
128
129
static int
130
dissect_tacacs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
131
4
{
132
4
  proto_tree      *tacacs_tree;
133
4
  proto_item      *ti;
134
4
  uint32_t        version,type,userlen,passlen;
135
136
4
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "TACACS");
137
4
  col_clear(pinfo->cinfo, COL_INFO);
138
139
4
  version = tvb_get_uint8(tvb,0);
140
4
  if (version != 0) {
141
3
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "XTACACS");
142
3
  }
143
144
4
  type = tvb_get_uint8(tvb,1);
145
4
  col_add_str(pinfo->cinfo, COL_INFO,
146
4
        val_to_str(type, tacacs_type_vals, "Unknown (0x%02x)"));
147
148
  /* if (tree) */
149
4
  {
150
4
    ti = proto_tree_add_protocol_format(tree, proto_tacacs,
151
4
     tvb, 0, -1, version==0?"TACACS":"XTACACS");
152
4
    tacacs_tree = proto_item_add_subtree(ti, ett_tacacs);
153
154
4
    proto_tree_add_uint(tacacs_tree, hf_tacacs_version, tvb, 0, 1, version);
155
4
    proto_tree_add_uint(tacacs_tree, hf_tacacs_type, tvb, 1, 1, type);
156
4
    proto_tree_add_item(tacacs_tree, hf_tacacs_nonce, tvb, 2, 2, ENC_BIG_ENDIAN);
157
158
4
    if (version==0)
159
1
    {
160
1
      if (type!=TACACS_RESPONSE)
161
1
      {
162
1
        proto_tree_add_item_ret_uint(tacacs_tree, hf_tacacs_userlen, tvb, 4, 1, ENC_NA, &userlen);
163
1
        proto_tree_add_item_ret_uint(tacacs_tree, hf_tacacs_passlen, tvb, 5, 1, ENC_NA, &passlen);
164
1
        proto_tree_add_item(tacacs_tree, hf_tacacs_username, tvb, 6, userlen, ENC_ASCII);
165
1
        proto_tree_add_item(tacacs_tree, hf_tacacs_password, tvb, 6+userlen, passlen, ENC_ASCII);
166
1
      }
167
0
      else
168
0
      {
169
0
        proto_tree_add_item(tacacs_tree, hf_tacacs_response, tvb, 4, 1, ENC_BIG_ENDIAN);
170
0
        proto_tree_add_item(tacacs_tree, hf_tacacs_reason, tvb, 5, 1, ENC_BIG_ENDIAN);
171
0
      }
172
1
    }
173
3
    else
174
3
    {
175
3
      proto_tree_add_item_ret_uint(tacacs_tree, hf_tacacs_userlen, tvb, 4, 1, ENC_NA, &userlen);
176
3
      proto_tree_add_item_ret_uint(tacacs_tree, hf_tacacs_passlen, tvb, 5, 1, ENC_NA, &passlen);
177
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_response, tvb, 6, 1, ENC_BIG_ENDIAN);
178
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_reason, tvb, 7, 1, ENC_BIG_ENDIAN);
179
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_result1, tvb, 8, 4, ENC_BIG_ENDIAN);
180
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_destaddr, tvb, 12, 4, ENC_BIG_ENDIAN);
181
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_destport, tvb, 16, 2, ENC_BIG_ENDIAN);
182
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_line, tvb, 18, 2, ENC_BIG_ENDIAN);
183
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_result2, tvb, 20, 4, ENC_BIG_ENDIAN);
184
3
      proto_tree_add_item(tacacs_tree, hf_tacacs_result3, tvb, 24, 2, ENC_BIG_ENDIAN);
185
3
      if (type!=TACACS_RESPONSE)
186
1
      {
187
1
        proto_tree_add_item(tacacs_tree, hf_tacacs_username, tvb, 26, userlen, ENC_ASCII);
188
1
        proto_tree_add_item(tacacs_tree, hf_tacacs_password, tvb, 26+userlen, passlen, ENC_ASCII);
189
1
      }
190
3
    }
191
4
  }
192
4
  return tvb_captured_length(tvb);
193
4
}
194
195
void
196
proto_register_tacacs(void)
197
14
{
198
14
  static hf_register_info hf[] = {
199
14
    { &hf_tacacs_version,
200
14
      { "Version", "tacacs.version",
201
14
        FT_UINT8, BASE_HEX, VALS(tacacs_version_vals), 0x0,
202
14
        NULL, HFILL }},
203
14
    { &hf_tacacs_type,
204
14
      { "Type", "tacacs.type",
205
14
        FT_UINT8, BASE_DEC, VALS(tacacs_type_vals), 0x0,
206
14
        NULL, HFILL }},
207
14
    { &hf_tacacs_nonce,
208
14
      { "Nonce", "tacacs.nonce",
209
14
        FT_UINT16, BASE_HEX, NULL, 0x0,
210
14
        NULL, HFILL }},
211
14
    { &hf_tacacs_userlen,
212
14
      { "Username length", "tacacs.userlen",
213
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
214
14
        NULL, HFILL }},
215
14
    { &hf_tacacs_passlen,
216
14
      { "Password length", "tacacs.passlen",
217
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
218
14
        NULL, HFILL }},
219
14
    { &hf_tacacs_response,
220
14
      { "Response", "tacacs.response",
221
14
        FT_UINT8, BASE_DEC, VALS(tacacs_resp_vals), 0x0,
222
14
        NULL, HFILL }},
223
14
    { &hf_tacacs_reason,
224
14
      { "Reason", "tacacs.reason",
225
14
        FT_UINT8, BASE_DEC, VALS(tacacs_reason_vals), 0x0,
226
14
        NULL, HFILL }},
227
14
    { &hf_tacacs_result1,
228
14
      { "Result 1", "tacacs.result1",
229
14
        FT_UINT32, BASE_HEX, NULL, 0x0,
230
14
        NULL, HFILL }},
231
14
    { &hf_tacacs_destaddr,
232
14
      { "Destination address", "tacacs.destaddr",
233
14
        FT_IPv4, BASE_NONE, NULL, 0x0,
234
14
        NULL, HFILL }},
235
14
    { &hf_tacacs_destport,
236
14
      { "Destination port", "tacacs.destport",
237
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
238
14
        NULL, HFILL }},
239
14
    { &hf_tacacs_line,
240
14
      { "Line", "tacacs.line",
241
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
242
14
        NULL, HFILL }},
243
14
    { &hf_tacacs_result2,
244
14
      { "Result 2", "tacacs.result2",
245
14
        FT_UINT32, BASE_HEX, NULL, 0x0,
246
14
        NULL, HFILL }},
247
14
    { &hf_tacacs_result3,
248
14
      { "Result 3", "tacacs.result3",
249
14
        FT_UINT16, BASE_HEX, NULL, 0x0,
250
14
        NULL, HFILL }},
251
14
    { &hf_tacacs_username,
252
14
      { "Username", "tacacs.username",
253
14
        FT_STRING, BASE_NONE, NULL, 0x0,
254
14
        NULL, HFILL }},
255
14
    { &hf_tacacs_password,
256
14
      { "Password", "tacacs.password",
257
14
        FT_STRING, BASE_NONE, NULL, 0x0,
258
14
        NULL, HFILL }},
259
14
  };
260
261
14
  static int *ett[] = {
262
14
    &ett_tacacs,
263
14
  };
264
14
  proto_tacacs = proto_register_protocol("TACACS", "TACACS", "tacacs");
265
14
  proto_register_field_array(proto_tacacs, hf, array_length(hf));
266
14
  proto_register_subtree_array(ett, array_length(ett));
267
14
  tacacs_handle = register_dissector("tacacs", dissect_tacacs, proto_tacacs);
268
14
}
269
270
void
271
proto_reg_handoff_tacacs(void)
272
14
{
273
14
  dissector_add_uint_with_preference("udp.port", UDP_PORT_TACACS, tacacs_handle);
274
14
}
275
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;
345
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;
351
352
static expert_field ei_tacplus_packet_len_invalid;
353
static expert_field ei_tacplus_unencrypted;
354
static expert_field ei_tacplus_bogus_data;
355
356
typedef struct _tacplus_key_entry {
357
  address *s; /* Server address */
358
  address *c; /* client address */
359
  char  *k; /* Key */
360
} tacplus_key_entry;
361
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 )
364
0
{
365
0
  uint8_t *buff;
366
0
  uint8_t session_id[4];
367
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 */
370
371
0
  tvb_memcpy(tvb, session_id, 4,4);
372
373
0
  buff = (uint8_t *)tvb_memdup(pinfo->pool, tvb, TAC_PLUS_HDR_SIZE, len);
374
375
376
0
  md5_xor( buff, key, len, session_id,version, tvb_get_uint8(tvb,2) );
377
378
  /* Allocate a new tvbuff, referring to the decrypted data. */
379
0
  *dst_tvb = tvb_new_child_real_data(tvb,  buff, len, len );
380
381
  /* Add the decrypted data to the data source list. */
382
0
  add_new_data_source(pinfo, *dst_tvb, "TACACS+ Decrypted");
383
384
0
  return 0;
385
0
}
386
static void
387
dissect_tacplus_args_list( tvbuff_t *tvb, proto_tree *tree, int data_off, int len_off, int arg_cnt )
388
7
{
389
7
  int i;
390
7
  int len;
391
7
  uint8_t *value;
392
94
  for(i=0;i<arg_cnt;i++){
393
87
    len=tvb_get_uint8(tvb,len_off+i);
394
87
    proto_tree_add_uint_format(tree, hf_tacplus_arg_length, tvb, len_off+i, 1, len,
395
87
                  "Arg[%d] length: %d", i, len);
396
87
    value=tvb_get_string_enc(wmem_packet_scope(), tvb, data_off, len, ENC_ASCII|ENC_NA);
397
87
    proto_tree_add_string_format(tree, hf_tacplus_arg_value, tvb, data_off, len, value,
398
87
                  "Arg[%d] value: %s", i, value);
399
87
    data_off+=len;
400
87
  }
401
7
}
402
403
404
static int
405
proto_tree_add_tacplus_common_fields( tvbuff_t *tvb, proto_tree *tree,  int offset, int var_off )
406
8
{
407
8
  int val;
408
  /* priv_lvl */
409
8
  proto_tree_add_item(tree, hf_tacplus_privilege_level, tvb, offset, 1, ENC_BIG_ENDIAN);
410
8
  offset++;
411
412
  /* authen_type */
413
8
  proto_tree_add_item(tree, hf_tacplus_authentication_type, tvb, offset, 1, ENC_BIG_ENDIAN);
414
8
  offset++;
415
416
  /* service */
417
8
  proto_tree_add_item(tree, hf_tacplus_service, tvb, offset, 1, ENC_BIG_ENDIAN);
418
8
  offset++;
419
420
  /* user_len && user */
421
8
  val=tvb_get_uint8(tvb,offset);
422
8
  proto_tree_add_uint(tree, hf_tacplus_user_len, tvb, offset, 1, val);
423
424
8
  if( val ){
425
6
    proto_tree_add_item(tree, hf_tacplus_user, tvb, var_off, val, ENC_ASCII);
426
6
    var_off+=val;
427
6
  }
428
8
  offset++;
429
430
431
  /* port_len && port */
432
8
  val=tvb_get_uint8(tvb,offset);
433
8
  proto_tree_add_uint(tree, hf_tacplus_port_len, tvb, offset, 1, val);
434
8
  if( val ){
435
3
    proto_tree_add_item(tree, hf_tacplus_port, tvb, var_off, val, ENC_ASCII);
436
3
    var_off+=val;
437
3
  }
438
8
  offset++;
439
440
  /* rem_addr_len && rem_addr */
441
8
  val=tvb_get_uint8(tvb,offset);
442
8
  proto_tree_add_uint(tree, hf_tacplus_remote_address_len, tvb, offset, 1, val);
443
8
  if( val ){
444
2
    proto_tree_add_item(tree, hf_tacplus_remote_address, tvb, var_off, val, ENC_ASCII);
445
2
    var_off+=val;
446
2
  }
447
8
  return var_off;
448
8
}
449
450
static void
451
dissect_tacplus_body_authen_req_login( tvbuff_t* tvb, proto_tree *tree, int var_off )
452
0
{
453
0
  uint8_t val;
454
0
  val=tvb_get_uint8( tvb, AUTHEN_S_DATA_LEN_OFF );
455
456
0
  switch ( tvb_get_uint8(tvb, AUTHEN_S_AUTHEN_TYPE_OFF ) ) { /* authen_type */
457
458
0
    case TAC_PLUS_AUTHEN_TYPE_ASCII:
459
0
      proto_tree_add_item(tree, hf_tacplus_ascii_length, tvb, AUTHEN_S_DATA_LEN_OFF, 1, ENC_BIG_ENDIAN);
460
0
      if( val )
461
0
        proto_tree_add_item( tree, hf_tacplus_data, tvb, var_off, val, ENC_NA);
462
0
      break;
463
464
0
    case TAC_PLUS_AUTHEN_TYPE_PAP:
465
0
      proto_tree_add_item(tree, hf_tacplus_password_length, tvb, AUTHEN_S_DATA_LEN_OFF, 1, ENC_BIG_ENDIAN);
466
0
      if( val ) {
467
0
        proto_tree_add_item(tree, hf_tacplus_auth_password, tvb, var_off, val, ENC_ASCII);
468
0
      }
469
0
      break;
470
471
0
    case TAC_PLUS_AUTHEN_TYPE_CHAP:
472
0
      proto_tree_add_item(tree, hf_tacplus_chap_data_length, tvb, AUTHEN_S_DATA_LEN_OFF, 1, ENC_BIG_ENDIAN);
473
0
      if( val ) {
474
0
        proto_tree *pt;
475
0
        uint8_t chal_len=val-(1+16); /* Response field alwayes 16 octets */
476
0
        pt = proto_tree_add_subtree(tree, tvb, var_off, val, ett_tacplus_body_chap, NULL, "CHAP Data" );
477
0
        proto_tree_add_item(pt, hf_tacplus_chap_id, tvb, var_off, 1, ENC_BIG_ENDIAN);
478
0
        var_off++;
479
0
        proto_tree_add_item(pt, hf_tacplus_chap_challenge, tvb, var_off, chal_len, ENC_ASCII);
480
0
        var_off+=chal_len;
481
0
        proto_tree_add_item(pt, hf_tacplus_chap_response, tvb, var_off, 16, ENC_ASCII);
482
0
      }
483
0
      break;
484
0
    case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
485
0
      proto_tree_add_item(tree, hf_tacplus_mschap_data_length, tvb, AUTHEN_S_DATA_LEN_OFF, 1, ENC_BIG_ENDIAN);
486
0
      if( val ) {
487
0
        proto_tree *pt;
488
0
        uint8_t chal_len=val-(1+49);  /* Response field alwayes 49 octets */
489
0
        pt = proto_tree_add_subtree(tree, tvb, var_off, val, ett_tacplus_body_chap, NULL, "MSCHAP Data" );
490
0
        proto_tree_add_item(pt, hf_tacplus_mschap_id, tvb, var_off, 1, ENC_BIG_ENDIAN);
491
0
        var_off++;
492
0
        proto_tree_add_item(pt, hf_tacplus_mschap_challenge, tvb, var_off, chal_len, ENC_ASCII);
493
0
        var_off+=chal_len;
494
0
        proto_tree_add_item(pt, hf_tacplus_mschap_response, tvb, var_off, 49, ENC_ASCII);
495
0
      }
496
0
      break;
497
0
    case TAC_PLUS_AUTHEN_TYPE_ARAP:
498
0
      proto_tree_add_item(tree, hf_tacplus_arap_data_length, tvb, AUTHEN_S_DATA_LEN_OFF, 1, ENC_BIG_ENDIAN);
499
0
      if( val ) {
500
0
        proto_tree *pt;
501
0
        pt = proto_tree_add_subtree(tree, tvb, var_off, val, ett_tacplus_body_chap, NULL, "ARAP Data" );
502
0
        proto_tree_add_item(pt, hf_tacplus_arap_nas_challenge, tvb, var_off, 8, ENC_ASCII);
503
0
        var_off+=8;
504
0
        proto_tree_add_item(pt, hf_tacplus_arap_remote_challenge, tvb, var_off, 8, ENC_ASCII);
505
0
        var_off+=8;
506
0
        proto_tree_add_item(pt, hf_tacplus_arap_remote_response, tvb, var_off, 8, ENC_ASCII);
507
0
      }
508
0
      break;
509
510
0
    default: /* Should not be reached */
511
0
      proto_tree_add_item(tree, hf_tacplus_data_length, tvb, AUTHEN_S_DATA_LEN_OFF, 1, ENC_BIG_ENDIAN);
512
0
      if( val ){
513
0
        proto_tree_add_item( tree, hf_tacplus_data, tvb, var_off, val, ENC_NA);
514
0
      }
515
0
  }
516
0
}
517
518
static void
519
dissect_tacplus_body_authen_req( tvbuff_t* tvb, proto_tree *tree )
520
1
{
521
1
  uint8_t val;
522
1
  int var_off=AUTHEN_S_VARDATA_OFF;
523
524
  /* Action */
525
1
  val=tvb_get_uint8( tvb, AUTHEN_S_ACTION_OFF );
526
1
  proto_tree_add_item(tree, hf_tacplus_authen_action, tvb, AUTHEN_S_ACTION_OFF, 1, ENC_BIG_ENDIAN);
527
1
  var_off=proto_tree_add_tacplus_common_fields( tvb, tree , AUTHEN_S_PRIV_LVL_OFF, AUTHEN_S_VARDATA_OFF );
528
529
1
  switch( val ) {
530
0
    case TAC_PLUS_AUTHEN_LOGIN:
531
0
      dissect_tacplus_body_authen_req_login( tvb, tree, var_off );
532
0
      break;
533
0
    case TAC_PLUS_AUTHEN_SENDAUTH:
534
0
      break;
535
1
  }
536
1
}
537
538
static void
539
dissect_tacplus_body_authen_req_cont( tvbuff_t *tvb, proto_tree *tree )
540
7
{
541
7
  int val;
542
7
  int var_off=AUTHEN_C_VARDATA_OFF;
543
7
  proto_item* ti;
544
545
7
  val=tvb_get_uint8( tvb, AUTHEN_C_FLAGS_OFF );
546
7
  ti = proto_tree_add_item(tree, hf_tacplus_body_authen_req_cont_flags, tvb, AUTHEN_C_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
547
7
  if (val&TAC_PLUS_CONTINUE_FLAG_ABORT)
548
1
    proto_item_append_text(ti, "(Abort)");
549
550
7
  val=tvb_get_ntohs( tvb, AUTHEN_C_USER_LEN_OFF );
551
7
  proto_tree_add_uint(tree, hf_tacplus_body_authen_req_cont_user_length, tvb, AUTHEN_C_USER_LEN_OFF, 2, val);
552
7
  if( val ){
553
3
    proto_tree_add_item(tree, hf_tacplus_body_authen_req_cont_user, tvb, var_off, val, ENC_ASCII);
554
3
    var_off+=val;
555
3
  }
556
557
7
  val=tvb_get_ntohs( tvb, AUTHEN_C_DATA_LEN_OFF );
558
7
  proto_tree_add_uint(tree, hf_tacplus_body_authen_req_cont_data_length, tvb, AUTHEN_C_DATA_LEN_OFF, 2, val);
559
7
  if( val ){
560
1
    proto_tree_add_item( tree, hf_tacplus_data, tvb, var_off, val, ENC_NA );
561
1
  }
562
563
7
}
564
565
/* Server REPLY */
566
static void
567
dissect_tacplus_body_authen_rep( tvbuff_t *tvb, proto_tree *tree )
568
3
{
569
3
  int val;
570
3
  int var_off=AUTHEN_R_VARDATA_OFF;
571
3
  proto_item* ti;
572
573
3
  proto_tree_add_item(tree, hf_tacplus_body_authen_rep_status, tvb, AUTHEN_R_STATUS_OFF, 1, ENC_BIG_ENDIAN);
574
575
3
  val=tvb_get_uint8( tvb, AUTHEN_R_FLAGS_OFF );
576
3
  ti = proto_tree_add_item(tree, hf_tacplus_body_authen_rep_flags, tvb, AUTHEN_R_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
577
3
  if (val&TAC_PLUS_REPLY_FLAG_NOECHO)
578
0
    proto_item_append_text(ti, "(NoEcho)");
579
580
3
  val=tvb_get_ntohs(tvb, AUTHEN_R_SRV_MSG_LEN_OFF );
581
3
  proto_tree_add_uint(tree, hf_tacplus_body_authen_rep_server_msg_len, tvb, AUTHEN_R_SRV_MSG_LEN_OFF, 2, val);
582
583
3
  if( val ) {
584
3
    proto_tree_add_item(tree, hf_tacplus_body_authen_rep_server_msg, tvb, var_off, val, ENC_ASCII);
585
3
    var_off+=val;
586
3
  }
587
588
3
  val=tvb_get_ntohs(tvb, AUTHEN_R_DATA_LEN_OFF );
589
3
  proto_tree_add_uint(tree, hf_tacplus_body_authen_rep_server_data_len, tvb, AUTHEN_R_DATA_LEN_OFF, 2, val);
590
3
  if( val ){
591
0
    proto_tree_add_item(tree, hf_tacplus_data, tvb, var_off, val, ENC_NA );
592
0
  }
593
3
}
594
595
static void
596
dissect_tacplus_body_author_req( tvbuff_t* tvb, proto_tree *tree )
597
0
{
598
0
  int val;
599
0
  int var_off;
600
601
0
  proto_tree_add_item(tree, hf_tacplus_body_author_req_auth_method, tvb, AUTHOR_Q_AUTH_METH_OFF, 1, ENC_BIG_ENDIAN);
602
603
0
  val = tvb_get_uint8( tvb, AUTHOR_Q_ARGC_OFF );
604
0
  var_off=proto_tree_add_tacplus_common_fields( tvb, tree ,
605
0
      AUTHOR_Q_PRIV_LVL_OFF,
606
0
      AUTHOR_Q_VARDATA_OFF + val);
607
608
0
  proto_tree_add_item(tree, hf_tacplus_body_author_req_arg_count, tvb, AUTHOR_Q_ARGC_OFF, 1, ENC_BIG_ENDIAN);
609
610
/* var_off points after rem_addr */
611
612
0
  dissect_tacplus_args_list( tvb, tree, var_off, AUTHOR_Q_VARDATA_OFF, val );
613
0
}
614
615
static void
616
dissect_tacplus_body_author_rep( tvbuff_t* tvb, proto_tree *tree )
617
0
{
618
0
  int offset=AUTHOR_R_VARDATA_OFF;
619
0
  int val;
620
621
0
  proto_tree_add_item(tree, hf_tacplus_body_author_rep_auth_status, tvb, AUTHOR_R_STATUS_OFF, 1, ENC_BIG_ENDIAN);
622
623
0
  val=tvb_get_ntohs( tvb, AUTHOR_R_SRV_MSG_LEN_OFF );
624
0
  offset+=val;
625
0
  proto_tree_add_item(tree, hf_tacplus_body_author_rep_server_msg_len, tvb, AUTHOR_R_SRV_MSG_LEN_OFF, 2, ENC_BIG_ENDIAN);
626
627
0
  val=tvb_get_ntohs( tvb, AUTHOR_R_DATA_LEN_OFF );
628
0
  offset+=val;
629
0
  proto_tree_add_item(tree, hf_tacplus_body_author_rep_server_data_len, tvb, AUTHOR_R_DATA_LEN_OFF, 2, ENC_BIG_ENDIAN);
630
631
0
  val=tvb_get_uint8( tvb, AUTHOR_R_ARGC_OFF);
632
0
  offset+=val;
633
0
  proto_tree_add_item(tree, hf_tacplus_body_author_rep_arg_count, tvb, AUTHOR_R_ARGC_OFF, 1, ENC_BIG_ENDIAN);
634
635
0
  dissect_tacplus_args_list( tvb, tree, offset, AUTHOR_R_VARDATA_OFF, val );
636
0
}
637
638
static void
639
dissect_tacplus_body_acct_req( tvbuff_t* tvb, proto_tree *tree )
640
7
{
641
7
  int val, var_off;
642
643
7
  proto_item *tf;
644
7
  proto_tree *flags_tree;
645
646
7
  tf = proto_tree_add_item( tree, hf_tacplus_acct_flags, tvb, ACCT_Q_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
647
648
7
  flags_tree = proto_item_add_subtree( tf, ett_tacplus_acct_flags );
649
7
  proto_tree_add_item(flags_tree, hf_tacplus_acct_flags_more, tvb, ACCT_Q_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
650
7
  proto_tree_add_item(flags_tree, hf_tacplus_acct_flags_start, tvb, ACCT_Q_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
651
7
  proto_tree_add_item(flags_tree, hf_tacplus_acct_flags_stop, tvb, ACCT_Q_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
652
7
  proto_tree_add_item(flags_tree, hf_tacplus_acct_flags_watchdog, tvb, ACCT_Q_FLAGS_OFF, 1, ENC_BIG_ENDIAN);
653
654
7
  proto_tree_add_item(tree, hf_tacplus_acct_authen_method, tvb, ACCT_Q_METHOD_OFF, 1, ENC_BIG_ENDIAN);
655
7
  val=tvb_get_uint8( tvb, ACCT_Q_ARG_CNT_OFF );
656
657
  /* authen_type */
658
7
  var_off=proto_tree_add_tacplus_common_fields( tvb, tree ,
659
7
      ACCT_Q_PRIV_LVL_OFF,
660
7
      ACCT_Q_VARDATA_OFF+val
661
7
      );
662
663
7
  proto_tree_add_item(tree, hf_tacplus_acct_arg_count, tvb, ACCT_Q_ARG_CNT_OFF, 1, ENC_BIG_ENDIAN);
664
665
7
  dissect_tacplus_args_list( tvb, tree, var_off, ACCT_Q_VARDATA_OFF, val );
666
667
668
7
}
669
670
static void
671
dissect_tacplus_body_acct_rep( tvbuff_t* tvb, proto_tree *tree )
672
1
{
673
1
  int val, var_off=ACCT_R_VARDATA_OFF;
674
675
  /* Status */
676
1
  proto_tree_add_item(tree, hf_tacplus_body_acct_status, tvb, ACCT_R_STATUS_OFF, 1, ENC_BIG_ENDIAN);
677
678
  /* Server Message */
679
1
  val=tvb_get_ntohs( tvb, ACCT_R_SRV_MSG_LEN_OFF );
680
1
  proto_tree_add_item(tree, hf_tacplus_body_acct_server_msg_len, tvb, ACCT_R_SRV_MSG_LEN_OFF, 2, ENC_BIG_ENDIAN);
681
1
  if( val ) {
682
1
    proto_tree_add_item(tree, hf_tacplus_body_acct_server_msg, tvb, var_off, val, ENC_ASCII);
683
1
    var_off+=val;
684
1
  }
685
686
  /*  Data */
687
1
  val=tvb_get_ntohs( tvb, ACCT_R_DATA_LEN_OFF );
688
1
  proto_tree_add_item(tree, hf_tacplus_body_acct_data_len, tvb, ACCT_R_DATA_LEN_OFF, 2, ENC_BIG_ENDIAN);
689
1
  if( val ) {
690
1
    proto_tree_add_item(tree, hf_tacplus_body_acct_data, tvb, var_off, val, ENC_ASCII);
691
1
  }
692
1
}
693
694
695
696
static void
697
dissect_tacplus_body(tvbuff_t * hdr_tvb, packet_info *pinfo, tvbuff_t * tvb, proto_tree * tree )
698
39
{
699
39
  int type = tvb_get_uint8( hdr_tvb, H_TYPE_OFF );
700
39
  int seq_no = tvb_get_uint8( hdr_tvb, H_SEQ_NO_OFF );
701
702
39
  switch (type) {
703
11
    case TAC_PLUS_AUTHEN:
704
11
    if (  seq_no & 0x01) {
705
8
      if ( seq_no == 1 )
706
1
        dissect_tacplus_body_authen_req( tvb, tree );
707
7
      else
708
7
        dissect_tacplus_body_authen_req_cont( tvb, tree );
709
8
    } else {
710
3
      dissect_tacplus_body_authen_rep( tvb, tree );
711
3
    }
712
11
    break;
713
0
    case TAC_PLUS_AUTHOR:
714
0
    if ( seq_no & 0x01)
715
0
      dissect_tacplus_body_author_req( tvb, tree );
716
0
    else
717
0
      dissect_tacplus_body_author_rep( tvb, tree );
718
0
    break;
719
8
    case TAC_PLUS_ACCT:
720
8
    if ( seq_no & 0x01)
721
7
      dissect_tacplus_body_acct_req( tvb, tree );
722
1
    else
723
1
      dissect_tacplus_body_acct_rep( tvb, tree );
724
8
    break;
725
20
    default:
726
20
    proto_tree_add_expert( tree, pinfo, &ei_tacplus_bogus_data, tvb, 0, -1);
727
20
    break;
728
39
  }
729
39
}
730
731
#ifdef DEB_TACPLUS
732
static void
733
tacplus_print_key_entry( void *data, void *user_data )
734
{
735
  tacplus_key_entry *tacplus_data=(tacplus_key_entry *)data;
736
  char *s_str, *c_str;
737
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 );
744
  }
745
  wmem_free(NULL, s_str);
746
  wmem_free(NULL, c_str);
747
}
748
#endif
749
static int
750
cmp_conv_address( const void *p1, const void *p2 )
751
0
{
752
0
  const tacplus_key_entry *a1=(const tacplus_key_entry *)p1;
753
0
  const tacplus_key_entry *a2=(const tacplus_key_entry *)p2;
754
0
  int32_t ret;
755
  /*
756
  ws_debug_printf("p1=>");
757
  tacplus_print_key_entry( p1, NULL );
758
  ws_debug_printf("p2=>");
759
  tacplus_print_key_entry( p2, NULL );
760
  */
761
0
  ret=cmp_address( a1->s, a2->s );
762
0
  if( !ret ) {
763
0
    ret=cmp_address( a1->c, a2->c );
764
    /*
765
    if(ret)
766
      ws_debug_printf("No Client found!"); */
767
0
  } else {
768
    /* ws_debug_printf("No Server found!"); */
769
0
  }
770
0
  return ret;
771
0
}
772
773
static const char*
774
find_key( address *srv, address *cln )
775
131
{
776
131
  tacplus_key_entry data;
777
131
  GSList *match;
778
779
131
  data.s=srv;
780
131
  data.c=cln;
781
/*  ws_debug_printf("Looking for: ");
782
  tacplus_print_key_entry( (const void *)&data, NULL ); */
783
131
  match=g_slist_find_custom( tacplus_keys, (void *)&data, cmp_conv_address );
784
/*  ws_debug_printf("Finished (%p)\n", match);  */
785
131
  if( match )
786
0
    return ((tacplus_key_entry*)match->data)->k;
787
788
131
  return (tacplus_keys?NULL:tacplus_opt_key);
789
131
}
790
791
static void
792
mkipv4_address( address **addr, const char *str_addr )
793
0
{
794
0
  int   ret;
795
0
  char *addr_data;
796
797
0
  *addr=g_new(address, 1);
798
0
  addr_data=(char *)g_malloc( 4 );
799
0
  ret = str_to_ip(str_addr, addr_data);
800
0
  if (ret)
801
0
    set_address(*addr, AT_IPv4, 4, addr_data);
802
0
  else {
803
0
    g_free(addr_data);  /* not set, not used */
804
0
    set_address(*addr, AT_STRINGZ, (int)strlen(ADDR_INVLD)+1, ADDR_INVLD);
805
0
  }
806
0
}
807
static void
808
parse_tuple( char *key_from_option )
809
0
{
810
0
  char *client,*key;
811
0
  tacplus_key_entry *tacplus_data=g_new(tacplus_key_entry, 1);
812
  /*
813
  ws_debug_printf("keys: %s\n", key_from_option );
814
  */
815
0
  client=strchr(key_from_option,'/');
816
0
  if(!client) {
817
0
    g_free(tacplus_data);
818
0
    return;
819
0
  }
820
0
  *client++='\0';
821
0
  key=strchr(client,'=');
822
0
  if(!key) {
823
0
    g_free(tacplus_data);
824
0
    return;
825
0
  }
826
0
  *key++='\0';
827
  /*
828
  ws_debug_printf("%s %s => %s\n", key_from_option, client, key );
829
  */
830
0
  mkipv4_address( &tacplus_data->s, key_from_option );
831
0
  mkipv4_address( &tacplus_data->c, client );
832
0
  tacplus_data->k=g_strdup(key);
833
0
  tacplus_keys = g_slist_prepend( tacplus_keys, tacplus_data );
834
0
}
835
836
static
837
void
838
parse_tacplus_keys( const char *keys_from_option )
839
0
{
840
0
  char *key_copy,*s,*s1;
841
842
  /* Drop old keys */
843
0
  if( tacplus_keys ) {
844
0
    g_slist_free( tacplus_keys );
845
0
    tacplus_keys=NULL;
846
0
  }
847
848
0
  if( !strchr( keys_from_option, '/' ) ){
849
    /* option not in client/server=key format */
850
0
    return ;
851
0
  }
852
0
  key_copy=g_strdup(keys_from_option);
853
0
  s=key_copy;
854
0
  while(s){
855
0
    if( (s1=strchr( s, ' ' )) != NULL )
856
0
      *s1++='\0';
857
0
    parse_tuple( s );
858
0
    s=s1;
859
0
  }
860
0
  g_free( key_copy );
861
#ifdef DEB_TACPLUS
862
  g_slist_foreach( tacplus_keys, tacplus_print_key_entry, GINT_TO_POINTER(1) );
863
#endif
864
0
}
865
866
static unsigned
867
get_tacplus_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
868
136
{
869
136
  return (unsigned)tvb_get_ntohl(tvb, offset+H_LENGTH_OFF) +  TAC_PLUS_HDR_SIZE;
870
136
}
871
872
static int
873
dissect_tacplus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
874
37
{
875
37
  tcp_dissect_pdus(tvb, pinfo, tree, tacplus_preference_desegment, TAC_PLUS_HDR_SIZE, get_tacplus_message_len, dissect_tacplus_message, data);
876
37
  return tvb_captured_length(tvb);
877
37
}
878
879
static int
880
dissect_tacplus_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
881
131
{
882
131
  tvbuff_t  *new_tvb=NULL;
883
131
  proto_tree      *tacplus_tree, *body_tree;
884
131
  proto_item      *ti, *hidden_item;
885
131
  uint8_t   version,flags;
886
131
  proto_tree      *flags_tree;
887
131
  proto_item      *tf;
888
131
  proto_item  *tmp_pi;
889
131
  uint32_t    len;
890
131
  bool  request=( pinfo->destport == TCP_PORT_TACACS );
891
131
  const char  *key=NULL;
892
893
131
  len = tvb_get_ntohl(tvb, 8);
894
895
131
  if( request ) {
896
66
    key=find_key( &pinfo->dst, &pinfo->src );
897
66
  } else {
898
65
    key=find_key(  &pinfo->src, &pinfo->dst );
899
65
  }
900
131
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "TACACS+");
901
902
131
  col_add_fstr( pinfo->cinfo, COL_INFO, "%s: %s",
903
131
        request ? "Q" : "R",
904
131
        val_to_str(tvb_get_uint8(tvb,1), tacplus_type_vals, "Unknown (0x%02x)"));
905
906
  /* if (tree) */
907
131
  {
908
131
    ti = proto_tree_add_item(tree, proto_tacplus, tvb, 0, -1, ENC_NA);
909
910
131
    tacplus_tree = proto_item_add_subtree(ti, ett_tacplus);
911
131
    if (pinfo->match_uint == pinfo->destport)
912
66
    {
913
66
      hidden_item = proto_tree_add_boolean(tacplus_tree,
914
66
          hf_tacplus_request, tvb, 0, 0, true);
915
66
    }
916
65
    else
917
65
    {
918
65
      hidden_item = proto_tree_add_boolean(tacplus_tree,
919
65
          hf_tacplus_response, tvb, 0, 0, true);
920
65
    }
921
131
    proto_item_set_hidden(hidden_item);
922
923
131
    version = tvb_get_uint8(tvb,0);
924
131
    proto_tree_add_uint_format_value(tacplus_tree, hf_tacplus_majvers, tvb, 0, 1,
925
131
        version,
926
131
        "%s",
927
131
        (version&0xf0)==0xc0?"TACACS+":"Unknown Version");
928
131
    proto_tree_add_uint(tacplus_tree, hf_tacplus_minvers, tvb, 0, 1,
929
131
        version&0xf);
930
131
    proto_tree_add_item(tacplus_tree, hf_tacplus_type, tvb, 1, 1,
931
131
        ENC_BIG_ENDIAN);
932
131
    proto_tree_add_item(tacplus_tree, hf_tacplus_seqno, tvb, 2, 1,
933
131
        ENC_BIG_ENDIAN);
934
131
    flags = tvb_get_uint8(tvb,3);
935
131
    tf = proto_tree_add_uint_format_value(tacplus_tree, hf_tacplus_flags,
936
131
        tvb, 3, 1, flags,
937
131
        "0x%02x (%s payload, %s)", flags,
938
131
        (flags&FLAGS_UNENCRYPTED) ? "Unencrypted" : "Encrypted",
939
131
        (flags&FLAGS_SINGLE) ? "Single connection" : "Multiple Connections" );
940
131
    flags_tree = proto_item_add_subtree(tf, ett_tacplus_flags);
941
131
    tmp_pi = proto_tree_add_boolean(flags_tree, hf_tacplus_flags_payload_type,
942
131
        tvb, 3, 1, flags);
943
131
    if (flags&FLAGS_UNENCRYPTED) {
944
39
      expert_add_info(pinfo, tmp_pi, &ei_tacplus_unencrypted);
945
39
    }
946
131
    proto_tree_add_boolean(flags_tree, hf_tacplus_flags_connection_type,
947
131
        tvb, 3, 1, flags);
948
131
    proto_tree_add_item(tacplus_tree, hf_tacplus_session_id, tvb, 4, 4,
949
131
        ENC_BIG_ENDIAN);
950
951
131
    tmp_pi = proto_tree_add_uint(tacplus_tree, hf_tacplus_packet_len, tvb, 8, 4, len);
952
131
    if ((int)len < 1) {
953
89
      expert_add_info_format(pinfo, tmp_pi, &ei_tacplus_packet_len_invalid, "Invalid length: %u", len);
954
89
    }
955
956
131
    body_tree = proto_tree_add_subtree_format(tacplus_tree, tvb, TAC_PLUS_HDR_SIZE, len,
957
131
            ett_tacplus_body, NULL, "%s%s", ((flags&FLAGS_UNENCRYPTED)?"":"Encrypted "), request?"Request":"Reply" );
958
959
131
    if( flags&FLAGS_UNENCRYPTED ) {
960
39
      new_tvb = tvb_new_subset_length( tvb, TAC_PLUS_HDR_SIZE, len );
961
92
    }  else {
962
92
      new_tvb=NULL;
963
92
      if( key && *key ){
964
0
        tacplus_decrypted_tvb_setup( tvb, &new_tvb, pinfo, len, version, key );
965
0
      }
966
92
    }
967
131
    if( new_tvb ) {
968
      /* Check to see if I've a decrypted tacacs packet */
969
39
      if( !(flags&FLAGS_UNENCRYPTED) ){
970
0
        body_tree = proto_tree_add_subtree_format(tacplus_tree, new_tvb, 0, len,
971
0
              ett_tacplus_body, NULL, "Decrypted %s", request?"Request":"Reply" );
972
0
      }
973
39
      dissect_tacplus_body( tvb, pinfo, new_tvb, body_tree);
974
39
    }
975
131
  }
976
131
  return tvb_captured_length(tvb);
977
131
}
978
979
static void
980
tacplus_pref_cb(void)
981
0
{
982
0
  parse_tacplus_keys( tacplus_opt_key );
983
0
}
984
985
void
986
proto_register_tacplus(void)
987
14
{
988
14
  static hf_register_info hf[] = {
989
14
    { &hf_tacplus_response,
990
14
      { "Response", "tacplus.response",
991
14
        FT_BOOLEAN, BASE_NONE, NULL, 0x0,
992
14
        "true if TACACS+ response", HFILL }},
993
14
    { &hf_tacplus_request,
994
14
      { "Request", "tacplus.request",
995
14
        FT_BOOLEAN, BASE_NONE, NULL, 0x0,
996
14
        "true if TACACS+ request", HFILL }},
997
14
    { &hf_tacplus_majvers,
998
14
      { "Major version", "tacplus.majvers",
999
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1000
14
        "Major version number", HFILL }},
1001
14
    { &hf_tacplus_minvers,
1002
14
      { "Minor version", "tacplus.minvers",
1003
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1004
14
        "Minor version number", HFILL }},
1005
14
    { &hf_tacplus_type,
1006
14
      { "Type", "tacplus.type",
1007
14
        FT_UINT8, BASE_DEC, VALS(tacplus_type_vals), 0x0,
1008
14
        NULL, HFILL }},
1009
14
    { &hf_tacplus_seqno,
1010
14
      { "Sequence number", "tacplus.seqno",
1011
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1012
14
        NULL, HFILL }},
1013
14
    { &hf_tacplus_flags,
1014
14
      { "Flags", "tacplus.flags",
1015
14
        FT_UINT8, BASE_HEX, NULL, 0x0,
1016
14
        NULL, HFILL }},
1017
14
    { &hf_tacplus_flags_payload_type,
1018
14
      { "Unencrypted", "tacplus.flags.unencrypted",
1019
14
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), FLAGS_UNENCRYPTED,
1020
14
        "Is payload unencrypted? (deprecated)", HFILL }},
1021
14
    { &hf_tacplus_flags_connection_type,
1022
14
      { "Single Connection", "tacplus.flags.singleconn",
1023
14
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), FLAGS_SINGLE,
1024
14
        "Is this a single connection?", HFILL }},
1025
14
    { &hf_tacplus_acct_flags,
1026
14
      { "Flags", "tacplus.acct.flags",
1027
14
        FT_UINT8, BASE_HEX, NULL, 0x0,
1028
14
        NULL, HFILL }},
1029
14
    { &hf_tacplus_acct_flags_more,
1030
14
      { "More", "tacplus.acct.flags.more",
1031
14
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), TAC_PLUS_ACCT_FLAG_MORE,
1032
14
        NULL, HFILL }},
1033
14
    { &hf_tacplus_acct_flags_start,
1034
14
      { "Start", "tacplus.acct.flags.start",
1035
14
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), TAC_PLUS_ACCT_FLAG_START,
1036
14
        NULL, HFILL }},
1037
14
    { &hf_tacplus_acct_flags_stop,
1038
14
      { "Stop", "tacplus.acct.flags.stop",
1039
14
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), TAC_PLUS_ACCT_FLAG_STOP,
1040
14
        NULL, HFILL }},
1041
14
    { &hf_tacplus_acct_flags_watchdog,
1042
14
      { "Watchdog", "tacplus.acct.flags.watchdog",
1043
14
        FT_BOOLEAN, 8, TFS(&tfs_set_notset), TAC_PLUS_ACCT_FLAG_WATCHDOG,
1044
14
        NULL, HFILL }},
1045
14
    { &hf_tacplus_session_id,
1046
14
      { "Session ID", "tacplus.session_id",
1047
14
        FT_UINT32, BASE_DEC, NULL, 0x0,
1048
14
        NULL, HFILL }},
1049
14
    { &hf_tacplus_packet_len,
1050
14
      { "Packet length", "tacplus.packet_len",
1051
14
        FT_UINT32, BASE_DEC, NULL, 0x0,
1052
14
        NULL, HFILL }},
1053
14
    { &hf_tacplus_auth_password,
1054
14
      { "Password", "tacplus.auth_password",
1055
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1056
14
        NULL, HFILL }},
1057
14
    { &hf_tacplus_port,
1058
14
      { "Port", "tacplus.port",
1059
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1060
14
        NULL, HFILL }},
1061
14
    { &hf_tacplus_remote_address,
1062
14
      { "Remote Address", "tacplus.remote_address",
1063
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1064
14
        NULL, HFILL }},
1065
14
    { &hf_tacplus_chap_challenge,
1066
14
      { "Challenge", "tacplus.chap.challenge",
1067
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1068
14
        NULL, HFILL }},
1069
14
    { &hf_tacplus_chap_response,
1070
14
      { "Response", "tacplus.chap.response",
1071
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1072
14
        NULL, HFILL }},
1073
14
    { &hf_tacplus_mschap_challenge,
1074
14
      { "Challenge", "tacplus.mschap.challenge",
1075
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1076
14
        NULL, HFILL }},
1077
14
    { &hf_tacplus_mschap_response,
1078
14
      { "Response", "tacplus.mschap.response",
1079
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1080
14
        NULL, HFILL }},
1081
14
    { &hf_tacplus_arap_nas_challenge,
1082
14
      { "Nas Challenge", "tacplus.arap.nas_challenge",
1083
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1084
14
        NULL, HFILL }},
1085
14
    { &hf_tacplus_arap_remote_challenge,
1086
14
      { "Remote Challenge", "tacplus.arap.remote_challenge",
1087
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1088
14
        NULL, HFILL }},
1089
14
    { &hf_tacplus_arap_remote_response,
1090
14
      { "Remote Response", "tacplus.arap.remote_response",
1091
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1092
14
        NULL, HFILL }},
1093
14
    { &hf_tacplus_privilege_level,
1094
14
      { "Privilege Level", "tacplus.privilege_level",
1095
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1096
14
        NULL, HFILL }},
1097
14
    { &hf_tacplus_authentication_type,
1098
14
      { "Authentication type", "tacplus.authentication_type",
1099
14
        FT_UINT8, BASE_DEC, VALS(tacplus_authen_type_vals), 0x0,
1100
14
        NULL, HFILL }},
1101
14
    { &hf_tacplus_service,
1102
14
      { "Service", "tacplus.service",
1103
14
        FT_UINT8, BASE_DEC, VALS(tacplus_authen_service_vals), 0x0,
1104
14
        NULL, HFILL }},
1105
14
    { &hf_tacplus_user_len,
1106
14
      { "User len", "tacplus.user_len",
1107
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1108
14
        NULL, HFILL }},
1109
14
    { &hf_tacplus_user,
1110
14
      { "User", "tacplus.user",
1111
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1112
14
        NULL, HFILL }},
1113
14
    { &hf_tacplus_port_len,
1114
14
      { "Port len", "tacplus.port_len",
1115
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1116
14
        NULL, HFILL }},
1117
14
    { &hf_tacplus_remote_address_len,
1118
14
      { "Remaddr len", "tacplus.address_len",
1119
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1120
14
        NULL, HFILL }},
1121
14
    { &hf_tacplus_arg_length,
1122
14
      { "Length", "tacplus.arg_length",
1123
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1124
14
        NULL, HFILL }},
1125
14
    { &hf_tacplus_arg_value,
1126
14
      { "Value", "tacplus.arg_value",
1127
14
        FT_STRINGZ, BASE_NONE, NULL, 0x0,
1128
14
        NULL, HFILL }},
1129
14
    { &hf_tacplus_chap_id,
1130
14
      { "ID", "tacplus.chap.id",
1131
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1132
14
        NULL, HFILL }},
1133
14
    { &hf_tacplus_mschap_id,
1134
14
      { "ID", "tacplus.mschap.id",
1135
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1136
14
        NULL, HFILL }},
1137
14
    { &hf_tacplus_authen_action,
1138
14
      { "Action", "tacplus.authen_action",
1139
14
        FT_UINT8, BASE_DEC, VALS(tacplus_authen_action_vals), 0x0,
1140
14
        NULL, HFILL }},
1141
14
    { &hf_tacplus_body_authen_req_cont_flags,
1142
14
      { "Flags", "tacplus.body_authen_req_cont.flags",
1143
14
        FT_UINT8, BASE_HEX, NULL, 0x0,
1144
14
        NULL, HFILL }},
1145
14
    { &hf_tacplus_body_authen_req_cont_user_length,
1146
14
      { "User length", "tacplus.body_authen_req_cont.user_length",
1147
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1148
14
        NULL, HFILL }},
1149
14
    { &hf_tacplus_body_authen_req_cont_data_length,
1150
14
      { "Data length", "tacplus.body_authen_req_cont.data_length",
1151
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1152
14
        NULL, HFILL }},
1153
14
    { &hf_tacplus_body_authen_req_cont_user,
1154
14
      { "User", "tacplus.body_authen_req_cont.user",
1155
14
        FT_STRING, BASE_NONE, NULL, 0x0,
1156
14
        NULL, HFILL }},
1157
14
    { &hf_tacplus_body_authen_rep_status,
1158
14
      { "Status", "tacplus.body_authen_rep.status",
1159
14
        FT_UINT8, BASE_HEX, VALS(tacplus_reply_status_vals), 0x0,
1160
14
        NULL, HFILL }},
1161
14
    { &hf_tacplus_body_authen_rep_flags,
1162
14
      { "Flags", "tacplus.body_authen_rep.flags",
1163
14
        FT_UINT8, BASE_HEX, NULL, 0x0,
1164
14
        NULL, HFILL }},
1165
14
    { &hf_tacplus_body_authen_rep_server_msg_len,
1166
14
      { "Server message length", "tacplus.body_authen_rep.server_msg_len",
1167
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1168
14
        NULL, HFILL }},
1169
14
    { &hf_tacplus_body_authen_rep_server_msg,
1170
14
      { "Server message", "tacplus.body_authen_rep.server_msg",
1171
14
        FT_STRING, BASE_NONE, NULL, 0x0,
1172
14
        NULL, HFILL }},
1173
14
    { &hf_tacplus_body_authen_rep_server_data_len,
1174
14
      { "Data length", "tacplus.body_authen_rep_server.data_len",
1175
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1176
14
        NULL, HFILL }},
1177
14
    { &hf_tacplus_body_author_req_auth_method,
1178
14
      { "Auth Method", "tacplus.body_author_req.auth_method",
1179
14
        FT_UINT8, BASE_HEX, VALS(tacplus_authen_method), 0x0,
1180
14
        NULL, HFILL }},
1181
14
    { &hf_tacplus_body_author_req_arg_count,
1182
14
      { "Arg count", "tacplus.body_author_req.arg_count",
1183
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1184
14
        NULL, HFILL }},
1185
14
    { &hf_tacplus_body_author_rep_auth_status,
1186
14
      { "Auth Status", "tacplus.body_author_rep.auth_status",
1187
14
        FT_UINT8, BASE_HEX, VALS(tacplus_author_status), 0x0,
1188
14
        NULL, HFILL }},
1189
14
    { &hf_tacplus_body_author_rep_server_msg_len,
1190
14
      { "Server Msg length", "tacplus.body_author_rep_server.msg_len",
1191
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1192
14
        NULL, HFILL }},
1193
14
    { &hf_tacplus_body_author_rep_server_data_len,
1194
14
      { "Data length", "tacplus.body_author_rep_server.data_len",
1195
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1196
14
        NULL, HFILL }},
1197
14
    { &hf_tacplus_body_author_rep_arg_count,
1198
14
      { "Arg count", "tacplus.body_author_rep.arg_count",
1199
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1200
14
        NULL, HFILL }},
1201
14
    { &hf_tacplus_acct_authen_method,
1202
14
      { "Auth Method", "tacplus.acct.auth_method",
1203
14
        FT_UINT8, BASE_HEX, VALS(tacplus_authen_method), 0x0,
1204
14
        NULL, HFILL }},
1205
14
    { &hf_tacplus_acct_arg_count,
1206
14
      { "Arg count", "tacplus.acct.arg_count",
1207
14
        FT_UINT8, BASE_DEC, NULL, 0x0,
1208
14
        NULL, HFILL }},
1209
14
    { &hf_tacplus_body_acct_status,
1210
14
      { "Status", "tacplus.body_acct.status",
1211
14
        FT_UINT8, BASE_HEX, VALS(tacplus_acct_status), 0x0,
1212
14
        NULL, HFILL }},
1213
14
    { &hf_tacplus_body_acct_server_msg_len,
1214
14
      { "Server Msg length", "tacplus.body_acct.msg_len",
1215
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1216
14
        NULL, HFILL }},
1217
14
    { &hf_tacplus_body_acct_data_len,
1218
14
      { "Data length", "tacplus.body_acct.data_len",
1219
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
1220
14
        NULL, HFILL }},
1221
14
    { &hf_tacplus_body_acct_server_msg,
1222
14
      { "Server message", "tacplus.body_acct.server_msg",
1223
14
        FT_STRING, BASE_NONE, NULL, 0x0,
1224
14
        NULL, HFILL }},
1225
14
    { &hf_tacplus_body_acct_data,
1226
14
      { "Data", "tacplus.body_acct.data",
1227
14
        FT_STRING, BASE_NONE, NULL, 0x0,
1228
14
        NULL, HFILL }},
1229
14
    { &hf_tacplus_data,
1230
14
      { "Data", "tacplus.data",
1231
14
        FT_BYTES, BASE_NONE, NULL, 0x0,
1232
14
        NULL, HFILL }},
1233
1234
  /* Generated from convert_proto_tree_add_text.pl */
1235
14
    { &hf_tacplus_ascii_length, { "ASCII Data Length", "tacplus.ascii_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1236
14
    { &hf_tacplus_password_length, { "Password Length", "tacplus.password_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1237
14
    { &hf_tacplus_chap_data_length, { "CHAP Data Length", "tacplus.chap_data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1238
14
    { &hf_tacplus_mschap_data_length, { "MSCHAP Data Length", "tacplus.mschap_data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1239
14
    { &hf_tacplus_arap_data_length, { "ARAP Data Length", "tacplus.arap_data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1240
14
    { &hf_tacplus_data_length, { "Data", "tacplus.data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1241
14
  };
1242
1243
14
  static int *ett[] = {
1244
14
    &ett_tacplus,
1245
14
    &ett_tacplus_flags,
1246
14
    &ett_tacplus_acct_flags,
1247
14
    &ett_tacplus_body,
1248
14
    &ett_tacplus_body_chap,
1249
14
  };
1250
1251
14
  static ei_register_info ei[] = {
1252
14
    { &ei_tacplus_packet_len_invalid, { "tacplus.packet_len.invalid", PI_PROTOCOL, PI_WARN, "Invalid length", EXPFILL }},
1253
14
    { &ei_tacplus_unencrypted, { "tacplus.flags.unencrypted.deprecated", PI_SECURITY, PI_WARN, "Unencrypted payload option MUST NOT be used in production", EXPFILL }},
1254
14
    { &ei_tacplus_bogus_data, { "tacplus.bogus_data", PI_PROTOCOL, PI_WARN, "Bogus data", EXPFILL }},
1255
14
  };
1256
1257
14
  module_t *tacplus_module;
1258
14
  expert_module_t* expert_tacplus;
1259
1260
14
  proto_tacplus = proto_register_protocol("TACACS+", "TACACS+", "tacplus");
1261
14
  proto_register_field_array(proto_tacplus, hf, array_length(hf));
1262
14
  proto_register_subtree_array(ett, array_length(ett));
1263
14
  tacplus_handle = register_dissector("tacplus", dissect_tacplus, proto_tacplus);
1264
14
  expert_tacplus = expert_register_protocol(proto_tacplus);
1265
14
  expert_register_field_array(expert_tacplus, ei, array_length(ei));
1266
14
  tacplus_module = prefs_register_protocol (proto_tacplus, tacplus_pref_cb );
1267
1268
14
  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);
1269
1270
14
  prefs_register_string_preference ( tacplus_module, "key",
1271
14
  "TACACS+ Encryption Key", "TACACS+ Encryption Key", &tacplus_opt_key );
1272
14
}
1273
1274
void
1275
proto_reg_handoff_tacplus(void)
1276
14
{
1277
14
  dissector_add_uint_with_preference("tcp.port", TCP_PORT_TACACS, tacplus_handle);
1278
14
}
1279
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 )
1282
0
{
1283
0
  int i,j;
1284
0
  size_t md5_len;
1285
0
  uint8_t *md5_buff;
1286
0
  uint8_t hash[HASH_MD5_LENGTH];        /* the md5 hash */
1287
0
  uint8_t *mdp;
1288
1289
0
  md5_len = 4 /* sizeof(session_id) */ + strlen(key)
1290
0
      + sizeof(version) + sizeof(seq_no);
1291
1292
0
  md5_buff = (uint8_t*)wmem_alloc(wmem_packet_scope(), md5_len + HASH_MD5_LENGTH);
1293
1294
1295
0
  mdp = md5_buff;
1296
0
  memcpy(mdp, session_id, 4);
1297
0
  mdp += 4 ;
1298
0
  memcpy(mdp, key, strlen(key));
1299
0
  mdp += strlen(key);
1300
0
  *mdp++ = version;
1301
0
  *mdp++ = seq_no;
1302
1303
1304
0
  gcry_md_hash_buffer(GCRY_MD_MD5, hash, md5_buff, md5_len);
1305
0
  md5_len += HASH_MD5_LENGTH;
1306
0
  for (i = 0; i < data_len; i += 16) {
1307
1308
0
    for (j = 0; j < 16; j++) {
1309
0
      if ((i + j) >= data_len)  {
1310
0
        i = data_len+1; /* To exit from the external loop  */
1311
0
        break;
1312
0
      }
1313
0
      data[i + j] ^= hash[j];
1314
0
    }
1315
0
    memcpy(mdp, hash, HASH_MD5_LENGTH);
1316
0
    gcry_md_hash_buffer(GCRY_MD_MD5, hash, md5_buff, md5_len);
1317
0
  }
1318
0
}
1319
1320
/*
1321
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1322
 *
1323
 * Local variables:
1324
 * c-basic-offset: 8
1325
 * tab-width: 8
1326
 * indent-tabs-mode: t
1327
 * End:
1328
 *
1329
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1330
 * :indentSize=8:tabSize=8:noTabs=false:
1331
 */