Coverage Report

Created: 2025-07-18 06:58

/src/ndpi/src/lib/protocols/kerberos.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * kerberos.c
3
 *
4
 * Copyright (C) 2011-25 - ntop.org
5
 * Copyright (C) 2009-11 - ipoque GmbH
6
 *
7
 * This file is part of nDPI, an open source deep packet inspection
8
 * library based on the OpenDPI and PACE technology by ipoque GmbH
9
 *
10
 * nDPI is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Lesser General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * nDPI is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
#include "ndpi_protocol_ids.h"
26
27
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_KERBEROS
28
29
#include "ndpi_api.h"
30
#include "ndpi_private.h"
31
32
/* #define KERBEROS_DEBUG 1 */
33
34
0
#define KERBEROS_PORT 88
35
36
static int ndpi_search_kerberos_extra(struct ndpi_detection_module_struct *ndpi_struct,
37
              struct ndpi_flow_struct *flow);
38
39
40
/* Reference: https://en.wikipedia.org/wiki/X.690#Length_octets */
41
static int krb_decode_asn1_length(struct ndpi_detection_module_struct *ndpi_struct,
42
                                  size_t * const kasn1_offset)
43
0
{
44
0
  struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
45
0
  int64_t length;
46
0
  u_int16_t value_len;
47
48
0
  length = asn1_ber_decode_length(&packet->payload[*kasn1_offset],
49
0
          packet->payload_packet_len - *kasn1_offset,
50
0
          &value_len);
51
52
0
  if (length == -1 ||
53
0
      packet->payload_packet_len < *kasn1_offset + value_len + length)
54
0
  {
55
0
    return -1;
56
0
  }
57
58
0
  *kasn1_offset += value_len;
59
60
0
  return (int)length;
61
0
}
62
63
/* Reference: https://en.wikipedia.org/wiki/X.690#Identifier_octets */
64
static int krb_decode_asn1_sequence_type(struct ndpi_detection_module_struct *ndpi_struct,
65
                                         size_t * const kasn1_offset)
66
0
{
67
0
  struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
68
69
0
  if (packet->payload_packet_len <= *kasn1_offset + 1 /* length octet */ ||
70
0
      packet->payload[*kasn1_offset] != 0x30 /* Universal Constructed Tag Type: Sequence */)
71
0
  {
72
0
    return -1;
73
0
  }
74
75
0
  (*kasn1_offset)++;
76
77
0
  return krb_decode_asn1_length(ndpi_struct, kasn1_offset);
78
0
}
79
80
/* Reference: https://en.wikipedia.org/wiki/X.690#Identifier_octets */
81
static int krb_decode_asn1_string_type(struct ndpi_detection_module_struct *ndpi_struct,
82
                                       size_t * const kasn1_offset,
83
                                       char const ** const out)
84
0
{
85
0
  struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
86
0
  int length;
87
88
0
  if (packet->payload_packet_len <= *kasn1_offset + 1 /* length octet */ ||
89
0
      (packet->payload[*kasn1_offset] != 0xA3 /* Context-specific Constructed Tag Type: Bit String */ &&
90
0
       packet->payload[*kasn1_offset] != 0xA4 /* Context-specific Constructed Tag Type: Octect String */ &&
91
0
       packet->payload[*kasn1_offset] != 0x30 /* Sequence Of */))
92
0
  {
93
0
    return -1;
94
0
  }
95
96
0
  (*kasn1_offset)++;
97
98
0
  length = krb_decode_asn1_length(ndpi_struct, kasn1_offset);
99
0
  if (length <= 0)
100
0
  {
101
0
    return -1;
102
0
  }
103
104
0
  if (out != NULL)
105
0
  {
106
0
    *out = (char *)&packet->payload[*kasn1_offset];
107
0
  }
108
109
0
  return length;
110
0
}
111
112
/* Reference: https://en.wikipedia.org/wiki/X.690#Identifier_octets */
113
static int krb_decode_asn1_int_type(struct ndpi_detection_module_struct *ndpi_struct,
114
                                    size_t * const kasn1_offset,
115
                                    int * const out)
