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