Fix Dissector bug, protocol SNMP: proto.c:932: failed assertion
[metze/wireshark/wip.git] / epan / oids.c
1 /* oids.c
2  * Object IDentifier Support
3  *
4  * (c) 2007, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35
36 #include "emem.h"
37 #include "uat.h"
38 #include "prefs.h"
39 #include "proto.h"
40 #include "packet.h"
41 #include "report_err.h"
42 #include "filesystem.h"
43 #include "dissectors/packet-ber.h"
44
45 #ifdef HAVE_LIBSMI
46 #include <smi.h>
47 #endif
48
49 #define D(level,args) do if (debuglevel >= level) { printf args; printf("\n"); fflush(stdout); } while(0)
50
51 #include "oids.h"
52
53 static int debuglevel = 0;
54
55 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};
56 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};
57 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};
58 static const oid_value_type_t ipv4_type =       { FT_IPv4,   BASE_NONE, BER_CLASS_APP, 0,                       4,   4, OID_KEY_TYPE_IPADDR,  4};
59 static const oid_value_type_t counter32_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 1,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
60 static const oid_value_type_t unsigned32_type = { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 2,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
61 /*static const oid_value_type_t timeticks_type =  { FT_UINT32, BASE_DEC,  BER_CLASS_APP, 3,                       1,   4, OID_KEY_TYPE_INTEGER, 1};
62  * TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
63  * If the BER encoding should not have the top bit set as to not become a negative number
64  * the ber encoding may take 5 octets to encode.
65  */
66 static const oid_value_type_t timeticks_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 3,                       1,   5, OID_KEY_TYPE_INTEGER, 1};
67 static const oid_value_type_t opaque_type =     { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 4,                       1,   4, OID_KEY_TYPE_BYTES,   0};
68 static const oid_value_type_t nsap_type =       { FT_BYTES,  BASE_NONE, BER_CLASS_APP, 5,                       0,  -1, OID_KEY_TYPE_NSAP,    0};
69 static const oid_value_type_t counter64_type =  { FT_UINT64, BASE_DEC,  BER_CLASS_APP, 6,                       1,   8, OID_KEY_TYPE_INTEGER, 1};
70 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};
71 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};
72 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};
73 static const oid_value_type_t ether_type =      { FT_ETHER,  BASE_NONE, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, 6,   6, OID_KEY_TYPE_BYTES,   6};
74 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};
75 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};
76
77 static oid_info_t oid_root = { 0, NULL, OID_KIND_UNKNOWN, NULL, &unknown_type, -2, NULL, NULL, NULL};
78
79 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) {
80         guint i = 0;
81         oid_info_t* c = &oid_root;
82
83         if (!oid_root.children) {
84                 char* debug_env = getenv("WIRESHARK_DEBUG_MIBS");
85                 guint32 subid;
86
87                 debuglevel = debug_env ? strtoul(debug_env,NULL,10) : 0;
88
89                 oid_root.children = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"oid_root");
90
91                 /*
92                  * make sure we got strings at least in the three root-children oids
93                  * that way oid_resolved() will always have a string to print
94                  */
95                 subid = 0; oid_add("itu-t",1,&subid);
96                 subid = 1; oid_add("iso",1,&subid);
97                 subid = 2; oid_add("joint-iso-itu-t",1,&subid);
98         }
99
100         oid_len--;
101
102         do {
103                 oid_info_t* n = emem_tree_lookup32(c->children,subids[i]);
104
105                 if(n) {
106                         if (i == oid_len) {
107                                 if (n->name) {
108                                         if (!g_str_equal(n->name,name)) {
109                                                 D(2,("Renaming Oid from: %s -> %s, this means the same oid is registered more than once",n->name,name));
110                                         }
111                                         /* XXX - Don't free n->name here. It may be part of an hf_register_info
112                                          * struct that has been appended to the hfa GArray. */
113                                 }
114
115                                 n->name = g_strdup(name);
116
117                                 if (! n->value_type) {
118                                         n->value_type = type;
119                                 }
120
121                                 return n;
122                         }
123                 } else {
124                         n = g_malloc(sizeof(oid_info_t));
125                         n->subid = subids[i];
126                         n->kind = kind;
127                         n->children = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"oid_children");
128                         n->value_hfid = -2;
129                         n->key = key;
130                         n->parent = c;
131                         n->bits = NULL;
132
133                         emem_tree_insert32(c->children,n->subid,n);
134
135                         if (i == oid_len) {
136                                 n->name = g_strdup(name);
137                                 n->value_type = type;
138                                 n->kind = kind;
139                                 return n;
140                         } else {
141                                 n->name = NULL;
142                                 n->value_type = NULL;
143                                 n->kind = OID_KIND_UNKNOWN;
144                         }
145                 }
146                 c = n;
147         } while(++i);
148
149         g_assert_not_reached();
150         return NULL;
151 }
152
153 void oid_add(const char* name, guint oid_len, guint32 *subids) {
154         g_assert(subids && *subids <= 2);
155         if (oid_len) {
156                 D(3,("\tOid (from subids): %s %s ",name?name:"NULL", oid_subid2string(subids,oid_len)));
157                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
158         } else {
159                 D(1,("Failed to add Oid: %s (from subids)",name?name:"NULL"));
160         }
161 }
162
163 void oid_add_from_string(const char* name, const gchar *oid_str) {
164         guint32* subids;
165         guint oid_len = oid_string2subid(oid_str, &subids);
166
167         if (oid_len) {
168                 D(3,("\tOid (from string): %s %s ",name?name:"NULL", oid_subid2string(subids,oid_len)));
169                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,oid_len,subids);
170         } else {
171                 D(1,("Failed to add Oid: %s %s ",name?name:"NULL", oid_str?oid_str:NULL));
172         }
173 }
174
175 extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len) {
176         guint32* subids;
177         guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
178
179         if (subids_len) {
180                 D(3,("\tOid (from encoded): %s %s ",name, oid_subid2string(subids,subids_len)));
181                 add_oid(name,OID_KIND_UNKNOWN,NULL,NULL,subids_len,subids);
182         } else {
183                 D(1,("Failed to add Oid: %s [%d]%s ",name?name:"NULL", oid_len,bytestring_to_str(oid, oid_len, ':')));
184         }
185 }
186
187 #ifdef HAVE_LIBSMI
188 /* de-allocate storage mallocated by libsmi                            */
189 /*                                                                     */
190 /* XXX: On Windows we can use free() only if the Windows libsmi.dll    */
191 /*      being used is linked with the same CRTL as wireshark.          */
192 /*      As a temporary hack we'll assume on Windows that the Wireshark */
193 /*      build of libsmi.dll was done with VC6/msvcrt.dll (as is        */
194 /*      currently the case).  If wireshark is being built with         */
195 /*      vc6 (which is also currently the case for the standard         */
196 /*      wireshark release). we can use free().                         */
197 /*      If vc6 is not being used here, then we'll just have to live    */
198 /*      with a memory leak for now.                                    */
199 /*      Note: A permanent fix would probably be for libsmi to include  */
200 /*       its' existing smiFree function as part of the libsmi API so   */
201 /*       wireshark can call it to free storage mallocated by libsmi.   */
202
203 static void smi_free(void *ptr) {
204 #if !defined _WIN32 || (_MSC_VER == 1200)
205         free(ptr);
206 #endif
207 }
208
209
210 typedef struct smi_module_t {
211         char* name;
212 } smi_module_t;
213
214 static smi_module_t* smi_paths = NULL;
215 static guint num_smi_paths = 0;
216 static uat_t* smi_paths_uat = NULL;
217
218 static smi_module_t* smi_modules = NULL;
219 static guint num_smi_modules = 0;
220 static uat_t* smi_modules_uat = NULL;
221
222 static GString* smi_errors;
223
224 UAT_CSTRING_CB_DEF(smi_mod,name,smi_module_t)
225
226 static void smi_error_handler(char *path, int line, int severity, char *msg, char *tag) {
227                 g_string_sprintfa(smi_errors,"%s:%d %d %s %s\n",
228                                                   path ? path : "-",
229                                                   line, severity,
230                                                   tag ? tag : "-",
231                                                   msg ? msg : "");
232 }
233
234
235 static void* smi_mod_copy_cb(void* dest, const void* orig, unsigned len _U_) {
236         const smi_module_t* m = orig;
237         smi_module_t* d = dest;
238
239         d->name = g_strdup(m->name);
240
241         return d;
242 }
243
244 static void smi_mod_free_cb(void* p) {
245         smi_module_t* m = p;
246         if (m->name) g_free(m->name);
247 }
248
249
250 static char* alnumerize(const char* name) {
251         char* s = g_strdup(name);
252         char* r = s;
253         char* w = r;
254         char c;
255
256         for (;(c = *r); r++) {
257                 if (isalnum(c) || c == '_' || c == '-' || c == '.') {
258                         *(w++) = c;
259                 } else if (c == ':' && r[1] == ':') {
260                         *(w++) = '.';
261                 }
262         }
263
264         *w = '\0';
265
266         return s;
267 }
268
269 const oid_value_type_t* get_typedata(SmiType* smiType) {
270         /*
271          * There has to be a better way to know if a given
272          * OCTETSTRING type is actually human readable text,
273          * an address of some type or some moe specific FT_
274          * Until that is found, this is the mappping between
275          * SNMP Types and our FT_s
276          */
277         static const struct _type_mapping_t {
278                 char* name;
279                 SmiBasetype base;
280                 const oid_value_type_t* type;
281         } types[] =  {
282                 {"IpAddress", SMI_BASETYPE_UNKNOWN, &ipv4_type},
283                 {"InetAddressIPv4",SMI_BASETYPE_UNKNOWN,&ipv4_type},
284                 {"InetAddressIPv6",SMI_BASETYPE_UNKNOWN,&ipv6_type},
285                 {"NetworkAddress",SMI_BASETYPE_UNKNOWN,&ipv4_type},
286                 {"MacAddress",SMI_BASETYPE_UNKNOWN,&ether_type},
287                 {"TimeTicks",SMI_BASETYPE_UNKNOWN,&timeticks_type},
288                 {"Ipv6Address",SMI_BASETYPE_UNKNOWN,&ipv6_type},
289                 {"TimeStamp",SMI_BASETYPE_UNKNOWN,&timeticks_type},
290                 {"DisplayString",SMI_BASETYPE_UNKNOWN,&string_type},
291                 {"SnmpAdminString",SMI_BASETYPE_UNKNOWN,&string_type},
292                 {"DateAndTime",SMI_BASETYPE_UNKNOWN,&string_type},
293                 {"Counter",SMI_BASETYPE_UNKNOWN,&counter32_type},
294                 {"Counter32",SMI_BASETYPE_UNKNOWN,&counter32_type},
295                 {"Unsigned32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
296                 {"Gauge",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
297                 {"Gauge32",SMI_BASETYPE_UNKNOWN,&unsigned32_type},
298                 {"NsapAddress",SMI_BASETYPE_UNKNOWN,&nsap_type},
299                 {"i32",SMI_BASETYPE_INTEGER32,&integer_type},
300                 {"octets",SMI_BASETYPE_OCTETSTRING,&bytes_type},
301                 {"oid",SMI_BASETYPE_OBJECTIDENTIFIER,&oid_type},
302                 {"u32",SMI_BASETYPE_UNSIGNED32,&unsigned32_type},
303                 {"u64",SMI_BASETYPE_UNSIGNED64,&counter64_type},
304                 {"f32",SMI_BASETYPE_FLOAT32,&float_type},
305                 {"f64",SMI_BASETYPE_FLOAT64,&double_type},
306                 {"f128",SMI_BASETYPE_FLOAT128,&bytes_type},
307                 {"enum",SMI_BASETYPE_ENUM,&integer_type},
308                 {"bits",SMI_BASETYPE_BITS,&bytes_type},
309                 {"unk",SMI_BASETYPE_UNKNOWN,&unknown_type},
310                 {NULL,0,NULL}
311         };
312         const struct _type_mapping_t* t;
313         SmiType* sT = smiType;
314
315         if (!smiType) return NULL;
316
317         do {
318                 for (t = types; t->type ; t++ ) {
319                         char* name = smiRenderType(sT, SMI_RENDER_NAME);
320                         if (name && t->name && g_str_equal(name, t->name )) {
321                                 smi_free(name);
322                                 return t->type;
323                         }
324                         if (name) {
325                                 smi_free (name);
326                         }
327                 }
328         } while(( sT  = smiGetParentType(sT) ));
329
330         for (t = types; t->type ; t++ ) {
331                 if(smiType->basetype == t->base) {
332                         return t->type;
333                 }
334         }
335
336         return &unknown_type;
337 }
338
339 static guint get_non_implicit_size(SmiType* sT) {
340         SmiRange *sR;
341         guint size = 0xffffffff;
342
343         switch (sT->basetype) {
344                 case SMI_BASETYPE_OCTETSTRING:
345                 case SMI_BASETYPE_OBJECTIDENTIFIER:
346                         break;
347                 default:
348                         return 0;
349         }
350
351         for ( ; sT; sT = smiGetParentType(sT) ) {
352                 for (sR = smiGetFirstRange(sT); sR ; sR = smiGetNextRange(sR)) {
353                         if (size == 0xffffffff) {
354                                 if (sR->minValue.value.unsigned32 == sR->maxValue.value.unsigned32) {
355                                         size = sR->minValue.value.unsigned32;
356                                 } else {
357                                         return 0;
358                                 }
359                         } else {
360                                 if (sR->minValue.value.unsigned32 != size || sR->maxValue.value.unsigned32 != size) {
361                                         return 0;
362                                 }
363                         }
364                 }
365         }
366
367         return size == 0xffffffff ? 0 : size;
368 }
369
370
371 static inline oid_kind_t smikind(SmiNode* sN, oid_key_t** key_p) {
372         *key_p = NULL;
373
374         switch(sN->nodekind) {
375                 case SMI_NODEKIND_ROW: {
376                         SmiElement* sE;
377                         oid_key_t* kl = NULL;
378                         const oid_value_type_t* typedata = NULL;
379                         gboolean implied;
380
381                         switch (sN->indexkind) {
382                                 case SMI_INDEX_INDEX:
383                                         break;
384                                 case SMI_INDEX_AUGMENT:
385                                 case SMI_INDEX_REORDER:
386                                 case SMI_INDEX_SPARSE:
387                                 case SMI_INDEX_EXPAND:
388                                         sN = smiGetRelatedNode(sN);
389                                         break;
390                                 case SMI_INDEX_UNKNOWN:
391                                         return OID_KIND_UNKNOWN;
392                         };
393
394                         implied = sN->implied;
395
396                         for (sE = smiGetFirstElement(sN); sE; sE = smiGetNextElement(sE)) {
397                                 SmiNode* elNode =  smiGetElementNode(sE) ;
398                                 SmiType* elType = smiGetNodeType(elNode);
399                                 oid_key_t* k;
400                                 guint non_implicit_size = 0;
401                                 char *oid1, *oid2;
402
403                                 if (elType) {
404                                         non_implicit_size = get_non_implicit_size(elType);
405                                 }
406
407                                 typedata =  get_typedata(elType);
408
409                                 k = g_malloc(sizeof(oid_key_t));
410
411                                 oid1 = smiRenderOID(sN->oidlen, sN->oid, SMI_RENDER_QUALIFIED);
412                                 oid2 = smiRenderOID(elNode->oidlen, elNode->oid, SMI_RENDER_NAME);
413                                 k->name = g_strdup_printf("%s.%s", oid1, oid2);
414                                 smi_free (oid1);
415                                 smi_free (oid2);
416
417                                 k->hfid = -2;
418                                 k->ft_type = typedata ? typedata->ft_type : FT_BYTES;
419                                 k->display = typedata ? typedata->display : BASE_NONE;
420                                 k->next = NULL;
421
422
423                                 if (typedata) {
424                                         k->key_type = typedata->keytype;
425                                         k->num_subids = typedata->keysize;
426                                 } else {
427                                         if (elType) {
428                                                 switch (elType->basetype) {
429                                                         case SMI_BASETYPE_BITS:
430                                                         case SMI_BASETYPE_OCTETSTRING: {
431                                                                 k->key_type = OID_KEY_TYPE_BYTES;
432                                                                 k->num_subids = non_implicit_size;
433                                                                 break;
434                                                         }
435                                                         case SMI_BASETYPE_ENUM:
436                                                         case SMI_BASETYPE_OBJECTIDENTIFIER:
437                                                         case SMI_BASETYPE_INTEGER32:
438                                                         case SMI_BASETYPE_UNSIGNED32:
439                                                         case SMI_BASETYPE_INTEGER64:
440                                                         case SMI_BASETYPE_UNSIGNED64:
441                                                                 k->key_type = OID_KEY_TYPE_INTEGER;
442                                                                 k->num_subids = 1;
443                                                                 break;
444                                                         default:
445                                                                 k->key_type = OID_KEY_TYPE_WRONG;
446                                                                 k->num_subids = 0;
447                                                                 break;
448                                                 }
449                                         } else {
450                                                 k->key_type = OID_KEY_TYPE_WRONG;
451                                                 k->num_subids = 0;
452                                                 break;
453                                         }
454                                 }
455
456                                 if (!*key_p) *key_p = k;
457                                 if (kl) kl->next = k;
458
459                                 kl = k;
460                         }
461
462                         if (implied) {
463                                 switch (kl->key_type) {
464                                         case OID_KEY_TYPE_BYTES:  kl->key_type = OID_KEY_TYPE_IMPLIED_BYTES; break;
465                                         case OID_KEY_TYPE_STRING: kl->key_type = OID_KEY_TYPE_IMPLIED_STRING; break;
466                                         case OID_KEY_TYPE_OID:    kl->key_type = OID_KEY_TYPE_IMPLIED_OID; break;
467                                         default: break;
468                                 }
469                         }
470
471                         return OID_KIND_ROW;
472                 }
473                 case SMI_NODEKIND_NODE: return OID_KIND_NODE;
474                 case SMI_NODEKIND_SCALAR: return OID_KIND_SCALAR;
475                 case SMI_NODEKIND_TABLE: return OID_KIND_TABLE;
476                 case SMI_NODEKIND_COLUMN: return OID_KIND_COLUMN;
477                 case SMI_NODEKIND_NOTIFICATION: return OID_KIND_NOTIFICATION;
478                 case SMI_NODEKIND_GROUP: return OID_KIND_GROUP;
479                 case SMI_NODEKIND_COMPLIANCE: return OID_KIND_COMPLIANCE;
480                 case SMI_NODEKIND_CAPABILITIES: return OID_KIND_CAPABILITIES;
481                 default: return OID_KIND_UNKNOWN;
482         }
483 }
484
485 #define IS_ENUMABLE(ft) ( (ft == FT_UINT8) || (ft == FT_UINT16) || (ft == FT_UINT24) || (ft == FT_UINT32) \
486                                                    || (ft == FT_INT8) || (ft == FT_INT16) || (ft == FT_INT24) || (ft == FT_INT32) \
487                                                    || (ft == FT_UINT64) || (ft == FT_INT64) )
488
489 void register_mibs(void) {
490         SmiModule *smiModule;
491         SmiNode *smiNode;
492         guint i;
493         int proto_mibs = -1;
494         GArray* hfa = g_array_new(FALSE,TRUE,sizeof(hf_register_info));
495         GArray* etta = g_array_new(FALSE,TRUE,sizeof(gint*));
496         static uat_field_t smi_fields[] = {
497                 UAT_FLD_CSTRING(smi_mod,name,"The module's name"),
498                 UAT_END_FIELDS
499         };
500         static uat_field_t smi_paths_fields[] = {
501                 UAT_FLD_CSTRING(smi_mod,name,"The directory name"),
502                 UAT_END_FIELDS
503         };
504         char* smi_load_error = NULL;
505         gchar* path_str;
506
507         smi_modules_uat = uat_new("SMI Modules",
508                                                           sizeof(smi_module_t),
509                                                           "smi_modules",
510                                                           FALSE,
511                                                           (void*)&smi_modules,
512                                                           &num_smi_modules,
513                                                           UAT_CAT_GENERAL,
514                                                           "ChSNMPSMIModules",
515                                                           smi_mod_copy_cb,
516                                                           NULL,
517                                                           smi_mod_free_cb,
518                                                           smi_fields);
519
520         smi_paths_uat = uat_new("SMI Paths",
521                                                           sizeof(smi_module_t),
522                                                           "smi_paths",
523                                                           FALSE,
524                                                           (void*)&smi_paths,
525                                                           &num_smi_paths,
526                                                           UAT_CAT_GENERAL,
527                                                           "ChSNMPSMIPaths",
528                                                           smi_mod_copy_cb,
529                                                           NULL,
530                                                           smi_mod_free_cb,
531                                                           smi_paths_fields);
532
533
534         smiInit(NULL);
535
536         uat_load(smi_modules_uat, &smi_load_error);
537
538         if (smi_load_error) {
539                 report_failure("Error Loading SMI Modules Table: %s",smi_load_error);
540                 return;
541         }
542
543         uat_load(smi_paths_uat, &smi_load_error);
544
545         if (smi_load_error) {
546                 report_failure("Error Loading SMI Paths Table: %s",smi_load_error);
547                 return;
548         }
549
550         path_str = oid_get_default_mib_path();
551         D(1,("SMI Path: '%s'",path_str));
552
553         smiSetPath(path_str);
554
555
556
557         smi_errors = g_string_new("");
558         smiSetErrorHandler(smi_error_handler);
559
560         for(i=0;i<num_smi_modules;i++) {
561                 if (!smi_modules[i].name) continue;
562
563
564                 if (smiIsLoaded(smi_modules[i].name)) {
565                         continue;
566                 } else {
567                         char* mod_name =  smiLoadModule(smi_modules[i].name);
568                         if (mod_name)
569                                 D(2,("Loaded: '%s'[%d] as %s",smi_modules[i].name,i,mod_name ));
570                         else
571                                 D(1,("Failed to load: '%s'[%d]",smi_modules[i].name,i));
572                 }
573         }
574
575         if (smi_errors->len) {
576                 report_failure("The following errors were found while loading the MIBS:\n%s\n\n"
577                                            "The Current Path is: %s\n" , smi_errors->str , path_str);
578                 D(1,("Errors while loading:\n%s\n",smi_errors->str));
579         }
580
581         g_free(path_str);
582         g_string_free(smi_errors,TRUE);
583
584         for (smiModule = smiGetFirstModule();
585                  smiModule;
586                  smiModule = smiGetNextModule(smiModule)) {
587
588                 D(3,("\tModule: %s", smiModule->name));
589
590                 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
591                          smiNode;
592                          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
593
594                         SmiType* smiType =  smiGetNodeType(smiNode);
595                         const oid_value_type_t* typedata =  get_typedata(smiType);
596                         oid_key_t* key;
597                         oid_kind_t kind = smikind(smiNode,&key);
598                         char *oid = smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_QUALIFIED);
599                         oid_info_t* oid_data = add_oid(oid,
600                                                        kind,
601                                                        typedata,
602                                                        key,
603                                                        smiNode->oidlen,
604                                                        smiNode->oid);
605                         smi_free (oid);
606
607                         D(4,("\t\tNode: kind=%d oid=%s name=%s ",
608                                  oid_data->kind, oid_subid2string(smiNode->oid, smiNode->oidlen), oid_data->name ));
609
610                         if ( typedata && oid_data->value_hfid == -2 ) {
611                                 SmiNamedNumber* smiEnum;
612                                 hf_register_info hf = { &(oid_data->value_hfid), {
613                                         oid_data->name,
614                                         alnumerize(oid_data->name),
615                                         typedata->ft_type,
616                                         typedata->display,
617                                         NULL,
618                                         0,
619 #if !defined _WIN32 || (_MSC_VER == 1200)
620                                         smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL),
621 #else
622                                         g_strdup (smiRenderOID(smiNode->oidlen, smiNode->oid, SMI_RENDER_ALL)),
623 #endif
624                                         HFILL }};
625
626                                 oid_data->value_hfid = -1;
627
628                                 if ( IS_ENUMABLE(hf.hfinfo.type) && (smiEnum = smiGetFirstNamedNumber(smiType))) {
629                                         GArray* vals = g_array_new(TRUE,TRUE,sizeof(value_string));
630
631                                         for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum)) {
632                                                 if (smiEnum->name) {
633                                                         value_string val = {smiEnum->value.value.integer32,g_strdup(smiEnum->name)};
634                                                         g_array_append_val(vals,val);
635                                                 }
636                                         }
637
638                                         hf.hfinfo.strings = VALS(vals->data);
639                                         g_array_free(vals,FALSE);
640                                 }
641 #if 0 /* packet-snmp does not handle bits yet */
642                         } else if (smiType->basetype == SMI_BASETYPE_BITS && ( smiEnum = smiGetFirstNamedNumber(smiType) )) {
643                                 guint n = 0;
644                                 oid_bits_info_t* bits = g_malloc(sizeof(oid_bits_info_t));
645                                 gint* ettp = &(bits->ett);
646
647                                 bits->num = 0;
648                                 bits->ett = -1;
649
650                                 g_array_append_val(etta,ettp);
651
652                                 for(;smiEnum; smiEnum = smiGetNextNamedNumber(smiEnum), bits->num++);
653
654                                 bits->data = g_malloc(sizeof(struct _oid_bit_t)*bits->num);
655
656                                 for(smiEnum = smiGetFirstNamedNumber(smiType),n=0;
657                                         smiEnum;
658                                         smiEnum = smiGetNextNamedNumber(smiEnum),n++) {
659                                         guint mask = 1 << (smiEnum->value.value.integer32 % 8);
660                                         char* base = alnumerize(oid_data->name);
661                                         char* ext = alnumerize(smiEnum->name);
662                                         hf_register_info hf2 = { &(bits->data[n].hfid), { NULL, NULL, FT_UINT8, BASE_HEX, NULL, mask, "", HFILL }};
663
664                                         bits->data[n].hfid = -1;
665                                         bits->data[n].offset = smiEnum->value.value.integer32 / 8;
666
667                                         hf2.hfinfo.name = g_strdup_printf("%s:%s",oid_data->name,smiEnum->name);
668                                         hf2.hfinfo.abbrev = g_strdup_printf("%s.%s",base,ext);
669
670                                         g_free(base);
671                                         g_free(ext);
672                                         g_array_append_val(hfa,hf2);
673                                 }
674 #endif /* packet-snmp does not use this yet */
675                                 g_array_append_val(hfa,hf);
676                         }
677
678                         if ((key = oid_data->key)) {
679                                 for(; key; key = key->next) {
680                                         hf_register_info hf = { &(key->hfid), {
681                                                 key->name,
682                                                 alnumerize(key->name),
683                                                 key->ft_type,
684                                                 key->display,
685                                                 NULL,
686                                                 0,
687                                                 "",
688                                                 HFILL }};
689
690                                         D(5,("\t\t\tIndex: name=%s subids=%d key_type=%d",
691                                                  key->name, key->num_subids, key->key_type ));
692
693                                         if (key->hfid == -2) {
694                                                 g_array_append_val(hfa,hf);
695                                                 key->hfid = -1;
696                                         } else {
697                                                 g_free((void*)hf.hfinfo.abbrev);
698                                         }
699                                 }
700                         }
701                 }
702         }
703
704         proto_mibs = proto_register_protocol("MIBs", "MIBS", "mibs");
705
706         proto_register_field_array(proto_mibs, (hf_register_info*)hfa->data, hfa->len);
707
708         proto_register_subtree_array((gint**)etta->data, etta->len);
709
710
711         g_array_free(etta,TRUE);
712         g_array_free(hfa,FALSE);
713 }
714 #endif
715
716
717 void oids_init(void) {
718 #ifdef HAVE_LIBSMI
719         register_mibs();
720 #else
721         D(1,("libsmi disabled oid resolution not enabled"));
722 #endif
723 }
724
725 const char* oid_subid2string(guint32* subids, guint len) {
726         char* s = ep_alloc0(((len)*11)+1);
727         char* w = s;
728
729         if(!subids)
730                 return "*** Empty OID ***";
731
732         do {
733                 w += sprintf(w,"%u.",*subids++);
734         } while(--len);
735
736         if (w!=s) *(w-1) = '\0'; else *(s) = '\0';
737
738         return s;
739 }
740
741 guint check_num_oid(const char* str) {
742         const char* r = str;
743         char c = '\0';
744         guint n = 0;
745
746         D(8,("check_num_oid: '%s'",str));
747         if (*r == '.' || *r == '\0') return 0;
748
749         do {
750                 D(9,("\tcheck_num_oid: '%c' %d",*r,n));
751                 switch(*r) {
752                         case '.':
753                                 n++;
754                                 if (c == '.') return 0;
755                         case '1' : case '2' : case '3' : case '4' : case '5' :
756                         case '6' : case '7' : case '8' : case '9' : case '0' :
757                                 continue;
758                         case '\0':
759                                 n++;
760                                 break;
761                         default:
762                                 return 0;
763                 }
764         } while((c = *r++));
765
766         if (c == '.') return 0;
767
768         return n;
769 }
770
771 guint oid_string2subid(const char* str, guint32** subids_p) {
772         const char* r = str;
773         guint32* subids;
774         guint32* subids_overflow;
775         guint n = check_num_oid(str);
776         /*
777          * we cannot handle sub-ids greater than 32bytes
778          * keep a pilot subid of 64 bytes to check the limit
779          */
780         guint64 subid = 0;
781
782         D(6,("oid_string2subid: str='%s'",str));
783
784         if (!n) {
785                 *subids_p = NULL;
786                 return 0;
787         }
788
789         *subids_p = subids = ep_alloc0(sizeof(guint32)*n);
790         subids_overflow = subids + n;
791         do switch(*r) {
792                 case '.':
793                         subid = 0;
794                         subids++;
795                         continue;
796                 case '1' : case '2' : case '3' : case '4' : case '5' :
797                 case '6' : case '7' : case '8' : case '9' : case '0' :
798                         subid *= 10;
799                         subid += *r - '0';
800
801                         if( subids >= subids_overflow ||  subid > 0xffffffff) {
802                                 *subids_p=NULL;
803                                 return 0;
804                         }
805
806                         *(subids) *= 10;
807                         *(subids) += *r - '0';
808                         continue;
809                 case '\0':
810                         break;
811                 default:
812                         return 0;
813         } while(*r++);
814
815         return n;
816 }
817
818
819 guint oid_encoded2subid(const guint8 *oid_bytes, gint oid_len, guint32** subids_p) {
820         gint i;
821         guint n = 1;
822         gboolean is_first = TRUE;
823         guint32* subids;
824         guint32* subid_overflow;
825         /*
826          * we cannot handle sub-ids greater than 32bytes
827          * have the subid in 64 bytes to be able to check the limit
828          */
829         guint64 subid = 0;
830
831         for (i=0; i<oid_len; i++) { if (! (oid_bytes[i] & 0x80 )) n++; }
832
833         *subids_p = subids = ep_alloc(sizeof(guint32)*n);
834         subid_overflow = subids+n;
835
836         for (i=0; i<oid_len; i++){
837                 guint8 byte = oid_bytes[i];
838
839                 subid <<= 7;
840                 subid |= byte & 0x7F;
841
842                 if (byte & 0x80) {
843                         continue;
844                 }
845
846                 if (is_first) {
847                         guint32 subid0 = 0;
848
849                         if (subid >= 40) { subid0++; subid-=40; }
850                         if (subid >= 40) { subid0++; subid-=40; }
851
852                         *subids++ = subid0;
853
854                         is_first = FALSE;
855                 }
856
857                 if( subids >= subid_overflow || subid > 0xffffffff) {
858                         *subids_p=NULL;
859                         return 0;
860                 }
861
862                 *subids++ = (guint32)subid;
863                 subid = 0;
864         }
865
866         return n;
867 }
868
869 oid_info_t* oid_get(guint len, guint32* subids, guint* matched, guint* left) {
870         oid_info_t* curr_oid = &oid_root;
871         guint i;
872
873         if(!(subids && *subids <= 2)) {
874                 *matched = 0;
875                 *left = len;
876                 return curr_oid;
877         }
878
879         for( i=0; i < len; i++) {
880                 oid_info_t* next_oid = emem_tree_lookup32(curr_oid->children,subids[i]);
881                 if (next_oid) {
882                         curr_oid = next_oid;
883                 } else {
884                         goto done;
885                 }
886         }
887 done:
888         *matched = i;
889         *left = len - i;
890         return curr_oid;
891 }
892
893
894 oid_info_t* oid_get_from_encoded(const guint8 *bytes, gint byteslen, guint32** subids_p, guint* matched_p, guint* left_p) {
895         guint subids_len = oid_encoded2subid(bytes, byteslen, subids_p);
896         return oid_get(subids_len, *subids_p, matched_p, left_p);
897 }
898
899 oid_info_t* oid_get_from_string(const gchar *oid_str, guint32** subids_p, guint* matched, guint* left) {
900         guint subids_len = oid_string2subid(oid_str, subids_p);
901         return oid_get(subids_len, *subids_p, matched, left);
902 }
903
904 const gchar *oid_resolved_from_encoded(const guint8 *oid, gint oid_len) {
905         guint32 *subid_oid;
906         guint subid_oid_length = oid_encoded2subid(oid, oid_len, &subid_oid);
907
908         return oid_resolved(subid_oid_length, subid_oid);
909 }
910
911
912 guint oid_subid2encoded(guint subids_len, guint32* subids, guint8** bytes_p) {
913         guint bytelen = 0;
914         guint i;
915         guint32 subid;
916         guint8* bytes;
917         guint8* b;
918
919         if ( !subids || subids_len <= 0) {
920                 *bytes_p = NULL;
921                 return 0;
922         }
923
924         subid = (subids[0] * 40) + subids[1];
925         i = 2;
926
927         do {
928                 if (subid <= 0x0000007F) {
929                         bytelen += 1;
930                 } else if (subid <= 0x00003FFF ) {
931                         bytelen += 2;
932                 } else if (subid <= 0x001FFFFF ) {
933                         bytelen += 3;
934                 } else if (subid <= 0x0FFFFFFF ) {
935                         bytelen += 4;
936                 } else {
937                         bytelen += 5;
938                 }
939
940                         subid = subids[i];
941         } while ( i++ < subids_len );
942
943         *bytes_p = b = bytes = ep_alloc(bytelen);
944
945         subid = (subids[0] * 40) + subids[1];
946         i = 2;
947
948         do {
949                 guint len;
950
951                 if ((subid <= 0x0000007F )) len = 1;
952                 else if ((subid <= 0x00003FFF )) len = 2;
953                 else if ((subid <= 0x001FFFFF )) len = 3;
954                 else if ((subid <= 0x0FFFFFFF )) len = 4;
955                 else len = 5;
956
957                 switch(len) {
958                         default: *bytes_p=NULL; return 0;
959                         case 5: *(b++) = ((subid & 0xF0000000) << 28) | 0x80;
960                         case 4: *(b++) = ((subid & 0x0FE00000 ) >> 21)  | 0x80;
961                         case 3: *(b++) = ((subid & 0x001FC000 ) >> 14)  | 0x80;
962                         case 2: *(b++) = ((subid & 0x00003F10 ) >> 7)  | 0x80;
963                         case 1: *(b++) =  subid & 0x0000007F ; break;
964                 }
965
966                 subid = subids[i];
967         } while ( i++ < subids_len);
968
969         return bytelen;
970 }
971
972 const gchar* oid_encoded2string(const guint8* encoded, guint len) {
973         guint32* subids;
974         guint subids_len = oid_encoded2subid(encoded, len, &subids);
975
976         if (subids_len) {
977                 return oid_subid2string(subids,subids_len);
978         } else {
979                 return "";
980         }
981 }
982
983
984
985 guint oid_string2encoded(const char *oid_str, guint8 **bytes) {
986         guint32* subids;
987         guint32 subids_len;
988         guint byteslen;
989
990                 if ( ( subids_len = oid_string2subid(oid_str, &subids) )
991                          &&
992                          ( byteslen = oid_subid2encoded(subids_len, subids, bytes) )  ) {
993                         return byteslen;
994                 }
995         return 0;
996 }
997
998 char* oid2str(oid_info_t* oid, guint32* subids, guint len, guint left) {
999         if (left == 0) {
1000                 return oid->name;
1001         } else {
1002                 return ep_strdup_printf("%s.%s",oid->name,oid_subid2string(subids+(len-left),left));
1003         }
1004 }
1005
1006 const gchar *oid_resolved_from_string(const gchar *oid_str) {
1007         guint32 *subid_oid;
1008         guint subid_oid_length = oid_string2subid(oid_str, &subid_oid);
1009
1010         return oid_resolved(subid_oid_length, subid_oid);
1011 }
1012
1013 const gchar *oid_resolved(guint32 num_subids, guint32* subids) {
1014         guint matched;
1015         guint left;
1016         oid_info_t* oid;
1017
1018         if(! (subids && *subids <= 2 ))
1019                 return "*** Malformed OID ***";
1020
1021         oid = oid_get(num_subids, subids, &matched, &left);
1022
1023         while (! oid->name ) {
1024                 if (!(oid = oid->parent)) {
1025                         return oid_subid2string(subids,num_subids);
1026                 }
1027                 left++;
1028                 matched--;
1029         }
1030
1031         if (left) {
1032                 return ep_strdup_printf("%s.%s",
1033                                         oid->name ? oid->name : oid_subid2string(subids,matched),
1034                                         oid_subid2string(&(subids[matched]),left));
1035         } else {
1036                 return oid->name ? oid->name : oid_subid2string(subids,matched);
1037         }
1038 }
1039
1040 extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p) {
1041         *resolved_p = (void*)oid_resolved(oid_len,subids);
1042         *numeric_p = (void*)oid_subid2string(subids,oid_len);
1043 }
1044
1045 extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p) {
1046         guint32* subids;
1047         guint subids_len = oid_encoded2subid(oid, oid_len, &subids);
1048         *resolved_p = (void*)oid_resolved(subids_len,subids);
1049         *numeric_p = (void*)oid_subid2string(subids,subids_len);
1050 }
1051
1052 extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p) {
1053         guint32* subids;
1054         guint subids_len = oid_string2subid(oid_str, &subids);
1055         *resolved_p = (void*)oid_resolved(subids_len,subids);
1056         *numeric_p = (void*)oid_subid2string(subids,subids_len);
1057 }
1058
1059 /**
1060  * Fetch the default OID path.
1061  */
1062 extern gchar *
1063 oid_get_default_mib_path(void) {
1064 #ifdef HAVE_LIBSMI
1065         GString* path_str;
1066         gchar *path_ret;
1067         char *path;
1068         guint i;
1069
1070         path_str = g_string_new("");
1071 #ifdef _WIN32
1072 #define PATH_SEPARATOR ";"
1073         path = get_datafile_path("snmp\\mibs");
1074         g_string_sprintfa(path_str, "%s;", path);
1075         g_free (path);
1076
1077         path = get_persconffile_path("snmp\\mibs", FALSE, FALSE);
1078         g_string_sprintfa(path_str, "%s", path);
1079         g_free (path);
1080 #else
1081 #define PATH_SEPARATOR ":"
1082         path = smiGetPath();
1083         g_string_sprintfa(path_str, "%s", path);
1084         free (path);
1085 #endif
1086
1087         for(i=0;i<num_smi_paths;i++) {
1088                 if (!( smi_paths[i].name && *smi_paths[i].name))
1089                         continue;
1090
1091                 g_string_sprintfa(path_str,PATH_SEPARATOR "%s",smi_paths[i].name);
1092         }
1093
1094         path_ret = path_str->str;
1095         g_string_free(path_str, FALSE);
1096         return path_ret;
1097 #else /* HAVE_LIBSMI */
1098         return g_strdup("");
1099 #endif
1100 }
1101
1102 #ifdef DEBUG_OIDS
1103 char* oid_test_a2b(guint32 num_subids, guint32* subids) {
1104         guint8* sub2enc;
1105         guint8* str2enc;
1106         guint32* enc2sub;
1107         guint32* str2sub;
1108         const char* sub2str = oid_subid2string(subids, num_subids);
1109         guint sub2enc_len = oid_subid2encoded(num_subids, subids,&sub2enc);
1110         guint enc2sub_len = oid_encoded2subid(sub2enc, sub2enc_len, &enc2sub);
1111         const char* enc2str = oid_encoded2string(sub2enc, sub2enc_len);
1112         guint str2enc_len = oid_string2encoded(sub2str,&str2enc);
1113         guint str2sub_len = oid_string2subid(sub2str,&str2sub);
1114
1115         return ep_strdup_printf(
1116                                                         "oid_subid2string=%s \n"
1117                                                         "oid_subid2encoded=[%d]%s \n"
1118                                                         "oid_encoded2subid=%s \n "
1119                                                         "oid_encoded2string=%s \n"
1120                                                         "oid_string2encoded=[%d]%s \n"
1121                                                         "oid_string2subid=%s \n "
1122                                                         ,sub2str
1123                                                         ,sub2enc_len,bytestring_to_str(sub2enc, sub2enc_len, ':')
1124                                                         ,enc2sub ? oid_subid2string(enc2sub,enc2sub_len) : "-"
1125                                                         ,enc2str
1126                                                         ,str2enc_len,bytestring_to_str(str2enc, str2enc_len, ':')
1127                                                         ,str2sub ? oid_subid2string(str2sub,str2sub_len) : "-"
1128                                                         );
1129 }
1130
1131 void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree) {
1132         static const char* oid_kinds[] = { "Unknown", "Node", "Scalar", "Table", "Row", "Column", "Notification", "Group", "Compliance", "Capabilities"};
1133         static const char* key_types[] = {"OID_KEY_TYPE_WRONG","OID_KEY_TYPE_INTEGER",
1134                                                                                 "OID_KEY_TYPE_FIXED_STRING","OID_KEY_TYPE_FIXED_BYTES","OID_KEY_TYPE_STRING",
1135                                                                                 "OID_KEY_TYPE_BYTES","OID_KEY_TYPE_NSAP","OID_KEY_TYPE_OID","OID_KEY_TYPE_IPADDR"};
1136         proto_item* pi = proto_tree_add_text(tree,NULL,0,0,
1137         "OidInfo: Name='%s' sub-id=%u  kind=%s  hfid=%d",
1138         oid_info->name ? oid_info->name : "",
1139         oid_info->subid,
1140         oid_info->kind <= OID_KIND_CAPABILITIES ? oid_kinds[oid_info->kind] : "BROKEN",
1141         oid_info->value_hfid);
1142         proto_tree* pt = proto_item_add_subtree(pi,0);
1143         oid_key_t* key;
1144
1145         for(key = oid_info->key; key; key = key->next) {
1146                 proto_tree_add_text(pt,NULL,0,0,
1147                 "Key: name='%s' num_subids=%d type=%s",
1148                 key->name,
1149                 key->key_type <= OID_KEY_TYPE_IPADDR ? key_types[key->key_type] : "BROKEN"
1150                 );
1151         };
1152
1153         if (oid_info->parent) {
1154                 pi = proto_tree_add_text(pt,NULL,0,0,"Parent:");
1155                 pt = proto_item_add_subtree(pi,0);
1156                 add_oid_debug_subtree(oid_info->parent, pt);
1157         }
1158 }
1159 #endif
1160
1161 /*
1162  * Editor modelines
1163  *
1164  * Local Variables:
1165  * c-basic-offset: 8
1166  * tab-width: 8
1167  * indent-tabs-mode: tabs
1168  * End:
1169  *
1170  * ex: set shiftwidth=8 tabstop=8 noexpandtab
1171  * :indentSize=8:tabSize=8:noTabs=false:
1172  */
1173