Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/oids.c
Line
Count
Source
1
/* oids.c
2
 * Object IDentifier Support
3
 *
4
 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
60
#define WS_LOG_DOMAIN LOG_DOMAIN_EPAN
15
16
#include <glib.h>
17
#include <stdio.h>
18
#include <string.h>
19
20
#include <wsutil/report_message.h>
21
22
#include <epan/strutil.h>
23
#include <epan/wmem_scopes.h>
24
#include "uat.h"
25
#include "prefs.h"
26
#include "proto.h"
27
#include <epan/packet.h>
28
#include "wsutil/filesystem.h"
29
#include "dissectors/packet-ber.h"
30
#include <wsutil/ws_assert.h>
31
#include <wsutil/file_util.h>
32
33
#ifdef HAVE_LIBSMI
34
#include <smi.h>
35
36
static bool smi_init_done;
37
static bool oids_init_done;
38
static bool load_smi_modules;
39
static bool suppress_smi_errors;
40
#endif
41
42
#include "oids.h"
43
44
/*
45
 * From SNMPv2-SMI and X.690
46
 *
47
 * Counter32  ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
48
 * Gauge32    ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
49
 * Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) (alias of Gauge32)
50
 * TimeTicks  ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
51
 *
52
 * If the BER encoding should not have the top bit set as to not become a negative number
53
 * the BER encoding may take 5 octets to encode.
54
 */