116
0
{
117
0
  struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
118
0
  int length;
119
120
0
  if (packet->payload_packet_len <= *kasn1_offset + 1 /* length octet */ ||
121
0
      packet->payload[*kasn1_offset] != 0x02)
122
0
  {
123
0
    return -1;
124
0
  }
125
126
0
  (*kasn1_offset)++;
127
128
0
  length = krb_decode_asn1_length(ndpi_struct, kasn1_offset);
129
0
  if (length <= 0 || length > 4)
130
0
  {
131
0
    return -1;
132
0
  }
133
134
0
  if (out != NULL)
135
0
  {
136
0
    int i = 0;
137
0
    *out = 0;
138
0
    for (; i < length; ++i)
139
0
    {
140
0
      *out |= (unsigned int)packet->payload[*kasn1_offset + i] << (length - i - 1) * 8;
141
0
    }
142
0
    *kasn1_offset += i;
143
0
  }
144
145
0
  return length;
146
0
}
147
148
/* Tags in which we are not interested. */
149
static int krb_decode_asn1_blocks_skip(struct ndpi_detection_module_struct *ndpi_struct,
150
                                       size_t * const kasn1_offset)
151
0
{
152
0
  struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
153
0
  int length;
154
155
0
  if (packet->payload_packet_len <= *kasn1_offset + 1 /* length octet */ ||
156
0
      (packet->payload[*kasn1_offset] != 0xA0 /* Constructed Context-specific NULL */ &&
157
0
       packet->payload[*kasn1_offset] != 0xA1 /* Constructed Context-specific BOOLEAN */ &&
158
0
       packet->payload[*kasn1_offset] != 0xA2 /* Constructed Context-specific INTEGER */))
159
0
  {
160
0
    return -1;
161
0
  }
162
163
0
  (*kasn1_offset)++;
164
165
0
  length = krb_decode_asn1_length(ndpi_struct, kasn1_offset);
166
0
  if (length < 0)
167
0
  {
168
0
    return -1;
169
0
  }
170
171
0
  return length;
172
0
}
173
174
static void krb_strncpy_lower(char * const dst, size_t dst_siz,
175
                              char const * const src, size_t src_siz)
176
0
{
177
0
  int i, dst_len = (int)ndpi_min(src_siz, dst_siz - 1);
178
179
0
   dst[dst_len] = '\0';
180
181
0
   for(i = 0; i < dst_len; ++i)
182
0
   {
183
0
     if (ndpi_isprint(src[i]) == 0)
184
0
     {
185
0
       dst[i] = '?';
186
0
     } else {
187
0
       dst[i] = tolower(src[i]);
188
0
     }
189
0
   }
190
0
}
191
192
/* Reference: https://datatracker.ietf.org/doc/html/rfc4120 */
193
static int krb_parse(struct ndpi_detection_module_struct * const ndpi_struct,
194
                     struct ndpi_flow_struct * const flow,
195
                     size_t payload_offset)
196
0
{
197
0
  size_t kasn1_offset = payload_offset;
198
0
  int length, krb_version, msg_type;
199
0
  char const * text;
200
201
0
  length = krb_decode_asn1_sequence_type(ndpi_struct, &kasn1_offset);
202
0
  if (length < 0)
203
0
  {
204
0
    return -1;
205
0
  }
206
207
0
  length = krb_decode_asn1_blocks_skip(ndpi_struct, &kasn1_offset);
208
0
  if (length < 0)
209
0
  {
210
0
    return -1;
211
0
  }
212
213
0
  length = krb_decode_asn1_int_type(ndpi_struct, &kasn1_offset, &krb_version); /* pvno */
214
0
  if (length != 1 || krb_version != 5)
215
0
  {
216
0
    return -1;
217
0
  }
218
219
0
  length = krb_decode_asn1_blocks_skip(ndpi_struct, &kasn1_offset);
220
0
  if (length < 0)
221
0
  {
222
0
    return -1;
223
0
  }
224
225
0
  length = krb_decode_asn1_int_type(ndpi_struct, &kasn1_offset, &msg_type); /* msg-type */
226
0
  if (length != 1 || msg_type != 0x0d /* TGS-REP */)
227
0
  {
228
0
    return -1;
229
0
  }
230
231
0
  krb_decode_asn1_blocks_skip(ndpi_struct, &kasn1_offset);
232
233
0
  length = krb_decode_asn1_sequence_type(ndpi_struct, &kasn1_offset); /* Optional PADATA */
234
0
  if (length > 0)
235
0
  {
236
0
    kasn1_offset += length;
237
0
  }
238
239
0
  length = krb_decode_asn1_string_type(ndpi_struct, &kasn1_offset, &text);
240
0
  if (length < 3)
241
0
  {
242
0
    return -1;
243
0
  }
244
245
0
  kasn1_offset += length;
246
0
  text += 2;
247
0
  length -= 2;
248
0
  if (flow->protos.kerberos.domain[0] == '\0')
249
0
  {
250
0
    krb_strncpy_lower(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain),
251
0
                      text, length);
252
0
  }
253
254
0
  length = krb_decode_asn1_string_type(ndpi_struct, &kasn1_offset, NULL);
255
0
  if (length < 0)
256
0
  {
257
0
    return -1;
258
0
  }
259
260
0
  length = krb_decode_asn1_sequence_type(ndpi_struct, &kasn1_offset);
261
0
  if (length < 0)
262
0
  {
263
0
    return -1;
264
0
  }
265
266
0
  length = krb_decode_asn1_blocks_skip(ndpi_struct, &kasn1_offset);
267
0
  if (length < 0)
268
0
  {
269
0
    return -1;
270
0
  }
271
0
  kasn1_offset += length;
272
273
0
  length = krb_decode_asn1_blocks_skip(ndpi_struct, &kasn1_offset);
274
0
  if (length < 0)
275
0
  {
276
0
    return -1;
277
0
  }
278
279
0
  length = krb_decode_asn1_string_type(ndpi_struct, &kasn1_offset, &text);
280
0
  if (length < 3)
281
0
  {
282
0
    return -1;
283
0
  }
284
285
0
  kasn1_offset += length;
286
0
  text += 2;
287
0
  length -= 2;
288
0
  if (flow->protos.kerberos.hostname[0] == '\0' && text[length - 1] != '$')
289
0
  {
290
0
    krb_strncpy_lower(flow->protos.kerberos.hostname, sizeof(flow->protos.kerberos.hostname),
291
0
                      text, length);
292
0
  } else if (flow->protos.kerberos.username[0] == '\0') {
293
0
    krb_strncpy_lower(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username),
294
0
                      text, length - 1);
295
0
  }
296
297
0
  return 0;