55
56
#ifdef HAVE_LIBSMI
57
static const oid_value_type_t integer_type =    { FT_INT32,  BASE_DEC,  BER_CLASS_UNI, BER_UNI_TAG_INTEGER,     1,   4, OID_KEY_TYPE_INTEGER, 1};
58
static const oid_value_type_t bytes_type =      { FT_BYTES,  BASE_SHOW_ASCII_PRINTABLE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 0,  -1, OID_KEY_TYPE_BYTES,   0};
59
static const oid_value_type_t oid_type =        { FT_OID,    BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OID,         1,  -1, OID_KEY_TYPE_OID,     0};
60
static const oid_value_type_t ipv4_type =       { FT_IPv4,   BASE_NONE, BER_CLASS_APP, 0,                       4,   4, OID_KEY_TYPE_IPADDR,  4};
61
static const oid_value_type_t counter32_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 1,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
62
static const oid_value_type_t unsigned32_type = { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 2,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
63
static const oid_value_type_t timeticks_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 3,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
64
#if 0
65
static const oid_value_type_t opaque_type =     { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 4,                       1,   4, OID_KEY_TYPE_BYTES,   0};
66
#endif
67
static const oid_value_type_t nsap_type =       { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 5,                       0,  -1, OID_KEY_TYPE_NSAP,    0};
68
static const oid_value_type_t counter64_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 6,                       1,   8, OID_KEY_TYPE_INTEGER, 1};
69
static const oid_value_type_t ipv6_type =       { FT_IPv6,   BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 16, 16, OID_KEY_TYPE_BYTES,   16};
70
static const oid_value_type_t float_type =      { FT_FLOAT,  BASE_DEC,  BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 4,   4, OID_KEY_TYPE_WRONG,   0};
71
static const oid_value_type_t double_type =     { FT_DOUBLE, BASE_DEC,  BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 8,   8, OID_KEY_TYPE_WRONG,   0};
72
static const oid_value_type_t ether_type =      { FT_ETHER,  BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 6,   6, OID_KEY_TYPE_ETHER,   6};
73
static const oid_value_type_t string_type =     { FT_STRING, BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 0,  -1, OID_KEY_TYPE_STRING,  0};
74
static const oid_value_type_t date_and_time_type = { FT_STRING,  BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 8,  11, OID_KEY_TYPE_DATE_AND_TIME,   0};
75
#endif /* HAVE_LIBSMI */
76
77
static const oid_value_type_t unknown_type =    { FT_BYTES,  BASE_NONE, BER_CLASS_ANY, BER_TAG_ANY,             0,  -1, OID_KEY_TYPE_WRONG,   0};
78
79
static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
80
81
// NOLINTNEXTLINE(misc-no-recursion)
82
26.3k
static void prepopulate_oids(void) {
83
26.3k
  if (!oid_root.children) {
84
15
    uint32_t subid;
85
86
15
    oid_root.children = wmem_tree_new(wmem_epan_scope());
87
88
    /*
89
     * make sure we got strings at least in the three root-children oids
90
     * that way oid_resolved() will always have a string to print
91
     */
92
    // We recurse here once.
93
15
    subid = 0; oid_add("itu-t",1,&subid);
94
15
    subid = 1; oid_add("iso",1,&subid);
95
15
    subid = 2; oid_add("joint-iso-itu-t",1,&subid);
96
15
  }
97
26.3k
}
98
99
// NOLINTNEXTLINE(misc-no-recursion)
100
26.3k
static oid_info_t* add_oid(const char* name, oid_kind_t kind, const oid_value_type_t* type, oid_key_t* key, unsigned oid_len, uint32_t *subids) {
101
26.3k
  unsigned i = 0;
102
26.3k
  oid_info_t* c = &oid_root;
103
104
26.3k
  prepopulate_oids();
105
26.3k
  oid_len--;
106
107
181k
  do {
108
181k
    oid_info_t* n = (oid_info_t *)wmem_tree_lookup32(c->children,subids[i]);
109
110
181k
    if(n) {
111
148k
      if (i == oid_len) {
112
765
        if (n->name) {
113
510
          if (!g_str_equal(n->name,name)) {
114
225
            ws_debug("Renaming Oid from: %s -> %s, this means the same oid is registered more than once",n->name,name);
115
225
          }
116
510
          wmem_free(wmem_epan_scope(), n->name);
117
510
        }
118
119
765
        n->name = wmem_strdup(wmem_epan_scope(), name);
120
121
765
        if (! n->value_type) {
122
765
          n->value_type = type;
123
765
        }
124
125
765
        return n;
126
765
      }
127
148k
    } else {
128
32.9k
      n = wmem_new(wmem_epan_scope(), oid_info_t);
129
32.9k
      n->subid = subids[i];
130
32.9k
      n->kind = kind;
131
32.9k
      n->children = wmem_tree_new(wmem_epan_scope());
132
32.9k
      n->value_hfid = -2;
133
32.9k
      n->key = key;
134
32.9k
      n->parent = c;
135
32.9k
      n->bits = NULL;
136
137
32.9k
      wmem_tree_insert32(c->children,n->subid,n);
138
139
32.9k
      if (i == oid_len) {
140
25.5k
        n->name = wmem_strdup(wmem_epan_scope(), name);
141
25.5k
        n->value_type = type;
142
25.5k
        n->kind = kind;
143
25.5k
        return n;
144
25.5k
      } else {
145
7.36k
        n->name = NULL;
146
7.36k
        n->value_type = NULL;
147
7.36k
        n->kind = OID_KIND_UNKNOWN;
148
7.36k
      }
149
32.9k
    }
150
155k
    c = n;
151
155k
  } while(++i);
152
153
0
  ws_assert_not_reached();
154
0
  return NULL;
155
26.3k
}
156
157
26.3k
static void oid_subids_debug(const char* name, uint32_t *subids, unsigned len, const char* method) {
158
26.3k
  if (_LOG_DEBUG_ENABLED) {
159
0
    if (ws_log_msg_is_active(LOG_DOMAIN_EPAN, LOG_LEVEL_NOISY)) {
160
0
      char* sub = oid_subid2string(NULL, subids, len);
161
0
      ws_noisy("Oid (from %s): %s %s ", method, name?name:"NULL", sub);
162
0
      wmem_free(NULL, sub);
163
0
    }
164
0
  }
165
26.3k
}
166
167
// NOLINTNEXTLINE(misc-no-recursion)
168
45
void oid_add(const char* name, unsigned oid_len, uint32_t *subids) {
169
45
  ws_assert(subids && *subids <= 2);
170
45
  if (oid_len) {
171
45
    oid_subids_debug(name, subids, oid_len, "subids");
172
45
    add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
173
45
  } else {
174
0
    ws_info("Failed to add Oid: %s (from subids)", name?name:"NULL");
175
0
  }
176
45
}
177
178
26.3k
void oid_add_from_string(const char* name, const char *oid_str) {
179
26.3k
  uint32_t* subids;
180
26.3k
  unsigned oid_len = oid_string2subid(NULL, oid_str, &subids);
181
182
26.3k
  if (oid_len) {
183
26.2k
    oid_subids_debug(name, subids, oid_len, "string");
184
26.2k
    add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
185
26.2k
  } else {
186
30
    ws_info("Failed to add Oid: %s %s ", name?name:"NULL", oid_str?oid_str:NULL);
187
30
  }
188
26.3k
  wmem_free(NULL, subids);
189
26.3k
}
190
191
0
extern void oid_add_from_encoded(const char* name, const uint8_t *oid, int oid_len) {
192
0
  uint32_t* subids = NULL;
193
0
  unsigned subids_len = oid_encoded2subid(NULL, oid, oid_len, &subids);
194
195
0
  if (subids_len) {
196
0
    oid_subids_debug(name, subids, subids_len, "string");
197
0
    add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
198
0
  } else {
199
0
    if (ws_log_msg_is_active(LOG_DOMAIN_EPAN, LOG_LEVEL_INFO)) {
200
0
      char* bytestr = bytes_to_str_punct(NULL, oid, oid_len, ':');
201
0
      ws_info("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len, bytestr);
202
0
      wmem_free(NULL, bytestr);
203
0
    }
204
0
  }
205
0
  wmem_free(NULL, subids);
206
0
}
207
208
#ifdef HAVE_LIBSMI
209
/* de-allocate storage mallocated by libsmi                            */
210
/*                                                                     */
211
/* XXX: libsmi provides access to smiFree as of libsmi v 0.4.8.        */
212
/*      On Windows: Wireshark 1.01 and later is built and distributed  */
213
/*      with libsmi 0.4.8 (or newer).                                  */
214
/*      On non-Windows systems, free() should be OK for libsmi         */
215
/*       versions older than 0.4.8.                                    */
216
217
static void smi_free(void *ptr) {
218
219
#if (SMI_VERSION_MAJOR > 0) || (SMI_VERSION_MINOR > 4) || (SMI_VERSION_PATCHLEVEL >= 8)
220
       smiFree(ptr);
221
#else
222
 #ifdef _WIN32
223
 #error Unsupported Windows libsmi version < 0.4.8
224
 #endif
225
#define xx_free free  /* hack so checkAPIs.pl doesn't complain */
226
       xx_free(ptr);
227
#endif
228
}
229
230
231
typedef struct smi_module_t {
232
  char* name;
233
} smi_module_t;
234
235
static smi_module_t* smi_paths;
236
static unsigned num_smi_paths;
237
static uat_t* smi_paths_uat;
238
239
static smi_module_t* smi_modules;
240
static unsigned num_smi_modules;
241
static uat_t* smi_modules_uat;
242
243
static GString* smi_errors;
244
245
UAT_DIRECTORYNAME_CB_DEF(smi_mod,name,smi_module_t)
246
247
static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
248
    g_string_append_printf(smi_errors,"%s:%d %d %s %s\n",
249
              path ? path : "-",
250
              line, severity,
251
              tag ? tag : "-",
252
              msg ? msg : "");
253
}
254
255
256
static void* smi_mod_copy_cb(void* dest, const void* orig, size_t len _U_) {
257
  const smi_module_t* m = (const smi_module_t*)orig;
258
  smi_module_t* d = (smi_module_t*)dest;
259
260
  d->name = g_strdup(m->name);
261
262
  return d;
263
}
264
265
static void smi_mod_free_cb(void* p) {
266
  smi_module_t* m = (smi_module_t*)p;
267
  g_free(m->name);
268
}
269
270
271
static char* alnumerize(const char* name) {
272
  char* s = g_strdup(name);
273
  char* r = s;
274
  char* w = r;
275
  char c;
276
277
  for (;(c = *r); r++) {
278
    if (g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.') {
279
      *(w++) = c;
280
    } else if (c == ':' && r[1] == ':') {
281
      *(w++) = '.';
282
    }
283
  }
284
285
  *w = '\0';
286
287
  return s;
288
}
289
290
static const oid_value_type_t* get_typedata(SmiType* smiType) {
291
  /*
292
   * There has to be a better way to know if a given
293
   * OCTETSTRING type is actually human readable text,
294
   * an address of some type or some moe specific FT_
295
   * Until that is found, this is the mapping between
296
   * SNMP Types and our FT_s
297
   */
298
  static const struct _type_mapping_t {
299
    const char* name;
300
    SmiBasetype base;
301
    const oid_value_type_t* type;
302
  } types[] =  {
303
    {"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
304
    {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
305
    {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
306
    {"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
307
    {"MacAddress",SMI_BASETYPE_UNKNOWN,&ether_type},
308
    {"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
309
    {"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
310
    {"TimeStamp",SMI_BASETYPE_UNKNOWN,&timeticks_type},
311
    {"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
312
    {"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
313
    {"DateAndTime",SMI_BASETYPE_UNKNOWN,&date_and_time_type},
314
    {"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
315
    {"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
316
    {"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
317
    {"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
318
    {"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
319
    {"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
320
    {"i32",SMI_BASETYPE_INTEGER32,&integer_type},
321
    {"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
322
    {"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
323
    {"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
324
    {"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
325
    {"f32",SMI_BASETYPE_FLOAT32,&float_type},
326
    {"f64",SMI_BASETYPE_FLOAT64,&double_type},
327
    {"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
328
    {"enum",SMI_BASETYPE_ENUM,&integer_type},
329
    {"bits",SMI_BASETYPE_BITS,&bytes_type},
330
    {"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
331
    {NULL,SMI_BASETYPE_UNKNOWN,NULL} /* SMI_BASETYPE_UNKNOWN = 0 */
332
  };
333
  const struct _type_mapping_t* t;
334
  SmiType* sT = smiType;
335
336
  if (!smiType) return NULL;
337
338
  do {
339
    for (t = types; t->type ; t++ ) {
340
      char* name = smiRenderType(sT, SMI_RENDER_NAME);
341
      if (name && t->name && g_str_equal(name, t->name )) {
342
        smi_free(name);
343
        return t->type;
344
      }
345
      if (name) {
346
        smi_free (name);
347
      }
348
    }
349
  } while(( sT  = smiGetParentType(sT) ));
350
351
  for (t = types; t->type ; t++ ) {
352
    if(smiType->basetype == t->base) {
353
      return t->type;
354
    }
355
  }
356
357
  return &unknown_type;
358
}
359
360
static unsigned get_non_implicit_size(SmiType* sT) {
361
  SmiRange *sR;
362
  unsigned size = 0xffffffff;
363
364
  switch (sT->basetype) {
365
    case SMI_BASETYPE_OCTETSTRING:
366
    case SMI_BASETYPE_OBJECTIDENTIFIER:
367
      break;
368
    default:
369
      return 0;
370
  }
371
372
  for ( ; sT; sT = smiGetParentType(sT) ) {
373
    for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
374
      if (size == 0xffffffff) {
375
        if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
376
          size = (uint32_t)sR->minValue.value.unsigned32;
377
        } else {
378
          return 0;
379
        }
380
      } else {
381
        if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
382
          return 0;
383
        }
384
      }
385
    }
386
  }
387
388
  return size == 0xffffffff ? 0 : size;
389
}
390
391
392
static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
393
  *key_p = NULL;
394
395
  switch(sN->nodekind) {
396
    case SMI_NODEKIND_ROW: {
397
      SmiElement* sE;
398
      oid_key_t* kl = NULL; /* points to last element in the list of oid_key_t's */
399
      const oid_value_type_t* typedata = NULL;
400
      bool implied;
401
402
      switch (sN->indexkind) {
403
        case SMI_INDEX_INDEX:
404
          break;
405
        case SMI_INDEX_AUGMENT:
406
        case SMI_INDEX_REORDER:
407
        case SMI_INDEX_SPARSE:
408
        case SMI_INDEX_EXPAND:
409
          sN = smiGetRelatedNode(sN);
410
          break;
411
        case SMI_INDEX_UNKNOWN:
412
          return OID_KIND_UNKNOWN;
413
      };
414
415
      implied = sN->implied;
416
417
      for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
418
        SmiNode* elNode =  smiGetElementNode(sE) ;
419
        SmiType* elType = smiGetNodeType(elNode);
420
        oid_key_t* k;
421
        unsigned non_implicit_size = 0;
422
        char *oid1, *oid2;
423
424
        if (elType) {
425
          non_implicit_size = get_non_implicit_size(elType);
426
        }
427
428
        typedata =  get_typedata(elType);
429
430
        k = g_new(oid_key_t,1);
431
432
        oid1 = smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED);
433
        oid2 = smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME);
434
        k->name = g_strconcat(oid1, ".", oid2, NULL);
435
        smi_free (oid1);
436
        smi_free (oid2);
437
438
        k->hfid = -2;
439
        k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
440
        k->display = typedata ? typedata->display : BASE_NONE;
441
        k->next = NULL;
442
443
444
        if (typedata) {
445
          k->key_type = typedata->keytype;
446
          k->num_subids = typedata->keysize;
447
        } else {
448
          if (elType) {
449
            switch (elType->basetype) {
450
              case SMI_BASETYPE_BITS:
451
              case SMI_BASETYPE_OCTETSTRING: {
452
                k->key_type = OID_KEY_TYPE_BYTES;
453
                k->num_subids = non_implicit_size;
454
                break;
455
              }
456
              case SMI_BASETYPE_ENUM:
457
              case SMI_BASETYPE_OBJECTIDENTIFIER:
458
              case SMI_BASETYPE_INTEGER32:
459
              case SMI_BASETYPE_UNSIGNED32:
460
              case SMI_BASETYPE_INTEGER64:
461
              case SMI_BASETYPE_UNSIGNED64:
462
                k->key_type = OID_KEY_TYPE_INTEGER;
463
                k->num_subids = 1;
464
                break;
465
              default:
466
                k->key_type = OID_KEY_TYPE_WRONG;
467
                k->num_subids = 0;
468
                break;
469
            }
470
          } else {
471
            k->key_type = OID_KEY_TYPE_WRONG;
472
            k->num_subids = 0;
473
          }
474
        }
475
476
        if (!kl) {
477
          /*
478
           * The list is empty, so set the
479
           * pointer to the head of the list
480
           * to point to this entry.
481
           */
482
          *key_p = k;
483
        } else {
484
          /*
485
           * The list is non-empty, and kl
486
           * points to its last element.
487
           * Make the last element point to
488
           * this entry as its successor.
489
           */
490
          kl->next = k;
491
        }
492
493
        /*
494
         * This entry is now the last entry in
495
         * the list.
496
         */
497
        kl = k;
498
      }
499
500
      if (implied && kl) {
501
        switch (kl->key_type) {
502
          case OID_KEY_TYPE_BYTES:  kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
503
          case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
504
          case OID_KEY_TYPE_OID:    kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
505
          default: break;
506
        }
507
      }
508
509
      return OID_KIND_ROW;
510
    }
511
    case SMI_NODEKIND_NODE: return OID_KIND_NODE;
512
    case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
513
    case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
514
    case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
515
    case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
516
    case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
517
    case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
518
    case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
519
    default: return OID_KIND_UNKNOWN;
520
  }
521
}
522
523
#define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
524
               || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
525
               || (ft == FT_UINT64) || (ft == FT_INT64) )
526
527
static void unregister_mibs(void) {
528
  /* TODO: Unregister "MIBs" proto and clean up field array and subtree array.
529
   * Wireshark does not support that yet. :-( */
530
531
  /* smiExit(); */
532
}
533
534
static void restart_needed_warning(void) {
535
  if (oids_init_done)
536
    report_failure("Wireshark needs to be restarted for these changes to take effect");
537
}
538
539
static void register_mibs(const char* app_env_var_prefix) {
540
  SmiModule *smiModule;
541
  SmiNode *smiNode;
542
  unsigned i;
543
  int proto_mibs = -1;
544
  wmem_array_t* hfa;
545
  GArray* etta;
546
  char* path_str;
547
  int ret;
548
549
  if (!load_smi_modules) {
550
    ws_info("OID resolution not enabled");
551
    return;
552
  }
553
554
  /* TODO: Remove this workaround when unregistration of "MIBs" proto is solved.
555
   * Wireshark does not support that yet. :-( */
556
  if (oids_init_done) {
557
    ws_info("Exiting register_mibs() to avoid double registration of MIBs proto.");
558
    return;
559
  }
560
561
  hfa = wmem_array_sized_new(wmem_epan_scope(), sizeof(hf_register_info), 1024); /* oids 631 */
562
  etta = g_array_new(false,true,sizeof(int*));
563
564
  smiInit("wireshark");
565
  smi_init_done = true;
566
567
  smi_errors = g_string_new("");
568
  smiSetErrorHandler(smi_error_handler);
569
570
  path_str = oid_get_default_mib_path(app_env_var_prefix);
571
  ws_info("SMI Path: '%s'",path_str);
572
573
  ret = smiSetPath(path_str);
574
  if (ret < 0) {
575
    if (!suppress_smi_errors) {
576
      report_failure("Failed to set SMI path to '%s'", path_str);
577
    }
578
    ws_info("Failed to set SMI path to '%s'", path_str);
579
  }
580
581
  for(i=0;i<num_smi_modules;i++) {
582
    if (!smi_modules[i].name) continue;
583
584
    if (smiIsLoaded(smi_modules[i].name)) {
585
      continue;
586
    } else {
587
      char* mod_name =  smiLoadModule(smi_modules[i].name);
588
      if (mod_name)
589
        ws_debug("Loaded: '%s'[%u] as %s", smi_modules[i].name, i, mod_name);
590
      else
591
        ws_info("Failed to load: '%s'[%u]", smi_modules[i].name, i);
592
    }
593
  }
594
595
  if (smi_errors->len) {
596
    if (!suppress_smi_errors) {
597
      report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
598
             "The Current Path is: %s\n\nYou can avoid this error message "
599
             "by removing the missing MIB modules at Edit -> Preferences"
600
             " -> Name Resolution -> SMI (MIB and PIB) modules or by "
601
             "installing them.\n", smi_errors->str, path_str);
602
    }
603
    ws_info("Errors while loading:\n%s", smi_errors->str);
604
  }
605
606
  g_free(path_str);
607
  g_string_free(smi_errors,TRUE);
608
609
  for (smiModule = smiGetFirstModule();
610
     smiModule;
611
     smiModule = smiGetNextModule(smiModule)) {
612
613
    ws_debug("Module: %s", smiModule->name);
614
615
    /* TODO: Check libsmi version at compile time and disable this
616
     * workaround for libsmi versions where this problem is fixed.
617
     * Currently there is no such version. :-(
618
     */
619
    if (smiModule->conformance == 1) {
620
      if (!suppress_smi_errors) {
621
        report_failure("Stopped processing module %s due to "
622
          "error(s) to prevent potential crash in libsmi.\n"
623
          "Module's conformance level: %d.\n"
624
          "See details at: https://bugs.debian.org/560325\n",
625
           smiModule->name, smiModule->conformance);
626
      }
627
      continue;
628
    }
629
    for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
630
       smiNode;
631
       smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
632
633
      SmiType* smiType =  smiGetNodeType(smiNode);
634
      const oid_value_type_t* typedata =  get_typedata(smiType);
635
      oid_key_t* key;
636
      oid_kind_t kind = smikind(smiNode,&key);
637
      char *oid = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED);
638
      oid_info_t* oid_data = add_oid(oid,
639
                   kind,
640
                   typedata,
641
                   key,
642
                   smiNode->oidlen,
643
                   smiNode->oid);
644
      smi_free (oid);
645
646
      if (ws_log_msg_is_active(LOG_DOMAIN_EPAN, LOG_LEVEL_NOISY)) {
647
        char *sub;
648
        sub = oid_subid2string(NULL, smiNode->oid, smiNode->oidlen);
649
        ws_noisy("Node: kind=%d oid=%s name=%s ",
650
           oid_data->kind, sub, oid_data->name);
651
        wmem_free(NULL, sub);
652
      }
653
654
      if ( typedata && oid_data->value_hfid == -2 ) {
655
        SmiNamedNumber* smiEnum;
656
        hf_register_info hf;
657
        char *name;
658
        char *blurb;
659
660
        name = g_strdup(oid_data->name);
661
        blurb = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL);
662
        /* Don't allow duplicate blurb/name */
663
        if (strcmp(blurb, name) == 0) {
664
          smi_free(blurb);
665
          blurb = NULL;
666
        }
667
668
        hf.p_id                     = &(oid_data->value_hfid);
669
        hf.hfinfo.name              = name;
670
        hf.hfinfo.abbrev            = alnumerize(oid_data->name);
671
        hf.hfinfo.type              = typedata->ft_type;
672
        hf.hfinfo.display           = typedata->display;
673
        hf.hfinfo.strings           = NULL;
674
        hf.hfinfo.bitmask           = 0;
675
        hf.hfinfo.blurb             = blurb;
676
        /* HFILL */
677
        HFILL_INIT(hf);
678
679
        oid_data->value_hfid = -1;
680
681
        if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
682
          GArray* vals = g_array_sized_new(true,true,sizeof(value_string), 16);
683
684
          for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
685
            if (smiEnum->name) {
686
              value_string val;
687
              val.value  = (uint32_t)smiEnum->value.value.integer32;
688
              val.strptr = g_strdup(smiEnum->name);
689
              g_array_append_val(vals,val);
690
            }
691
          }
692
693
          hf.hfinfo.strings = g_array_free(vals, false);
694
        }
695
#if 0 /* packet-snmp does not handle bits yet */
696
      } else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
697
        unsigned n = 0;
698
        oid_bits_info_t* bits = g_new(oid_bits_info_t, 1);
699
        int* ettp = &(bits->ett);
700
701
        bits->num = 0;
702
        bits->ett = -1;
703
704
        g_array_append_val(etta,ettp);
705
706
        for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
707
708
        bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
709
710
        for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
711
          smiEnum;
712
          smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
713
          unsigned mask = 1 << (smiEnum->value.value.integer32 % 8);
714
          char* base = alnumerize(oid_data->name);
715
          char* ext = alnumerize(smiEnum->name);
716
          hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, NULL, HFILL }};
717
718
          bits->data[n].hfid = -1;
719
          bits->data[n].offset = smiEnum->value.value.integer32 / 8;
720
721
          hf2.hfinfo.name = g_strconcat("%s:%s",oid_data->name, ":", smiEnum->name, NULL);
722
          hf2.hfinfo.abbrev = g_strconcat(base, ".", ext, NULL);
723
724
          g_free(base);
725
          g_free(ext);
726
          g_array_append_val(hfa,hf2);
727
        }
728
#endif /* packet-snmp does not use this yet */
729
        wmem_array_append_one(hfa,hf);
730
      }
731
732
      if ((key = oid_data->key)) {
733
        for(; key; key = key->next) {
734
          ws_noisy("Index: name=%s subids=%u key_type=%d",
735
             key->name, key->num_subids, key->key_type);
736
737
          if (key->hfid == -2) {
738
            hf_register_info hf;
739
740
            hf.p_id                     = &(key->hfid);
741
            hf.hfinfo.name              = key->name;
742
            hf.hfinfo.abbrev            = alnumerize(key->name);
743
            hf.hfinfo.type              = key->ft_type;
744
            hf.hfinfo.display           = key->display;
745
            hf.hfinfo.strings           = NULL;
746
            hf.hfinfo.bitmask           = 0;
747
            hf.hfinfo.blurb             = NULL;
748
            /* HFILL */
749
            HFILL_INIT(hf);
750
751
            wmem_array_append_one(hfa,hf);
752
            key->hfid = -1;
753
          }
754
        }
755
      }
756
    }
757
  }
758
759
  proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
760
761
  proto_register_field_array(proto_mibs, (hf_register_info*)wmem_array_get_raw(hfa), wmem_array_get_count(hfa));
762
  proto_register_subtree_array((int**)(void*)etta->data, etta->len);
763
764
  g_array_free(etta,true);
765
766
  oids_init_done = true;
767
}
768
#endif
769
770
void oid_pref_init(module_t *nameres)
771
15
{
772
#ifdef HAVE_LIBSMI
773
  static uat_field_t smi_fields[] = {
774
    UAT_FLD_CSTRING(smi_mod,name,"Module name","The module's name"),
775
    UAT_END_FIELDS
776
  };
777
  static uat_field_t smi_paths_fields[] = {
778
    UAT_FLD_DIRECTORYNAME(smi_mod,name,"Directory path","The directory name"),
779
    UAT_END_FIELDS
780
  };
781
782
    prefs_register_bool_preference(nameres, "load_smi_modules",
783
                                  "Enable OID resolution",
784
                                  "Resolve Object IDs to object names from the MIB and PIB"
785
                                  " modules defined below."
786
                                  " You must restart Wireshark for this change to take effect",
787
                                  &load_smi_modules);
788
789
    prefs_register_bool_preference(nameres, "suppress_smi_errors",
790
                                  "Suppress SMI errors",
791
                                  "While loading MIB or PIB modules errors may be detected,"
792
                                  " which are reported. Some errors can be ignored."
793
                                  " If unsure, set to false.",
794
                                  &suppress_smi_errors);
795
796
    smi_paths_uat = uat_new("SMI Paths",
797
                            sizeof(smi_module_t),
798
                            "smi_paths",
799
                            false,
800
                            (void**)&smi_paths,
801
                            &num_smi_paths,
802
    /* affects dissection of packets (as the MIBs and PIBs affect the
803
       interpretation of e.g. SNMP variable bindings), but not set of
804
       named fields
805
806
       XXX - if named fields are generated from the MIBs and PIBs
807
       for particular variable bindings, this *does* affect the set
808
       of named fields! */
809
                            UAT_AFFECTS_DISSECTION,
810
                            "ChSNMPSMIPaths",
811
                            smi_mod_copy_cb,
812
                            NULL,
813
                            smi_mod_free_cb,
814
                            restart_needed_warning,
815
                            NULL,
816
                            smi_paths_fields);
817
818
    prefs_register_uat_preference(nameres,
819
                                  "smi_paths",
820
                                  "SMI (MIB and PIB) paths",
821
                                  "Search paths for SMI (MIB and PIB) modules (recursively). You must"
822
                                  " restart Wireshark for these changes to take effect.",
823
                                  smi_paths_uat);
824
825
    smi_modules_uat = uat_new("SMI Modules",
826
                              sizeof(smi_module_t),
827
                              "smi_modules",
828
                              false,
829
                              (void**)&smi_modules,
830
                              &num_smi_modules,
831
    /* affects dissection of packets (as the MIBs and PIBs affect the
832
       interpretation of e.g. SNMP variable bindings), but not set of
833
       named fields
834
835
       XXX - if named fields are generated from the MIBs and PIBs
836
       for particular variable bindings, would this affect the set
837
       of named fields? */
838
                              UAT_AFFECTS_DISSECTION,
839
                              "ChSNMPSMIModules",
840
                              smi_mod_copy_cb,
841
                              NULL,
842
                              smi_mod_free_cb,
843
                              restart_needed_warning,
844
                              NULL,
845
                              smi_fields);
846
847
    prefs_register_uat_preference(nameres,
848
                                  "smi_modules",
849
                                  "SMI (MIB and PIB) modules",
850
                                  "List of SMI (MIB and PIB) modules to load. You must"
851
                                  " restart Wireshark for these changes to take effect.",
852
                                  smi_modules_uat);
853
854
#else
855
15
    prefs_register_static_text_preference(nameres, "load_smi_modules_static",
856
15
                            "Enable OID resolution: N/A",
857
15
                            "Support for OID resolution was not compiled into this version of Wireshark");
858
859
15
    prefs_register_static_text_preference(nameres, "suppress_smi_errors_static",
860
15
                            "Suppress SMI errors: N/A",
861
15
                            "Support for OID resolution was not compiled into this version of Wireshark");
862
863
15
    prefs_register_static_text_preference(nameres, "smi_module_path",
864
15
                            "SMI (MIB and PIB) modules and paths: N/A",
865
15
                            "Support for OID resolution was not compiled into this version of Wireshark");
866
15
#endif
867
15
}
868
869
15
void oids_init(const char* app_env_var_prefix _U_) {
870
15
  prepopulate_oids();
871
#ifdef HAVE_LIBSMI
872
  register_mibs(app_env_var_prefix);
873
#else
874
15
  ws_info("libsmi disabled oid resolution not enabled");
875
15
#endif
876
15
}
877
878
15
void oids_cleanup(void) {
879
#ifdef HAVE_LIBSMI
880
  unregister_mibs();
881
#else
882
15
  ws_info("libsmi disabled oid resolution not enabled");
883
15
#endif
884
15
}
885
886
3.40k
char* oid_subid2string(wmem_allocator_t *scope, uint32_t* subids, unsigned len) {
887
3.40k
  return rel_oid_subid2string(scope, subids, len, true);
888
3.40k
}
889
3.40k
char* rel_oid_subid2string(wmem_allocator_t *scope, uint32_t* subids, unsigned len, bool is_absolute) {
890
891
3.40k
  wmem_strbuf_t *oid_str;
892
3.40k
  size_t oid_str_len;
893
894
3.40k
  if(!subids || len == 0)
895
0
    return wmem_strdup(scope, "*** Empty OID ***");
896
897
3.40k
  oid_str = wmem_strbuf_new(scope, "");
898
899
3.40k
  if (!is_absolute)
900
0
    wmem_strbuf_append_c(oid_str, '.');
901
902
25.8k
  do {
903
25.8k
    wmem_strbuf_append_printf(oid_str, "%u.",*subids++);
904
25.8k
  } while(--len);
905
906
  /* Remove trailing "." (which is guaranteed to be there) */
907
3.40k
  oid_str_len = wmem_strbuf_get_len(oid_str);
908
3.40k
  wmem_strbuf_truncate(oid_str, oid_str_len - 1);
909
910
3.40k
  return wmem_strbuf_finalize(oid_str);
911
3.40k
}
912
913
/* If a valid OID string, return number of numbers */
914
26.3k
static unsigned check_num_oid(const char* str) {
915
26.3k
  const char* r = str;
916
26.3k
  char c = '.';
917
26.3k
  unsigned n = 0;
918
919
26.3k
  ws_noisy("check_num_oid: '%s'",str);
920
26.3k
  if (!r) return 0;
921
922
458k
  do {
923
458k
    switch(*r) {
924
182k
      case '.': case '\0':
925
182k
        n++;
926
182k
        if (c == '.') return 0;
927
182k
        break;
928
189k
      case '1' : case '2' : case '3' : case '4' : case '5' :
929
276k
      case '6' : case '7' : case '8' : case '9' : case '0' :
930
276k
        continue;
931
33
      default:
932
33
        return 0;
933
458k
    }
934
458k
  } while((c = *r++));
935
936
26.2k
  return n;
937
26.3k
}
938
939
/* Set subids_p to an array of found numbers, return number of numbers */
940
26.3k
unsigned oid_string2subid(wmem_allocator_t *scope, const char* str, uint32_t** subids_p) {
941
26.3k
  const char* r = str;
942
26.3k
  uint32_t* subids;
943
26.3k
  uint32_t* subids_overflow;
944
26.3k
  unsigned n = check_num_oid(str);
945
  /*
946
   * we cannot handle sub-ids greater than 32bytes
947
   * keep a pilot subid of 64 bytes to check the limit
948
   */
949
26.3k
  uint64_t subid = 0;
950
951
26.3k
  ws_noisy("oid_string2subid: str='%s'",str);
952
953
26.3k
  if (!n) {
954
40
    *subids_p = NULL;
955
40
    return 0;
956
40
  }
957
958
26.2k
  *subids_p = subids = wmem_alloc0_array(scope, uint32_t, n);
959
26.2k
  subids_overflow = subids + n;
960
458k
  do switch(*r) {
961
155k
    case '.':
962
155k
      subid = 0;
963
155k
      subids++;
964
155k
      continue;
965
189k
    case '1' : case '2' : case '3' : case '4' : case '5' :
966
276k
    case '6' : case '7' : case '8' : case '9' : case '0' :
967
276k
      subid *= 10;
968
276k
      subid += *r - '0';
969
970
276k
      if( subids >= subids_overflow ||  subid > 0xffffffff) {
971
0
        wmem_free(scope, *subids_p);
972
0
        *subids_p=NULL;
973
0
        return 0;
974
0
      }
975
976
276k
      *(subids) *= 10;
977
276k
      *(subids) += *r - '0';
978
276k
      continue;
979
26.2k
    case '\0':
980
26.2k
      break;
981
0
    default:
982
0
      return 0;
983
458k
  } while(*r++);
984
985
26.2k
  return n;
986
26.2k
}
987
988
989
4.83k
unsigned oid_encoded2subid(wmem_allocator_t *scope, const uint8_t *oid_bytes, int oid_len, uint32_t** subids_p) {
990
4.83k
  return oid_encoded2subid_sub(scope, oid_bytes, oid_len, subids_p, true);
991
4.83k
}
992
unsigned oid_encoded2subid_sub(wmem_allocator_t *scope, const uint8_t *oid_bytes, int oid_len, uint32_t** subids_p,
993
4.83k
    bool is_first) {
994
4.83k
  int i;
995
4.83k
  unsigned n = is_first ? 1 : 0;
996
4.83k
  uint32_t* subids;
997
4.83k
  uint32_t* subid_overflow;
998
  /*
999
   * we cannot handle sub-ids greater than 32bytes
1000
   * have the subid in 64 bytes to be able to check the limit
1001
   */
1002
4.83k
  uint64_t subid = 0;
1003
1004
41.5k
  for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
1005
1006
4.83k
  *subids_p = subids = (uint32_t *)wmem_alloc(scope, sizeof(uint32_t)*n);
1007
4.83k
  subid_overflow = subids+n;
1008
1009
  /* If n is 0 or 1 (depending on how it was initialized) then we found
1010
   * no bytes in the OID with first bit cleared, so initialize our one
1011
   * byte (if any) to zero and return. This *seems* to be the right thing
1012
   * to do in this situation, and at the very least it avoids
1013
   * uninitialized memory errors that would otherwise occur. */
1014
4.83k
  if (is_first && n == 1) {
1015
35
    *subids = 0;
1016
35
    return n;
1017
35
  }
1018
4.80k
  else if (!is_first && n == 0) {
1019
0
    return n;
1020
0
  }
1021
1022
39.0k
  for (i=0; i<oid_len; i++){
1023
34.4k
    uint8_t byte = oid_bytes[i];
1024
1025
34.4k
    subid <<= 7;
1026
34.4k
    subid |= byte & 0x7F;
1027
1028
34.4k
    if (byte & 0x80) {
1029
3.40k
      continue;
1030
3.40k
    }
1031
1032
31.0k
    if (is_first) {
1033
4.80k
      uint32_t subid0 = 0;
1034
1035
4.80k
      if (subid >= 40) { subid0++; subid-=40; }
1036
4.80k
      if (subid >= 40) { subid0++; subid-=40; }
1037
1038
4.80k
      *subids++ = subid0;
1039
1040
4.80k
      is_first = false;
1041
4.80k
    }
1042
1043
31.0k
    if( subids >= subid_overflow || subid > 0xffffffff) {
1044
      /* scope may be NULL in which case we must free our
1045
       * useless buffer before returning */
1046
242
      wmem_free(scope, *subids_p);
1047
242
      *subids_p = NULL;
1048
242
      return 0;
1049
242
    }
1050
1051
30.8k
    *subids++ = (uint32_t)subid;
1052
30.8k
    subid = 0;
1053
30.8k
  }
1054
1055
4.55k
  ws_assert(subids == subid_overflow);
1056
1057
4.55k
  return n;
1058
4.80k
}
1059
1060
1.46k
oid_info_t* oid_get(unsigned len, uint32_t* subids, unsigned* matched, unsigned* left) {
1061
1.46k
  oid_info_t* curr_oid = &oid_root;
1062
1.46k
  unsigned i;
1063
1064
1.46k
  if(!(subids && *subids <= 2)) {
1065
0
    *matched = 0;
1066
0
    *left = len;
1067
0
    return curr_oid;
1068
0
  }
1069
1070
10.9k
  for( i=0; i < len; i++) {
1071
9.61k
    oid_info_t* next_oid = (oid_info_t *)wmem_tree_lookup32(curr_oid->children,subids[i]);
1072
9.61k
    if (next_oid) {
1073
9.49k
      curr_oid = next_oid;
1074
9.49k
    } else {
1075
117
      goto done;
1076
117
    }
1077
9.61k
  }
1078
1.46k
done:
1079
1.46k
  *matched = i;
1080
1.46k
  *left = len - i;
1081
1.46k
  return curr_oid;
1082
1.46k
}
1083
1084
1085
0
oid_info_t* oid_get_from_encoded(wmem_allocator_t *scope, const uint8_t *bytes, int byteslen, uint32_t** subids_p, unsigned* matched_p, unsigned* left_p) {
1086
0
  unsigned subids_len = oid_encoded2subid(scope, bytes, byteslen, subids_p);
1087
0
  return oid_get(subids_len, *subids_p, matched_p, left_p);
1088
0
}
1089
1090
0
oid_info_t* oid_get_from_string(wmem_allocator_t *scope, const char *oid_str, uint32_t** subids_p, unsigned* matched, unsigned* left) {
1091
0
  unsigned subids_len = oid_string2subid(scope, oid_str, subids_p);
1092
0
  return oid_get(subids_len, *subids_p, matched, left);
1093
0
}
1094
1095
1.51k
char *oid_resolved_from_encoded(wmem_allocator_t *scope, const uint8_t *oid, int oid_len) {
1096
1.51k
  uint32_t *subid_oid = NULL;
1097
1.51k
  char * ret;
1098
1.51k
  unsigned subid_oid_length = oid_encoded2subid(NULL, oid, oid_len, &subid_oid);
1099
1100
1.51k
  ret = oid_resolved(scope, subid_oid_length, subid_oid);
1101
1.51k
  wmem_free(NULL, subid_oid);
1102
1.51k
  return ret;
1103
1.51k
}
1104
1105
0
char *rel_oid_resolved_from_encoded(wmem_allocator_t *scope, const uint8_t *oid, int oid_len) {
1106
0
  uint32_t *subid_oid = NULL;
1107
0
  char* ret;
1108
0
  unsigned subid_oid_length = oid_encoded2subid_sub(NULL, oid, oid_len, &subid_oid, false);
1109
1110
0
  ret = rel_oid_subid2string(scope, subid_oid, subid_oid_length, false);
1111
0
  wmem_free(NULL, subid_oid);
1112
0
  return ret;
1113
0
}
1114
1115
1116
0
unsigned oid_subid2encoded(wmem_allocator_t *scope, unsigned subids_len, uint32_t* subids, uint8_t** bytes_p) {
1117
0
  unsigned bytelen = 0;
1118
0
  unsigned i;
1119
0
  uint32_t subid;
1120
0
  uint8_t* b;
1121
1122
0
  if ( !subids || subids_len <= 1) {
1123
0
    *bytes_p = NULL;
1124
0
    return 0;
1125
0
  }
1126
1127
0
  for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1128
0
    subid += subids[i];
1129
0
    if (subid <= 0x0000007F) {
1130
0
      bytelen += 1;
1131
0
    } else if (subid <= 0x00003FFF ) {
1132
0
      bytelen += 2;
1133
0
    } else if (subid <= 0x001FFFFF ) {
1134
0
      bytelen += 3;
1135
0
    } else if (subid <= 0x0FFFFFFF ) {
1136
0
      bytelen += 4;
1137
0
    } else {
1138
0
      bytelen += 5;
1139
0
    }
1140
0
  }
1141
1142
0
  *bytes_p = b = (uint8_t *)wmem_alloc(scope, bytelen);
1143
1144
0
  for (subid=subids[0] * 40, i = 1; i<subids_len; i++, subid=0) {
1145
0
    unsigned len;
1146
1147
0
    subid += subids[i];
1148
0
    if ((subid <= 0x0000007F )) len = 1;
1149
0
    else if ((subid <= 0x00003FFF )) len = 2;
1150
0
    else if ((subid <= 0x001FFFFF )) len = 3;
1151
0
    else if ((subid <= 0x0FFFFFFF )) len = 4;
1152
0
    else len = 5;
1153
1154
0
    switch(len) {
1155
0
      default: *bytes_p=NULL; return 0;
1156
0
      case 5: *(b++) = ((subid & 0xF0000000) >> 28) | 0x80;
1157
      /* FALL THROUGH */
1158
0
      case 4: *(b++) = ((subid & 0x0FE00000) >> 21) | 0x80;
1159
      /* FALL THROUGH */
1160
0
      case 3: *(b++) = ((subid & 0x001FC000) >> 14) | 0x80;
1161
      /* FALL THROUGH */
1162
0
      case 2: *(b++) = ((subid & 0x00003F80) >> 7)  | 0x80;
1163
      /* FALL THROUGH */
1164
0
      case 1: *(b++) =   subid & 0x0000007F ; break;
1165
0
    }
1166
0
  }
1167
1168
0
  return bytelen;
1169
0
}
1170
1171
3.32k
char* oid_encoded2string(wmem_allocator_t *scope, const uint8_t* encoded, unsigned len) {
1172
3.32k
  uint32_t* subids = NULL;
1173
3.32k
  char* ret;
1174
3.32k
  unsigned subids_len = oid_encoded2subid(NULL, encoded, len, &subids);
1175
1176
3.32k
  if (subids_len) {
1177
3.14k
    ret = oid_subid2string(scope, subids,subids_len);
1178
3.14k
  } else {
1179
174
    ret = wmem_strdup(scope, "");
1180
174
  }
1181
1182
3.32k
  wmem_free(NULL, subids);
1183
3.32k
  return ret;
1184
3.32k
}
1185
1186
0
char* rel_oid_encoded2string(wmem_allocator_t *scope, const uint8_t* encoded, unsigned len) {
1187
0
  uint32_t* subids = NULL;
1188
0
  char* ret;
1189
0
  unsigned subids_len = oid_encoded2subid_sub(NULL, encoded, len, &subids, false);
1190
1191
0
  if (subids_len) {
1192
0
    ret = rel_oid_subid2string(scope, subids,subids_len, false);
1193
0
  } else {
1194
0
    ret = wmem_strdup(scope, "");
1195
0
  }
1196
1197
0
  wmem_free(NULL, subids);
1198
0
  return ret;
1199
0
}
1200
1201
0
unsigned oid_string2encoded(wmem_allocator_t *scope, const char *oid_str, uint8_t **bytes) {
1202
0
  uint32_t* subids;
1203
0
  uint32_t subids_len;
1204
0
  unsigned byteslen;
1205
1206
0
  if ( (subids_len = oid_string2subid(NULL, oid_str, &subids)) &&
1207
0
       (byteslen   = oid_subid2encoded(scope, subids_len, subids, bytes)) ) {
1208
0
    wmem_free(NULL, subids);
1209
0
    return byteslen;
1210
0
  }
1211
0
  wmem_free(NULL, subids);
1212
0
  return 0;
1213
0
}
1214
1215
24
char *oid_resolved_from_string(wmem_allocator_t *scope, const char *oid_str) {
1216
24
  uint32_t    *subid_oid;
1217
24
  unsigned     subid_oid_length;
1218
24
  char *resolved;
1219
1220
24
  subid_oid_length = oid_string2subid(NULL, oid_str, &subid_oid);
1221
24
  resolved         = oid_resolved(scope, subid_oid_length, subid_oid);
1222
1223
24
  wmem_free(NULL, subid_oid);
1224
1225
24
  return resolved;
1226
24
}
1227
1228
1.53k
char *oid_resolved(wmem_allocator_t *scope, uint32_t num_subids, uint32_t* subids) {
1229
1.53k
  unsigned matched;
1230
1.53k
  unsigned left;
1231
1.53k
  oid_info_t* oid;
1232
1233
1.53k
  if(! (subids && *subids <= 2 ))
1234
78
    return wmem_strdup(scope, "*** Malformed OID ***");
1235
1236
1.46k
  oid = oid_get(num_subids, subids, &matched, &left);
1237
1238
1.53k
  while (! oid->name ) {
1239
71
    if (!(oid = oid->parent)) {
1240
0
      return oid_subid2string(scope, subids,num_subids);
1241
0
    }
1242
71
    left++;
1243
71
    matched--;
1244
71
  }
1245
1246
1.46k
  if (left) {
1247
126
    char *ret,
1248
126
        *str1 = oid_subid2string(NULL, subids,matched),
1249
126
        *str2 = oid_subid2string(NULL, &(subids[matched]),left);
1250
1251
126
    ret = wmem_strconcat(scope, oid->name ? oid->name : str1, ".", str2, NULL);
1252
126
    wmem_free(NULL, str1);
1253
126
    wmem_free(NULL, str2);
1254
126
    return ret;
1255
1.33k
  } else {
1256
1.33k
    return oid->name ? wmem_strdup(scope, oid->name) : oid_subid2string(scope, subids,matched);
1257
1.33k
  }
1258
1.46k
}
1259
1260
0
extern void oid_both(wmem_allocator_t *scope, unsigned oid_len, uint32_t *subids, char** resolved_p, char** numeric_p) {
1261
0
  *resolved_p = oid_resolved(scope, oid_len,subids);
1262
0
  *numeric_p = oid_subid2string(scope, subids,oid_len);
1263
0
}
1264
1265
0
extern void oid_both_from_encoded(wmem_allocator_t *scope, const uint8_t *oid, int oid_len, char** resolved_p, char** numeric_p) {
1266
0
  uint32_t* subids = NULL;
1267
0
  unsigned subids_len = oid_encoded2subid(NULL, oid, oid_len, &subids);
1268
0
  *resolved_p = oid_resolved(scope, subids_len,subids);
1269
0
  *numeric_p = oid_subid2string(scope, subids,subids_len);
1270
0
  wmem_free(NULL, subids);
1271
0
}
1272
1273
0
void oid_both_from_string(wmem_allocator_t *scope, const char *oid_str, char** resolved_p, char** numeric_p) {
1274
0
  uint32_t *subids;
1275
0
  unsigned subids_len;
1276
1277
0
  subids_len  = oid_string2subid(NULL, oid_str, &subids);
1278
0
  *resolved_p = oid_resolved(scope, subids_len,subids);
1279
0
  *numeric_p  = oid_subid2string(scope, subids,subids_len);
1280
0
  wmem_free(NULL, subids);
1281
0
}
1282
1283
#ifdef HAVE_LIBSMI
1284
// NOLINTNEXTLINE(misc-no-recursion)
1285
static void oid_add_unique_path(GHashTable* unique_paths, GString* path_str, const char* path)
1286
{
1287
  WS_DIR* dir;
1288
  WS_DIRENT* file;
1289
  const char* name;
1290
  char* filename;
1291
1292
  //Sanity check
1293
  if (!(path && *path))
1294
    return;
1295
1296
  if ((dir = ws_dir_open(path, 0, NULL)) != NULL) {
1297
    unsigned file_count = 0;
1298
    while ((file = ws_dir_read_name(dir)) != NULL) {
1299
      name = ws_dir_get_name(file);
1300
1301
      filename = ws_strdup_printf("%s%s%s", path, G_DIR_SEPARATOR_S, name);
1302
1303
      if (test_for_directory(filename) == EISDIR) {
1304
        if (!g_hash_table_contains(unique_paths, filename))
1305
          oid_add_unique_path(unique_paths, path_str, filename);
1306
      }
1307
      else {
1308
        if (file_count == 0) {
1309
          //There's at least one file in this directory, presume it's a MIB file and add it to the unique paths.
1310
          if (g_hash_table_add(unique_paths, g_strdup(path)))
1311
            g_string_append_printf(path_str, G_SEARCHPATH_SEPARATOR_S "%s", path);
1312
        }
1313
        file_count++;
1314
      }
1315
      g_free(filename);
1316
1317
    }
1318
    ws_dir_close(dir);
1319
  }
1320
}
1321
1322
//Done for more glib-friendly datatypes.
1323
gboolean
1324
files_identical_equal(const void* fname1, const void* fname2)
1325
{
1326
  return files_identical((const char*)fname1, (const char*)fname2);
1327
}
1328
#endif
1329
1330
/**
1331
 * Fetch the default OID path.
1332
 */
1333
char *
1334
0
oid_get_default_mib_path(const char* app_env_var_prefix _U_) {
1335
#ifdef HAVE_LIBSMI
1336
  GString* path_str = g_string_new("");
1337
  char *path;
1338
  unsigned i;
1339
1340
  if (!load_smi_modules) {
1341
    ws_info("OID resolution not enabled");
1342
    return g_string_free(path_str, FALSE);
1343
  }
1344
1345
  //To limit the size of the MIB path, we use a hash table to store the unique paths.
1346
  GHashTable* unique_paths = g_hash_table_new_full(files_identical_hash, files_identical_equal, NULL, g_free);
1347
1348
#ifdef _WIN32
1349
  /* XXX - This is appropriate for MSYS2 installed via package,
1350
   * but an MSYS2 install into the POSIX runtime should probably
1351
   * use the other path (NB: check the search path separator.) */
1352
  path = get_datafile_path("snmp\\mibs", app_env_var_prefix);
1353
  oid_add_unique_path(unique_paths, path_str, path);
1354
1355
  path = get_persconffile_path("snmp\\mibs", false, app_env_var_prefix);
1356
  oid_add_unique_path(unique_paths, path_str, path);
1357
#else
1358
  // This directory is usually flat on UN*X systems, and we haven't
1359
  // recursively descended into it before. We could start.
1360
  g_hash_table_add(unique_paths, g_strdup("/usr/share/snmp/mibs"));
1361
  g_string_append(path_str, "/usr/share/snmp/mibs");
1362
1363
  if (!smi_init_done)
1364
    smiInit("wireshark");
1365
  path = smiGetPath();
1366
  if (strlen(path) > 0 ) {
1367
    // Conversely to above, libsmi is generally compiled with the
1368
    // entire directory structure so we don't need to recurse here
1369
    // or check that there actually are files in each directory.
1370
    // We do want to split them for adding to the unique hash table.
1371
    // 20 is arbitrary here to have a limit; 12 is the number that
1372
    // libsmi seems to be compiled with currently.
1373
    char **paths = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 20);
1374
    for (i = 0; paths[i]; i++) {
1375
      //oid_add_unique_path(unique_paths, path_str, paths[i]);
1376
      if (g_hash_table_add(unique_paths, g_strdup(path)))
1377
        g_string_append_printf(path_str, G_SEARCHPATH_SEPARATOR_S "%s", path);
1378
    }
1379
    g_strfreev(paths);
1380
  }
1381
  smi_free(path);
1382
1383
  if (oids_init_done == false)
1384
  {
1385
#endif
1386
    for (i = 0; i < num_smi_paths; i++) {
1387
      if (!(smi_paths[i].name && *smi_paths[i].name))
1388
        continue;
1389
1390
      oid_add_unique_path(unique_paths, path_str, smi_paths[i].name);
1391
    }
1392
#ifndef _WIN32
1393
  }
1394
#endif
1395
1396
  g_hash_table_destroy(unique_paths);
1397
1398
  return g_string_free(path_str, FALSE);
1399
#else /* HAVE_LIBSMI */
1400
  return g_strdup("");
1401
0
#endif
1402
0
}
1403
1404
#ifdef DEBUG_OIDS
1405
char* oid_test_a2b(uint32_t num_subids, uint32_t* subids) {
1406
  uint8_t* sub2enc = NULL;
1407
  uint8_t* str2enc = NULL;
1408
  uint32_t* enc2sub = NULL;
1409
  uint32_t* str2sub;
1410
  char* ret;
1411
  char* sub2str = oid_subid2string(NULL, subids, num_subids);
1412
  unsigned sub2enc_len = oid_subid2encoded(NULL, num_subids, subids,&sub2enc);
1413
  unsigned enc2sub_len = oid_encoded2subid(NULL, sub2enc, sub2enc_len, &enc2sub);
1414
  char* enc2str = oid_encoded2string(NULL, sub2enc, sub2enc_len);
1415
  unsigned str2enc_len = oid_string2encoded(NULL, sub2str,&str2enc);
1416
  unsigned str2sub_len = oid_string2subid(sub2str,&str2sub);
1417
1418
  char* sub2enc_str = bytes_to_str_punct(NULL, sub2enc, sub2enc_len, ':');
1419
  char* enc2sub_str = enc2sub ? oid_subid2string(NULL, enc2sub,enc2sub_len) : wmem_strdup(NULL, "-");
1420
  char* str2enc_str = bytes_to_str_punct(NULL, str2enc, str2enc_len, ':');
1421
  char* str2sub_str = str2sub ? oid_subid2string(NULL, str2sub,str2sub_len) : wmem_strdup(NULL, "-");
1422
1423
  ret = wmem_strdup_printf(NULL,
1424
              "oid_subid2string=%s \n"
1425
              "oid_subid2encoded=[%d]%s \n"
1426
              "oid_encoded2subid=%s \n "
1427
              "oid_encoded2string=%s \n"
1428
              "oid_string2encoded=[%d]%s \n"
1429
              "oid_string2subid=%s \n "
1430
              ,sub2str
1431
              ,sub2enc_len,sub2enc_str
1432
              ,enc2sub_str
1433
              ,enc2str
1434
              ,str2enc_len,str2enc_str,
1435
              ,str2sub_str
1436
              );
1437
1438
  wmem_free(NULL, sub2enc_str);
1439
  wmem_free(NULL, enc2sub_str);
1440
  wmem_free(NULL, str2enc_str);
1441
  wmem_free(NULL, str2sub_str);
1442
1443
  wmem_free(NULL, sub2str);
1444
  wmem_free(NULL, enc2sub);
1445
  wmem_free(NULL, sub2enc);
1446
  wmem_free(NULL, str2enc);
1447
  wmem_free(NULL, enc2str);
1448
  return ret;
1449
}
1450
1451
void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
1452
  static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1453
  static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1454
                    "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1455
                    "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1456
  proto_item* pi = proto_tree_add_debug_text(tree,NULL,0,0,
1457
  "OidInfo: Name='%s' sub-id=%u  kind=%s  hfid=%d",
1458
  oid_info->name ? oid_info->name : "",
1459
  oid_info->subid,
1460
  oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
1461
  oid_info->value_hfid);
1462
  proto_tree* pt = proto_item_add_subtree(pi,0);
1463
  oid_key_t* key;
1464
1465
  for(key = oid_info->key; key; key = key->next) {
1466
    proto_tree_add_debug_text(pt,NULL,0,0,
1467
    "Key: name='%s' num_subids=%d type=%s",
1468
    key->name,
1469
    key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
1470
    );
1471
  };
1472
1473
  if (oid_info->parent) {
1474
    pi = proto_tree_add_debug_text(pt,NULL,0,0,"Parent:");
1475
    pt = proto_item_add_subtree(pi,0);
1476
    add_oid_debug_subtree(oid_info->parent, pt);
1477
  }
1478
}
1479
#endif
1480
1481
/*
1482
 * Editor modelines
1483
 *
1484
 * Local Variables:
1485
 * c-basic-offset: 8
1486
 * tab-width: 8
1487
 * indent-tabs-mode: t
1488
 * End:
1489
 *
1490
 * ex: set shiftwidth=8 tabstop=8 noexpandtab:
1491
 * :indentSize=8:tabSize=8:noTabs=false:
1492
 */