298
0
}
299
300
static void ndpi_int_kerberos_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
301
0
               struct ndpi_flow_struct *flow) {
302
0
  ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_KERBEROS, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
303
0
  NDPI_LOG_DBG(ndpi_struct, "trace KERBEROS\n");
304
0
}
305
306
/* ************************************************* */
307
308
static void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
309
0
         struct ndpi_flow_struct *flow) {
310
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
311
0
  u_int16_t sport = packet->tcp ? ntohs(packet->tcp->source) : ntohs(packet->udp->source);
312
0
  u_int16_t dport = packet->tcp ? ntohs(packet->tcp->dest) : ntohs(packet->udp->dest);
313
0
  const u_int8_t *original_packet_payload = NULL;
314
0
  u_int16_t original_payload_packet_len = 0;
315
316
0
  if((sport != KERBEROS_PORT) && (dport != KERBEROS_PORT)) {
317
0
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
318
0
    return;
319
0
  }
320
  
321
0
  NDPI_LOG_DBG(ndpi_struct, "search KERBEROS\n");
322
323
#ifdef KERBEROS_DEBUG
324
  printf("\n[Kerberos] Process packet [len: %u]\n", packet->payload_packet_len);
325
#endif
326
    
327
0
  if(flow->kerberos_buf.pktbuf != NULL) {
328
0
    u_int missing = flow->kerberos_buf.pktbuf_maxlen - flow->kerberos_buf.pktbuf_currlen;
329
330
0
    if(packet->payload_packet_len <= missing) {
331
0
      memcpy(&flow->kerberos_buf.pktbuf[flow->kerberos_buf.pktbuf_currlen], packet->payload, packet->payload_packet_len);
332
0
      flow->kerberos_buf.pktbuf_currlen += packet->payload_packet_len;
333
334
0
      if(flow->kerberos_buf.pktbuf_currlen == flow->kerberos_buf.pktbuf_maxlen) {
335
0
  original_packet_payload = packet->payload;
336
0
  original_payload_packet_len = packet->payload_packet_len;
337
0
  packet->payload = (u_int8_t *)flow->kerberos_buf.pktbuf;
338
0
  packet->payload_packet_len = flow->kerberos_buf.pktbuf_currlen;
339
#ifdef KERBEROS_DEBUG
340
  printf("[Kerberos] Packet is now full: processing\n");
341
#endif
342
0
      } else {
343
#ifdef KERBEROS_DEBUG
344
  printf("[Kerberos] Missing %u bytes: skipping\n",
345
         flow->kerberos_buf.pktbuf_maxlen - flow->kerberos_buf.pktbuf_currlen);
346
#endif
347
348
0
  return;
349
0
      }
350
0
    }
351
0
  }
352
353
  /* I have observed 0a,0c,0d,0e at packet->payload[19/21], maybe there are other possibilities */
354
0
  if(packet->payload_packet_len >= 4) {
355
0
    u_int32_t kerberos_len, expected_len;
356
0
    u_int16_t base_offset = 0;
357
358
0
    if(packet->tcp) {
359
0
      kerberos_len = ntohl(get_u_int32_t(packet->payload, 0)),
360
0
  expected_len = packet->payload_packet_len - 4;
361
0
      base_offset = 4;
362
0
    } else
363
0
      base_offset = 0, kerberos_len = expected_len = packet->payload_packet_len;
364
365
#ifdef KERBEROS_DEBUG
366
    printf("[Kerberos] [Kerberos len: %u][expected_len: %u]\n", kerberos_len, expected_len);
367
#endif
368
369
0
    if(kerberos_len < 12000) {
370
      /*
371
  Kerberos packets might be too long for a TCP packet
372
  so it could be split across two packets. Instead of
373
  rebuilding the stream we use a heuristic approach
374
      */
375
0
      if(kerberos_len > expected_len) {
376
0
  if(packet->tcp) {
377
0
    if(flow->kerberos_buf.pktbuf == NULL) {
378
0
      flow->kerberos_buf.pktbuf = (char*)ndpi_malloc(kerberos_len+4);
379
380
0
      if(flow->kerberos_buf.pktbuf != NULL) {
381
0
        flow->kerberos_buf.pktbuf_maxlen = kerberos_len+4;        
382
#ifdef KERBEROS_DEBUG
383
        printf("[Kerberos] Allocated %u bytes\n", flow->kerberos_buf.pktbuf_maxlen);
384
#endif        
385
0
      }
386
0
    }
387
    
388
0
    if(flow->kerberos_buf.pktbuf != NULL) {
389
0
      if(packet->payload_packet_len <= flow->kerberos_buf.pktbuf_maxlen) {
390
0
        memcpy(flow->kerberos_buf.pktbuf, packet->payload, packet->payload_packet_len);
391
0
        flow->kerberos_buf.pktbuf_currlen = packet->payload_packet_len;
392
0
      }
393
0
    }
394
0
  }
395
  
396
0
  return;
397
0
      } else if(kerberos_len == expected_len) {
398
0
  if(packet->payload_packet_len > 64) {
399
0
    u_int16_t koffset, i;
400
401
0
    for(i=8; i<16; i++)
402
0
      if((packet->payload[base_offset+i] == 0x03)
403
0
         && (packet->payload[base_offset+i+1] == 0x02)
404
0
         && (packet->payload[base_offset+i+2] == 0x01)
405
0
         && (packet->payload[base_offset+i+3] != 0x05)
406
0
         )
407
0
        break;
408
409
0
    koffset = base_offset + i + 3;
410
411
#ifdef KERBEROS_DEBUG
412
    printf("[Kerberos] [msg-type: 0x%02X/%u][koffset: %u]\n",
413
     packet->payload[koffset], packet->payload[koffset], koffset);
414
#endif
415
416
0
    if(((packet->payload[koffset] == 0x0A)
417
0
        || (packet->payload[koffset] == 0x0C)
418
0
        || (packet->payload[koffset] == 0x1E)
419
0
        || (packet->payload[koffset] == 0x0D)
420
0
        || (packet->payload[koffset] == 0x0E))) {
421
0
      u_int32_t koffsetp, body_offset = 0, pad_len;
422
0
      u_int8_t msg_type = packet->payload[koffset];
423
424
#ifdef KERBEROS_DEBUG
425
      printf("[Kerberos] Packet found 0x%02X/%u\n", msg_type, msg_type);
426
#endif
427
428
0
      ndpi_int_kerberos_add_connection(ndpi_struct, flow);
429
430
0
      if(msg_type != 0x0d) /* TGS-REP */ {
431
        /* Process only on requests */
432
0
        if(packet->payload[koffset+1] == 0xA3) {
433
0
    if(packet->payload[koffset+3] == 0x30)
434
0
      pad_len = packet->payload[koffset+4];
435
0
    else {
436
      /* Long pad */
437
0
      pad_len = packet->payload[koffset+2];
438
0
      for(i=3; i<10; i++) if(packet->payload[koffset+i] == pad_len) break;
439
440
0
      pad_len = (packet->payload[koffset+i+1] << 8) + packet->payload[koffset+i+2];
441
0
      koffset += i-2;
442
0
    }
443
0
        } else
444
0
    pad_len = 0;
445
446
#ifdef KERBEROS_DEBUG
447
        printf("pad_len=0x%02X/%u\n", pad_len, pad_len);
448
#endif
449
450
0
        if(pad_len > 0) {
451
0
    koffsetp = koffset + 2;
452
0
    for(i=0; i<4; i++) if(packet->payload[koffsetp] != 0x30) koffsetp++; /* ASN.1 */
453
#ifdef KERBEROS_DEBUG
454
    printf("koffsetp=%u [%02X %02X] [byte 0 must be 0x30]\n", koffsetp, packet->payload[koffsetp], packet->payload[koffsetp+1]);
455
#endif
456
0
        } else
457
0
    koffsetp = koffset;
458
459
0
        body_offset = koffsetp + 1 + pad_len;
460
461
0
        for(i=0; i<10; i++) if(body_offset<packet->payload_packet_len && packet->payload[body_offset] != 0x05) body_offset++; /* ASN.1 */
462
#ifdef KERBEROS_DEBUG
463
        printf("body_offset=%u [%02X %02X] [byte 0 must be 0x05]\n", body_offset, packet->payload[body_offset], packet->payload[body_offset+1]);
464
#endif
465
0
      }
466
      
467
0
      if(msg_type == 0x0A) /* AS-REQ */ {
468
#ifdef KERBEROS_DEBUG
469
        printf("[Kerberos] Processing AS-REQ\n");
470
#endif
471
472
473
0
        if(body_offset < packet->payload_packet_len) {
474
0
    u_int16_t name_offset = body_offset + 13;
475
    
476
0
    for(i=0; (i<20) && (name_offset < packet->payload_packet_len); i++) {
477
0
      if(packet->payload[name_offset] != 0x1b)
478
0
        name_offset++; /* ASN.1 */
479
0
    }
480
    
481
#ifdef KERBEROS_DEBUG
482
    printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]);
483
#endif
484
485
0
    if(name_offset < packet->payload_packet_len - 1) {
486
0
      u_int cname_len = 0;
487
488
0
      name_offset += 1;
489
0
      if(name_offset < packet->payload_packet_len - 1 &&
490
0
         ndpi_isprint(packet->payload[name_offset+1]) == 0) /* Isn't printable ? */
491
0
      {
492
0
        name_offset++;
493
0
      }
494
495
0
      if(name_offset < packet->payload_packet_len - 3 &&
496
0
         packet->payload[name_offset+1] == 0x1b)
497
0
      {
498
0
        name_offset += 2;
499
0
      }
500
      
501
0
      cname_len = packet->payload[name_offset];
502
503
0
      if((cname_len+name_offset) < packet->payload_packet_len) {
504
0
        u_int realm_len, realm_offset;
505
0
        char cname_str[48];
506
0
        u_int8_t num_cname = 0;
507
508
0
      cname_str[0] = '\0'; // required, because cname_len
509
510
0
        while(++num_cname <= 2) {
511
0
          if (name_offset + cname_len + 1 >= packet->payload_packet_len)
512
0
            cname_len = 0;
513
0
          krb_strncpy_lower(cname_str, sizeof(cname_str), (char*)&packet->payload[name_offset+1], cname_len);
514
515
#ifdef KERBEROS_DEBUG
516
          printf("[AS-REQ][s/dport: %u/%u][Kerberos Cname][len: %u][%s]\n", sport, dport, cname_len, cname_str);
517
#endif
518
519
0
          if(((strcmp(cname_str, "host") == 0) || (strcmp(cname_str, "ldap") == 0)) && (packet->payload[name_offset+1+cname_len] == 0x1b) && num_cname == 1) {
520
0
            name_offset += cname_len + 2;
521
0
            if (name_offset < packet->payload_packet_len)
522
0
              cname_len = packet->payload[name_offset];
523
0
          } else{
524
0
            break;
525
0
          }
526
0
        }
527
528
0
        realm_offset = cname_len + name_offset + 3;
529
530
        /* if cname does not end with a $ then it's a username */
531
0
        if(cname_len > 0 && name_offset + cname_len + 1 < packet->payload_packet_len
532
0
           && (cname_len < sizeof(cname_str))
533
0
           && (cname_str[cname_len-1] == '$')) {
534
0
          cname_str[cname_len-1] = '\0';
535
0
          ndpi_snprintf(flow->protos.kerberos.hostname, sizeof(flow->protos.kerberos.hostname), "%s", cname_str);
536
0
        } else
537
0
          ndpi_snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str);
538
539
0
        for(i=0; (i < 14) && (realm_offset <  packet->payload_packet_len); i++) {
540
0
          if(packet->payload[realm_offset] != 0x1b)
541
0
      realm_offset++; /* ASN.1 */
542
0
        }
543
        
544
#ifdef KERBEROS_DEBUG
545
        printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset,
546
         packet->payload[realm_offset], packet->payload[realm_offset+1]);
547
#endif
548
        
549
0
        realm_offset += 1;
550
        //if(num_cname == 2) realm_offset++;
551
0
        if(realm_offset  < packet->payload_packet_len) {
552
0
          realm_len = packet->payload[realm_offset];
553
554
0
          if((realm_offset+realm_len) < packet->payload_packet_len) {
555
0
      char realm_str[48];
556
557
0
      realm_offset += 1;
558
0
      krb_strncpy_lower(realm_str, sizeof(realm_str), (char*)&packet->payload[realm_offset], realm_len);
559
560
#ifdef KERBEROS_DEBUG
561
      printf("[AS-REQ][Kerberos Realm][len: %u][%s]\n", realm_len, realm_str);
562
#endif
563
0
            ndpi_snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str);
564
0
          }
565
0
        }
566
0
      }
567
0
    }
568
0
        } 
569
#ifdef KERBEROS_DEBUG
570
        printf("[Kerberos] Setting extra func from AS-REQ\n");
571
#endif
572
0
        flow->max_extra_packets_to_check = 5; /* Reply may be split into multiple segments */
573
0
        flow->extra_packets_func = ndpi_search_kerberos_extra;
574
0
      } else if(msg_type == 0x0e) /* AS-REQ */ {
575
#ifdef KERBEROS_DEBUG
576
        printf("[Kerberos] Processing AS-REQ\n");
577
#endif
578
        /* Nothing specific to do; stop dissecting this flow */
579
0
        flow->extra_packets_func = NULL;
580
581
0
      } else if(msg_type == 0x0c) /* TGS-REQ */ {
582
#ifdef KERBEROS_DEBUG
583
        printf("[Kerberos] Processing TGS-REQ\n");
584
#endif
585
586
0
        if(body_offset < packet->payload_packet_len) {
587
0
    u_int16_t name_offset, padding_offset = body_offset + 4;
588
589
0
    name_offset = padding_offset;
590
0
    for(i=0; i<14 && name_offset < packet->payload_packet_len; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
591
592
#ifdef KERBEROS_DEBUG
593
    printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]);
594
#endif
595
596
0
    if(name_offset < (packet->payload_packet_len - 1)) {
597
0
      u_int realm_len;
598
599
0
      name_offset++;
600
0
      realm_len = packet->payload[name_offset];
601
602
0
      if((realm_len+name_offset) < packet->payload_packet_len) {
603
0
        char realm_str[48];
604
605
0
        name_offset += 1;
606
0
        krb_strncpy_lower(realm_str, sizeof(realm_str), (char*)&packet->payload[name_offset], realm_len);
607
608
#ifdef KERBEROS_DEBUG
609
        printf("[TGS-REQ][s/dport: %u/%u][Kerberos Realm][len: %u][%s]\n", sport, dport, realm_len, realm_str);
610
#endif
611
0
        ndpi_snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str);
612
613
        /* If necessary we can decode sname */
614
0
        if(flow->kerberos_buf.pktbuf) {
615
0
          ndpi_free(flow->kerberos_buf.pktbuf);
616
0
          packet->payload = original_packet_payload;
617
0
          packet->payload_packet_len = original_payload_packet_len;
618
0
        }
619
0
        flow->kerberos_buf.pktbuf = NULL;
620
0
      }
621
0
    }
622
0
        }
623
#ifdef KERBEROS_DEBUG
624
        printf("[Kerberos] Setting extra func from TGS-REQ\n");
625
#endif
626
0
        if(!packet->udp) {
627
0
          flow->max_extra_packets_to_check = 5; /* Reply may be split into multiple segments */
628
0
          flow->extra_packets_func = ndpi_search_kerberos_extra;
629
0
        }
630
631
0
        if(flow->kerberos_buf.pktbuf != NULL) {
632
0
    ndpi_free(flow->kerberos_buf.pktbuf);
633
0
    packet->payload = original_packet_payload;
634
0
    packet->payload_packet_len = original_payload_packet_len;
635
0
    flow->kerberos_buf.pktbuf = NULL;
636
0
        }
637
638
0
        return;
639
0
      } else if(msg_type == 0x0d) /* TGS-REP */ {
640
0
        NDPI_LOG_DBG(ndpi_struct, "[Kerberos] Processing TGS-REP\n");
641
642
0
        if (krb_parse(ndpi_struct, flow, 8) != 0)
643
0
        {
644
0
          NDPI_LOG_DBG(ndpi_struct, "[TGS-REP] Invalid packet received\n");
645
0
          return;
646
0
        }
647
0
        NDPI_LOG_DBG(ndpi_struct,
648
0
                     "[TGS-REP][s/dport: %u/%u][Kerberos Hostname,Domain,Username][%s,%s,%s]\n",
649
0
                     sport, dport, flow->protos.kerberos.hostname, flow->protos.kerberos.domain,
650
0
                     flow->protos.kerberos.username);
651
0
        flow->extra_packets_func = NULL;
652
0
      } else if(msg_type == 0x1e) /* Error */ {
653
#ifdef KERBEROS_DEBUG
654
        printf("[Kerberos] Processing KRB-Error\n");
655
#endif
656
        /* Nothing specific to do; stop dissecting this flow */
657
0
        flow->extra_packets_func = NULL;
658
0
      }
659
660
0
      return;
661
0
    }
662
0
  }
663
0
      }
664
0
    } else {
665
#ifdef KERBEROS_DEBUG
666
      printf("[Kerberos][s/dport: %u/%u] Skipping packet: too long [kerberos_len: %u]\n",
667
       sport, dport, kerberos_len);
668
#endif
669
670
0
      if(flow->protos.kerberos.domain[0] != '\0')
671
0
  return;
672
0
    }
673
0
  }
674
675
0
  NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
676
0
}
677
678
static int ndpi_search_kerberos_extra(struct ndpi_detection_module_struct *ndpi_struct,
679
              struct ndpi_flow_struct *flow)
680
0
{
681
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
682
683
#ifdef KERBEROS_DEBUG
684
  printf("[Kerberos] Extra function\n");
685
#endif
686
687
  /* Unfortunately, generic "extra function" code doesn't honour protocol bitmask */
688
  /* TODO: handle that in ndpi_main.c for all the protocols */
689
0
  if(packet->payload_packet_len == 0 ||
690
0
     packet->tcp_retransmission)
691
0
    return 1;
692
693
  /* Possibly dissect the reply */
694
0
  ndpi_search_kerberos(ndpi_struct, flow);
695
696
  /* Possibly more processing */
697
0
  return flow->extra_packets_func != NULL;
698
0
}
699
700
1
void init_kerberos_dissector(struct ndpi_detection_module_struct *ndpi_struct) {
701
1
  register_dissector("Kerberos", ndpi_struct,
702
1
                     ndpi_search_kerberos,
703
1
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
704
1
                      1, NDPI_PROTOCOL_KERBEROS);
705
1
}