1 /* $OpenBSD: mib.y,v 1.2 2024/02/20 12:41:13 martijn Exp $ */
2
3 /*
4 * Copyright (c) 2023 Martijn van Duren <martijn@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 %{
20
21 #include <sys/tree.h>
22
23 #include <assert.h>
24 #include <ber.h>
25 #include <ctype.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <inttypes.h>
29 #include <limits.h>
30 #include <stdarg.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <strings.h>
34 #include <time.h>
35
36 #include "log.h"
37 #include "mib.h"
38
39 /* RFC2578 section 3.1 */
40 #define DESCRIPTOR_MAX 64
41
42 /* Values from real life testing, could be adjusted */
43 #define ITEM_MAX DESCRIPTOR_MAX
44 #define MODULENAME_MAX 64
45 #define SYMBOLS_MAX 256
46 #define IMPORTS_MAX 16
47 #define TEXT_MAX 16384
48
49 #ifndef nitems
50 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
51 #endif
52
53 struct objidcomponent {
54 enum {
55 OCT_DESCRIPTOR,
56 OCT_NUMBER,
57 OCT_NAMEANDNUMBER
58 } type;
59 uint32_t number;
60 char name[DESCRIPTOR_MAX + 1];
61 };
62
63 struct oid_unresolved {
64 /* Unusual to have long lists of unresolved components */
65 struct objidcomponent bo_id[16];
66 size_t bo_n;
67 };
68
69 struct oid_resolved {
70 uint32_t *bo_id;
71 size_t bo_n;
72 };
73
74 enum status {
75 CURRENT,
76 DEPRECATED,
77 OBSOLETE
78 };
79
80 enum access {
81 NOTACCESSIBLE,
82 ACCESSIBLEFORNOTIFY,
83 READONLY,
84 READWRITE,
85 READCREATE
86 };
87
88 struct objectidentity {
89 enum status status;
90 char *description;
91 char *reference;
92 };
93
94 struct objecttype {
95 void *syntax;
96 char *units;
97 enum access maxaccess;
98 enum status status;
99 char *description;
100 char *reference;
101 void *index;
102 void *defval;
103 };
104
105 struct notificationtype {
106 void *objects;
107 enum status status;
108 char *description;
109 char *reference;
110 };
111
112 struct textualconvention {
113 char *displayhint;
114 enum status status;
115 char *description;
116 char *reference;
117 void *syntax;
118 };
119
120 struct item {
121 char name[DESCRIPTOR_MAX + 1];
122 enum item_type {
123 IT_OID,
124 IT_MACRO,
125 IT_MODULE_IDENTITY,
126 IT_OBJECT_IDENTITY,
127 IT_APPLICATIONSYNTAX,
128 IT_OBJECT_TYPE,
129 IT_NOTIFICATION_TYPE,
130 IT_TEXTUAL_CONVENTION,
131 IT_OBJECT_GROUP,
132 IT_NOTIFICATION_GROUP,
133 IT_MODULE_COMPLIANCE,
134 IT_AGENT_CAPABITIES
135 } type;
136 int resolved;
137 struct module *module;
138
139 union {
140 struct oid_unresolved *oid_unresolved;
141 struct oid_resolved oid;
142 };
143
144 union {
145 struct objectidentity objectidentity;
146 struct objecttype objecttype;
147 struct notificationtype notificationtype;
148 struct textualconvention textualconvention;
149 };
150
151 /* Global case insensitive */
152 RB_ENTRY(item) entrygci;
153 /* Module case insensitive */
154 RB_ENTRY(item) entryci;
155 /* Module case sensitive */
156 RB_ENTRY(item) entrycs;
157 /* Global oid */
158 RB_ENTRY(item) entry;
159 };
160
161 struct import_symbol {
162 char name[DESCRIPTOR_MAX + 1];
163 struct item *item;
164 };
165
166 struct import {
167 char name[MODULENAME_MAX + 1];
168 struct module *module;
169 struct import_symbol symbols[SYMBOLS_MAX];
170 size_t nsymbols;
171 };
172
173 static struct module {
174 char name[MODULENAME_MAX + 1];
175 int8_t resolved;
176
177 time_t lastupdated;
178
179 struct import *imports;
180
181 RB_HEAD(itemscs, item) itemscs;
182 RB_HEAD(itemsci, item) itemsci;
183
184 RB_ENTRY(module) entryci;
185 RB_ENTRY(module) entrycs;
186 } *module;
187
188 int yylex(void);
189 static void yyerror(const char *, ...)
190 __attribute__((__format__ (printf, 1, 2)));
191 void mib_defaults(void);
192 void mib_modulefree(struct module *);
193 int mib_imports_add(char *, char **);
194 int mib_oid_append(struct oid_unresolved *,
195 const struct objidcomponent *);
196 int mib_macro(const char *);
197 int mib_oid_concat(struct oid_unresolved *,
198 const struct oid_unresolved *);
199 struct item *mib_item(const char *, enum item_type);
200 int mib_item_oid(struct item *,
201 const struct oid_unresolved *);
202 int mib_macro(const char *);
203 int mib_applicationsyntax(const char *);
204 struct item *mib_oid(const char *, const struct oid_unresolved *);
205 int mib_moduleidentity(const char *, time_t, const char *,
206 const char *, const char *, const struct oid_unresolved *);
207 int mib_objectidentity(const char *, enum status, const char *,
208 const char *, const struct oid_unresolved *);
209 int mib_objecttype(const char *, void *, const char *,
210 enum access, enum status, const char *, const char *,
211 void *, void *, const struct oid_unresolved *);
212 int mib_notificationtype(const char *, void *, enum status,
213 const char *, const char *, const struct oid_unresolved *);
214 int mib_textualconvetion(const char *, const char *, enum status,
215 const char *, const char *, void *);
216 int mib_objectgroup(const char *, void *, enum status,
217 const char *, const char *, const struct oid_unresolved *);
218 int mib_notificationgroup(const char *, void *, enum status,
219 const char *, const char *, const struct oid_unresolved *);
220 int mib_modulecompliance(const char *, enum status, const char *,
221 const char *, void *, const struct oid_unresolved *);
222 struct item *mib_item_find(struct item *, const char *);
223 struct item *mib_item_parent(struct ber_oid *);
224 int mib_resolve_oid(struct oid_resolved *,
225 struct oid_unresolved *, struct item *);
226 int mib_resolve_item(struct item *);
227 int mib_resolve_module(struct module *);
228 int module_cmp_cs(struct module *, struct module *);
229 int module_cmp_ci(struct module *, struct module *);
230 int item_cmp_cs(struct item *, struct item *);
231 int item_cmp_ci(struct item *, struct item *);
232 int item_cmp_oid(struct item *, struct item *);
233
234 RB_HEAD(modulesci, module) modulesci = RB_INITIALIZER(&modulesci);
235 RB_HEAD(modulescs, module) modulescs = RB_INITIALIZER(&modulescs);
236 RB_HEAD(items, item) items = RB_INITIALIZER(&items);
237 RB_HEAD(itemsgci, item) itemsci = RB_INITIALIZER(&itemsci);
238 /*
239 * Use case sensitive matching internally (for resolving IMPORTS) and
240 * case sensitive matching, followed by case insensitive matching
241 * for end-user resolving (e.g. mib_string2oid()).
242 * It shouldn't happen there's case-based overlap in module/item names,
243 * but allow all to be resolved in case there is.
244 */
245 RB_PROTOTYPE_STATIC(modulesci, module, entryci, module_cmp_ci);
246 RB_PROTOTYPE_STATIC(modulescs, module, entrycs, module_cmp_cs);
247 /*
248 * mib_string2oid() should match case insensitive on:
249 * <module>::<descriptor>
250 * <descriptor>
251 */
252 RB_PROTOTYPE_STATIC(itemsgci, item, entrygci, item_cmp_ci);
253 RB_PROTOTYPE_STATIC(itemsci, item, entryci, item_cmp_ci);
254 RB_PROTOTYPE_STATIC(itemscs, item, entrycs, item_cmp_cs);
255 RB_PROTOTYPE_STATIC(items, item, entry, item_cmp_oid);
256
257 struct file {
258 FILE *stream;
259 const char *name;
260 size_t lineno;
261 enum {
262 FILE_UNDEFINED,
263 FILE_ASN1,
264 FILE_SMI2
265 } state;
266 } file;
267
268 typedef union {
269 char string[TEXT_MAX];
270 unsigned long long number;
271 long long signednumber;
272 char symbollist[SYMBOLS_MAX][DESCRIPTOR_MAX + 1];
273 struct objidcomponent objidcomponent;
274 struct oid_unresolved oid;
275 time_t time;
276 enum status status;
277 enum access access;
278 } YYSTYPE;
279
280 %}
281
282 %token ERROR
283 %token HSTRING BSTRING
284
285 /* RFC2578 section 3.7 */
286 %token ABSENT ACCESS AGENTCAPABILITIES ANY APPLICATION AUGMENTS BEGIN
287 %token BIT BITS BOOLEAN BY CHOICE COMPONENT COMPONENTS CONTACTINFO
288 %token CREATIONREQUIRES Counter32 Counter64 DEFAULT DEFINED
289 %token DEFINITIONS DEFVAL DESCRIPTION DISPLAYHINT END ENUMERATED
290 %token ENTERPRISE EXPLICIT EXPORTS EXTERNAL FALSE FROM GROUP Gauge32
291 %token IDENTIFIER IMPLICIT IMPLIED IMPORTS INCLUDES INDEX INTEGER
292 %token Integer32 IpAddress LASTUPDATED MANDATORYGROUPS MAX MAXACCESS
293 %token MIN MINACCESS MINUSINFINITY MODULE MODULECOMPLIANCE MODULEIDENTITY
294 %token NOTIFICATIONGROUP NOTIFICATIONTYPE NOTIFICATIONS ASNNULL
295 %token OBJECT OBJECTGROUP OBJECTIDENTITY OBJECTTYPE OBJECTS OCTET OF
296 %token OPTIONAL ORGANIZATION Opaque PLUSINFINITY PRESENT PRIVATE
297 %token PRODUCTRELEASE REAL REFERENCE REVISION SEQUENCE SET SIZE STATUS
298 %token STRING SUPPORTS SYNTAX TAGS TEXTUALCONVENTION TRAPTYPE TRUE
299 %token TimeTicks UNITS UNIVERSAL Unsigned32 VARIABLES VARIATION WITH
300 %token WRITESYNTAX
301
302 /* SMIv2 */
303 %token SNMPv2SMI SNMPv2CONF SNMPv2TC
304
305 /* X.208 */
306 %token PRODUCTION RANGESEPARATOR
307
308 %token <string> typereference identifier TEXT HSTRING BSTRING
309 %token <number> NUMBER
310 %token <signednumber> SIGNEDNUMBER
311 %type <string> moduleidentifier smiv2moduleidentifier
312 %type <import> symbolsfrom
313 %type <symbollist> symbollist
314 %type <string> descriptor symbol
315 %type <objidcomponent>objidcomponentfirst objidcomponent
316 %type <oid> objidcomponentlist objectidentifiervalue
317 %type <string> displaypart referpart unitspart
318 %type <time> lastupdated
319 %type <status> status
320 %type <access> access
321
322 %%
323
324 grammar : /* empty */
325 | grammar module
326 ;
327
328 module : moduleidentifier DEFINITIONS PRODUCTION BEGIN {
329 file.state = FILE_ASN1;
330 module = calloc(1, sizeof(*module));
331 if (module == NULL) {
332 yyerror("malloc");
333 YYERROR;
334 }
335 RB_INIT(&module->itemscs);
336 RB_INIT(&module->itemsci);
337 module->resolved = 0;
338 if (strlcpy(module->name, $1,
339 sizeof(module->name)) >=
340 sizeof(module->name)) {
341 yyerror("module name too long");
342 free(module);
343 YYERROR;
344 }
345 } imports moduleidentity modulebody END {
346 struct module *mprev;
347
348 if ((mprev = RB_INSERT(modulescs, &modulescs,
349 module)) != NULL) {
350 if (module->lastupdated >
351 mprev->lastupdated) {
352 mib_modulefree(mprev);
353 RB_INSERT(modulescs, &modulescs,
354 module);
355 RB_INSERT(modulesci, &modulesci,
356 module);
357 } else
358 mib_modulefree(module);
359 } else
360 RB_INSERT(modulesci, &modulesci, module);
361 module = NULL;
362 }
363 | smiv2moduleidentifier {
364 log_debug("%s: SMIv2 definitions: skipping",
365 file.name);
366 YYACCEPT;
367 }
368 ;
369
370 moduleidentifier : typereference { strlcpy($$, $1, sizeof($$)); }
371 ;
372
373 smiv2moduleidentifier : SNMPv2SMI { strlcpy($$, "SNMPv2-SMI", sizeof($$)); }
374 | SNMPv2CONF { strlcpy($$, "SNMPv2-CONF", sizeof($$)); }
375 | SNMPv2TC { strlcpy($$, "SNMPv2-TC", sizeof($$)); }
376 ;
377
378 modulebody : assignmentlist
379 ;
380
381 imports : IMPORTS importlist ';'
382 ;
383
384 importlist : importlist symbolsfrom
385 | /* start */
386 ;
387
388 symbolsfrom : symbollist FROM moduleidentifier {
389 size_t i;
390 char *symbols[SYMBOLS_MAX];
391
392 for (i = 0; $1[i][0] != '\0'; i++)
393 symbols[i] = $1[i];
394 symbols[i] = NULL;
395
396 if (mib_imports_add($3, symbols) == -1)
397 YYERROR;
398 }
399 | symbollist FROM smiv2moduleidentifier {
400 size_t i;
401 char *symbols[SYMBOLS_MAX];
402
403 for (i = 0; $1[i][0] != '\0'; i++)
404 symbols[i] = $1[i];
405 symbols[i] = NULL;
406
407 if (mib_imports_add($3, symbols) == -1)
408 YYERROR;
409
410 file.state = FILE_SMI2;
411 }
412 ;
413
414 symbollist : symbollist ',' symbol {
415 size_t i;
416 for (i = 0; $1[i][0] != '\0'; i++)
417 strlcpy($$[i], $1[i], sizeof($$[i]));
418 if (i + 1 == nitems($$)) {
419 yyerror("too many symbols from module");
420 YYERROR;
421 }
422 if (strlcpy($$[i], $3, sizeof($$[i])) >=
423 sizeof($$[i])) {
424 yyerror("symbol too long");
425 YYERROR;
426 }
427 $$[i + 1][0] = '\0';
428 }
429 | symbol {
430 if (strlcpy($$[0], $1, sizeof($$[0])) >=
431 sizeof($$[0])) {
432 yyerror("symbol too long");
433 YYERROR;
434 }
435 $$[1][0] = '\0';
436 }
437 ;
438
439 symbol : typereference { strlcpy($$, $1, sizeof($$)); }
440 | descriptor { strlcpy($$, $1, sizeof($$)); }
441 /* SNMPv2-SMI */
442 | MODULEIDENTITY {
443 strlcpy($$, "MODULE-IDENTITY", sizeof($$));
444 }
445 | OBJECTIDENTITY {
446 strlcpy($$, "OBJECT-IDENTITY", sizeof($$));
447 }
448 | Integer32 { strlcpy($$, "Integer32", sizeof($$)); }
449 | IpAddress { strlcpy($$, "IpAddress", sizeof($$)); }
450 | Counter32 { strlcpy($$, "Counter32", sizeof($$)); }
451 | Gauge32 { strlcpy($$, "Gauge32", sizeof($$)); }
452 | Unsigned32 { strlcpy($$, "Unsigned32", sizeof($$)); }
453 | TimeTicks { strlcpy($$, "TimeTicks", sizeof($$)); }
454 | Opaque { strlcpy($$, "Opaque", sizeof($$)); }
455 | Counter64 { strlcpy($$, "Counter64", sizeof($$)); }
456 | OBJECTTYPE { strlcpy($$, "OBJECT-TYPE", sizeof($$)); }
457 | NOTIFICATIONTYPE {
458 strlcpy($$, "NOTIFICATION-TYPE", sizeof($$));
459 }
460 /* SNMPv2-TC */
461 | TEXTUALCONVENTION {
462 strlcpy($$, "TEXTUAL-CONVENTION", sizeof($$));
463 }
464 /* SNMPv2-CONF */
465 | OBJECTGROUP {
466 strlcpy($$, "OBJECT-GROUP", sizeof($$));
467 }
468 | NOTIFICATIONGROUP {
469 strlcpy($$, "NOTIFICATION-GROUP", sizeof($$));
470 }
471 | MODULECOMPLIANCE {
472 strlcpy($$, "MODULE-COMPLIANCE", sizeof($$));
473 }
474 | AGENTCAPABILITIES {
475 strlcpy($$, "AGENT-CAPABILITIES", sizeof($$));
476 }
477 ;
478
479 descriptor : identifier {
480 if (strlen($1) > DESCRIPTOR_MAX) {
481 yyerror("descriptor too long");
482 YYERROR;
483 }
484 strlcpy($$, $1, sizeof($$));
485 }
486 ;
487
488 moduleidentity : descriptor MODULEIDENTITY lastupdated
489 ORGANIZATION TEXT CONTACTINFO TEXT DESCRIPTION TEXT
490 revisionpart PRODUCTION objectidentifiervalue {
491 if (mib_moduleidentity(
492 $1, $3, $5, $7, $9, &$12) == -1)
493 YYERROR;
494 }
495 ;
496
497 lastupdated : LASTUPDATED TEXT {
498 char timebuf[14] = "";
499 struct tm tm = {};
500 size_t len;
501
502 if ((len = strlen($2)) == 11)
503 snprintf(timebuf, sizeof(timebuf),
504 "19%s", $2);
505 else if (len == 13)
506 strlcpy(timebuf, $2, sizeof(timebuf));
507 else {
508 yyerror("Invalid LAST-UPDATED: %s", $2);
509 YYERROR;
510 }
511
512 if (strptime(timebuf, "%Y%m%d%H%MZ", &tm) == NULL) {
513 yyerror("Invalid LAST-UPDATED: %s", $2);
514 YYERROR;
515 }
516
517 if (($$ = mktime(&tm)) == -1) {
518 yyerror("Invalid LAST-UPDATED: %s", $2);
519 YYERROR;
520 }
521 }
522 ;
523
524 revisionpart : revisions
525 | /* empty */
526 ;
527
528 revisions : revision
529 | revisions revision
530 ;
531
532 revision : REVISION TEXT DESCRIPTION TEXT
533 ;
534
535 assignmentlist : assignment assignmentlist
536 | /* empty */
537 ;
538
539 assignment : descriptor OBJECT IDENTIFIER PRODUCTION
540 objectidentifiervalue {
541 if (mib_oid($1, &$5) == NULL)
542 YYERROR;
543 }
544 | descriptor OBJECTIDENTITY STATUS status
545 DESCRIPTION TEXT referpart PRODUCTION
546 objectidentifiervalue {
547 const char *reference;
548
549 reference = $7[0] == '\0' ? NULL : $7;
550
551 if (mib_objectidentity($1, $4, $6, reference,
552 &$9) == -1)
553 YYERROR;
554 }
555 | descriptor OBJECTTYPE SYNTAX syntax unitspart
556 MAXACCESS access STATUS status DESCRIPTION TEXT
557 referpart indexpart defvalpart PRODUCTION
558 objectidentifiervalue {
559 const char *units, *reference;
560
561 units = $5[0] == '\0' ? NULL : $5;
562 reference = $12[0] == '\0' ? NULL : $12;
563
564 if (mib_objecttype($1, NULL, units, $7, $9, $11,
565 reference, NULL, NULL, &$16) == -1)
566 YYERROR;
567 }
568 | descriptor NOTIFICATIONTYPE objectspart STATUS status
569 DESCRIPTION TEXT referpart PRODUCTION
570 objectidentifiervalue {
571 const char *reference;
572
573 reference = $8[0] == '\0' ? NULL : $8;
574
575 if (mib_notificationtype($1, NULL, $5, $7,
576 reference, &$10) == -1)
577 YYERROR;
578 }
579 | typereference PRODUCTION SEQUENCE '{' entries '}' {
580 /* Table entry, ignore for now */
581 }
582 | typereference PRODUCTION TEXTUALCONVENTION displaypart
583 STATUS status DESCRIPTION TEXT referpart SYNTAX syntax {
584 const char *displayhint, *reference;
585
586 displayhint = $4[0] == '\0' ? NULL : $4;
587 reference = $9[0] == '\0' ? NULL : $9;
588
589 if (mib_textualconvetion($1, displayhint, $6,
590 $8, reference, NULL) == -1)
591 YYERROR;
592 }
593 | descriptor MODULECOMPLIANCE STATUS status
594 DESCRIPTION TEXT referpart compliancemodulepart
595 PRODUCTION objectidentifiervalue {
596 const char *reference;
597
598 reference = $7[0] == '\0' ? NULL : $7;
599
600 if (mib_modulecompliance($1, $4, $6, reference,
601 NULL, &$10) == -1)
602 YYERROR;
603 }
604 | descriptor OBJECTGROUP objectspart STATUS status
605 DESCRIPTION TEXT referpart PRODUCTION
606 objectidentifiervalue {
607 const char *reference;
608
609 reference = $8[0] == '\0' ? NULL : $8;
610
611 if (mib_objectgroup($1, NULL, $5, $7, reference,
612 &$10) == -1)
613 YYERROR;
614 }
615 | descriptor NOTIFICATIONGROUP notificationspart
616 STATUS status DESCRIPTION TEXT referpart PRODUCTION
617 objectidentifiervalue {
618 const char *reference;
619
620 reference = $8[0] == '\0' ? NULL : $8;
621
622 if (mib_notificationgroup($1, NULL, $5, $7, reference,
623 &$10) == -1)
624 YYERROR;
625 }
626 | typereference PRODUCTION syntax
627 ;
628
629 notificationspart : NOTIFICATIONS '{' notifications '}'
630 ;
631
632 notifications : notification
633 | notification ',' notifications
634 ;
635
636 notification : descriptor
637 ;
638
639 objectspart : OBJECTS '{' objects '}'
640 | /* empty */
641 ;
642
643 objects : object
644 | objects ',' object
645 ;
646
647 object : descriptor
648 ;
649
650 syntax : type
651 | SEQUENCE OF typereference
652 | integersubtype
653 | octetstringsubtype
654 | enumeration
655 | bits
656 ;
657
658 unitspart : UNITS TEXT {
659 strlcpy($$, $2, sizeof($$));
660 }
661 | /* empty */ {
662 $$[0] = '\0';
663 }
664 ;
665
666 referpart : REFERENCE TEXT {
667 strlcpy($$, $2, sizeof($$));
668 }
669 | /* empty */ {
670 $$[0] = '\0';
671 }
672 ;
673
674 indexpart : INDEX '{' indextypes '}'
675 | AUGMENTS '{' descriptor '}'
676 | /* empty */
677 ;
678
679 indextypes : indextype
680 | indextypes ',' indextype
681 ;
682
683 indextype : IMPLIED index
684 | index
685 ;
686
687 index : descriptor
688 ;
689
690 defvalpart : DEFVAL '{' defvalue '}'
691 | /* empty */
692 ;
693
694 defvalue : descriptor
695 | NUMBER
696 | SIGNEDNUMBER
697 | HSTRING
698 | TEXT
699 | bitsvalue
700 | objectidentifiervalue
701 ;
702
703 /* single-value and empty are covered by objectidentifiervalue */
704 bitsvalue : '{' bitscomponentlist '}'
705 ;
706
707 bitscomponentlist : bitscomponentlist ',' bitscomponent
708 | bitscomponent
709 | /* empty */
710 ;
711
712 bitscomponent : identifier
713 ;
714
715 displaypart : DISPLAYHINT TEXT {
716 strlcpy($$, $2, sizeof($$));
717 }
718 | /* empty */ {
719 $$[0] = '\0';
720 }
721 ;
722
723 entries : entry ',' entries
724 | entry
725 ;
726
727 entry : descriptor syntax
728 ;
729
730 compliancemodulepart : compliancemodules
731 ;
732
733 compliancemodules : compliancemodule
734 | compliancemodules compliancemodule
735 ;
736
737 compliancemodule : MODULE modulename modulemandatorypart
738 modulecompliancepart
739 ;
740
741 modulename : moduleidentifier
742 | /* empty */
743 ;
744
745 modulemandatorypart : MANDATORYGROUPS '{' modulegroups '}'
746 | /* empty */
747 ;
748
749 modulegroups : modulegroup
750 | modulegroups ',' modulegroup
751 ;
752
753 modulegroup : objectidentifiervalue
754 | descriptor
755 ;
756
757 modulecompliancepart : modulecompliances
758 | /* empty */
759 ;
760
761 modulecompliances : modulecompliance
762 | modulecompliances modulecompliance
763 ;
764
765 modulecompliance : modulecompliancegroup
766 | moduleobject
767 ;
768
769 modulecompliancegroup : GROUP modulegroupobjectname DESCRIPTION TEXT
770 ;
771
772 moduleobject : OBJECT moduleobjectname modulesyntaxpart
773 writesyntaxpart moduleaccesspart DESCRIPTION TEXT
774 ;
775
776 moduleobjectname : objectidentifiervalue
777 | descriptor
778 ;
779
780 modulegroupobjectname : objectidentifiervalue
781 | descriptor
782 ;
783
784 modulesyntaxpart : SYNTAX syntax
785 | /* empty */
786 ;
787
788 writesyntaxpart : WRITESYNTAX syntax
789 | /* empty */
790 ;
791
792 moduleaccesspart : MINACCESS access
793 | /* empty */
794 ;
795
796 /*
797 * An OBJECT IDENTIFIER needs at least 2 components and are needed to
798 * distinguish from BITS, which can have 0 elements and only differentiate by a
799 * comma separator.
800 */
801 objectidentifiervalue : '{' objidcomponentfirst objidcomponent
802 objidcomponentlist '}' {
803 $$.bo_n = 0;
804
805 if ($3.type == OCT_DESCRIPTOR) {
806 yyerror("only first component of "
807 "OBJECT IDENTIFIER can be a "
808 "descriptor");
809 YYERROR;
810 }
811 if (mib_oid_append(&$$, &$2) == -1)
812 YYERROR;
813 if (mib_oid_append(&$$, &$3) == -1)
814 YYERROR;
815 if (mib_oid_concat(&$$, &$4) == -1)
816 YYERROR;
817 }
818 ;
819
820 objidcomponentlist : objidcomponent objidcomponentlist {
821 if ($1.type == OCT_DESCRIPTOR) {
822 yyerror("only first component of "
823 "OBJECT IDENTIFIER can be a "
824 "descriptor");
825 YYERROR;
826 }
827
828 $$.bo_n = 0;
829 if (mib_oid_append(&$$, &$1) == -1)
830 YYERROR;
831 if (mib_oid_concat(&$$, &$2) == -1)
832 YYERROR;
833 }
834 | /* empty */ {
835 $$.bo_n = 0;
836 }
837 ;
838
839 objidcomponentfirst : descriptor {
840 $$.type = OCT_DESCRIPTOR;
841 strlcpy($$.name, $1, sizeof($$.name));
842 }
843 | objidcomponent {
844 $$.type = $1.type;
845 $$.number = $1.number;
846 strlcpy($$.name, $1.name, sizeof($$.name));
847 }
848 ;
849
850 objidcomponent : NUMBER {
851 $$.type = OCT_NUMBER;
852 if ($1 > UINT32_MAX) {
853 yyerror("OBJECT IDENTIFIER number "
854 "too large");
855 YYERROR;
856 }
857 $$.number = $1;
858 $$.name[0] = '\0';
859 }
860 | descriptor '(' NUMBER ')' {
861 $$.type = OCT_NAMEANDNUMBER;
862 if ($3 > UINT32_MAX) {
863 yyerror("OBJECT IDENTIFIER number "
864 "too large");
865 YYERROR;
866 }
867 $$.number = $3;
868 strlcpy($$.name, $1, sizeof($$.name));
869 }
870 ;
871
872 type : typereference
873 | INTEGER
874 | OBJECT IDENTIFIER
875 | OCTET STRING
876 | Integer32
877 | IpAddress
878 | Counter32
879 | Gauge32
880 | Unsigned32
881 | TimeTicks
882 | Opaque
883 | Counter64
884 | BITS
885 ;
886
887 integersubtype : INTEGER '(' ranges ')'
888 | Integer32 '(' ranges ')'
889 | Unsigned32 '(' ranges ')'
890 | Gauge32 '(' ranges ')'
891 | typereference '(' ranges ')'
892 ;
893
894 octetstringsubtype : OCTET STRING '(' SIZE '(' ranges ')' ')'
895 | Opaque '(' SIZE '(' ranges ')' ')'
896 | typereference '(' SIZE '(' ranges ')' ')'
897 ;
898
899 bits : BITS '{' namedbits '}'
900 ;
901
902 namedbits : namedbit
903 | namedbits ',' namedbit
904 ;
905
906 namedbit : identifier '(' NUMBER ')'
907 ;
908
909 enumeration : INTEGER '{' namednumbers '}'
910 | typereference '{' namednumbers '}'
911 ;
912
913 namednumbers : namednumber
914 | namednumbers ',' namednumber
915 ;
916
917 namednumber : identifier '(' NUMBER ')'
918 | identifier '(' SIGNEDNUMBER ')'
919 ;
920
921 ranges : range '|' ranges
922 | range
923 ;
924
925 range : value
926 | value RANGESEPARATOR value
927 ;
928
929 value : SIGNEDNUMBER
930 | NUMBER
931 | HSTRING
932 | BSTRING
933 ;
934
935 access : descriptor {
936 if (strcmp($1, "not-accessible") == 0)
937 $$ = NOTACCESSIBLE;
938 else if (
939 strcmp($1, "accessible-for-notify") == 0)
940 $$ = ACCESSIBLEFORNOTIFY;
941 else if (strcmp($1, "read-only") == 0)
942 $$ = READONLY;
943 else if (strcmp($1, "read-write") == 0)
944 $$ = READWRITE;
945 else if (strcmp($1, "read-create") == 0)
946 $$ = READCREATE;
947 else {
948 yyerror("invalid access");
949 YYERROR;
950 }
951 }
952 ;
953
954 status : descriptor {
955 if (strcmp($1, "current") == 0)
956 $$ = CURRENT;
957 else if (strcmp($1, "deprecated") == 0)
958 $$ = DEPRECATED;
959 else if (strcmp($1, "obsolete") == 0)
960 $$ = OBSOLETE;
961 else {
962 yyerror("invalid status");
963 YYERROR;
964 }
965 }
966 ;
967 %%
968
969 void
970 yyerror(const char *fmt, ...)
971 {
972 va_list ap;
973 char msg[1024] = "";
974
975 if (file.state == FILE_UNDEFINED) {
976 log_debug("%s: not an ASN.1 file: skipping", file.name);
977 return;
978 }
979 if (file.state == FILE_ASN1) {
980 if (strcmp(fmt, "syntax error") == 0) {
981 log_debug("%s: not an SMIv2 file: skipping", file.name);
982 return;
983 }
984 }
985 if (fmt != NULL) {
986 va_start(ap, fmt);
987 vsnprintf(msg, sizeof(msg), fmt, ap);
988 va_end(ap);
989 }
990 log_warnx("%s:%zu: %s", file.name, file.lineno, msg);
991 }
992
993 /*
994 * X.208
995 */
996 int
yylex(void)997 yylex(void)
998 {
999 const struct {
1000 const char *name;
1001 int token;
1002 } keywords[] = {
1003 /* RFC2578 section 3.7 */
1004 { "ABSENT", ABSENT },
1005 { "ACCESS", ACCESS },
1006 { "AGENT-CAPABILITIES", AGENTCAPABILITIES },
1007 { "ANY", ANY },
1008 { "APPLICATION", APPLICATION },
1009 { "AUGMENTS", AUGMENTS },
1010 { "BEGIN", BEGIN },
1011 { "BIT", BIT },
1012 { "BITS", BITS },
1013 { "BOOLEAN", BOOLEAN },
1014 { "BY", BY },
1015 { "CHOICE", CHOICE },
1016 { "COMPONENT", COMPONENT },
1017 { "COMPONENTS", COMPONENTS },
1018 { "CONTACT-INFO", CONTACTINFO },
1019 { "CREATION-REQUIRES", CREATIONREQUIRES },
1020 { "Counter32", Counter32 },
1021 { "Counter64", Counter64 },
1022 { "DEFAULT", DEFAULT },
1023 { "DEFINED", DEFINED },
1024 { "DEFINITIONS", DEFINITIONS },
1025 { "DEFVAL", DEFVAL },
1026 { "DESCRIPTION", DESCRIPTION },
1027 { "DISPLAY-HINT", DISPLAYHINT },
1028 { "END", END },
1029 { "ENUMERATED", ENUMERATED },
1030 { "ENTERPRISE", ENTERPRISE },
1031 { "EXPLICIT", EXPLICIT },
1032 { "EXPORTS", EXPORTS },
1033 { "EXTERNAL", EXTERNAL },
1034 { "FALSE", FALSE },
1035 { "FROM", FROM },
1036 { "GROUP", GROUP },
1037 { "Gauge32", Gauge32 },
1038 { "IDENTIFIER", IDENTIFIER },
1039 { "IMPLICIT", IMPLICIT },
1040 { "IMPLIED", IMPLIED },
1041 { "IMPORTS", IMPORTS },
1042 { "INCLUDES", INCLUDES },
1043 { "INDEX", INDEX },
1044 { "INTEGER", INTEGER },
1045 { "Integer32", Integer32 },
1046 { "IpAddress", IpAddress },
1047 { "LAST-UPDATED", LASTUPDATED },
1048 { "MANDATORY-GROUPS", MANDATORYGROUPS },
1049 { "MAX", MAX },
1050 { "MAX-ACCESS", MAXACCESS },
1051 { "MIN", MIN },
1052 { "MIN-ACCESS", MINACCESS },
1053 { "MINUS-INFINITY", MINUSINFINITY },
1054 { "MODULE", MODULE },
1055 { "MODULE-COMPLIANCE", MODULECOMPLIANCE },
1056 { "MODULE-IDENTITY", MODULEIDENTITY },
1057 { "NOTIFICATION-GROUP", NOTIFICATIONGROUP },
1058 { "NOTIFICATION-TYPE", NOTIFICATIONTYPE },
1059 { "NOTIFICATIONS", NOTIFICATIONS },
1060 { "NULL", ASNNULL },
1061 { "OBJECT", OBJECT },
1062 { "OBJECT-GROUP", OBJECTGROUP },
1063 { "OBJECT-IDENTITY", OBJECTIDENTITY },
1064 { "OBJECT-TYPE", OBJECTTYPE },
1065 { "OBJECTS", OBJECTS },
1066 { "OCTET", OCTET },
1067 { "OF", OF },
1068 { "OPTIONAL", OPTIONAL },
1069 { "ORGANIZATION", ORGANIZATION },
1070 { "Opaque", Opaque },
1071 { "PLUS-INFINITY", PLUSINFINITY },
1072 { "PRESENT", PRESENT },
1073 { "PRIVATE", PRIVATE },
1074 { "PRODUCT-RELEASE", PRODUCTRELEASE },
1075 { "REAL", REAL },
1076 { "REFERENCE", REFERENCE },
1077 { "REVISION", REVISION },
1078 { "SEQUENCE", SEQUENCE },
1079 { "SET", SET },
1080 { "SIZE", SIZE },
1081 { "STATUS", STATUS },
1082 { "STRING", STRING },
1083 { "SUPPORTS", SUPPORTS },
1084 { "SYNTAX", SYNTAX },
1085 { "TAGS", TAGS },
1086 { "TEXTUAL-CONVENTION", TEXTUALCONVENTION },
1087 { "TRAP-TYPE", TRAPTYPE },
1088 { "TRUE", TRUE },
1089 { "TimeTicks", TimeTicks },
1090 { "UNITS", UNITS },
1091 { "UNIVERSAL", UNIVERSAL },
1092 { "Unsigned32", Unsigned32 },
1093 { "VARIABLES", VARIABLES },
1094 { "VARIATION", VARIATION },
1095 { "WITH", WITH },
1096 { "WRITE-SYNTAX", WRITESYNTAX },
1097
1098 /* ASN.1 */
1099 { "::=", PRODUCTION },
1100 { "..", RANGESEPARATOR },
1101
1102 /* SMIv2 */
1103 { "SNMPv2-SMI", SNMPv2SMI },
1104 { "SNMPv2-CONF", SNMPv2CONF },
1105 { "SNMPv2-TC", SNMPv2TC },
1106
1107 {}
1108 };
1109 char buf[TEXT_MAX];
1110 size_t i = 0, j;
1111 int c, comment = 0;
1112 const char *errstr;
1113 char *endptr;
1114
1115 while ((c = fgetc(file.stream)) != EOF) {
1116 if (i == sizeof(buf)) {
1117 yyerror("token too large");
1118 return ERROR;
1119 }
1120 if (i > 0 && buf[0] == '"') {
1121 if (c == '"') {
1122 buf[i] = '\0';
1123 (void)strlcpy(yylval.string, buf + 1,
1124 sizeof(yylval.string));
1125 return TEXT;
1126 }
1127 if (c == '\n')
1128 file.lineno++;
1129 buf[i++] = c;
1130 continue;
1131 }
1132 if (comment) {
1133 if (c == '-') {
1134 if (++comment == 3)
1135 comment = 0;
1136 } else if (c == '\n') {
1137 file.lineno++;
1138 comment = 0;
1139 } else
1140 comment = 1;
1141 continue;
1142 }
1143 if (c == '\n') {
1144 if (i != 0) {
1145 if (buf[i - 1] == '\r') {
1146 i--;
1147 if (i == 0) {
1148 file.lineno++;
1149 continue;
1150 }
1151 }
1152 ungetc(c, file.stream);
1153 goto token;
1154 }
1155 file.lineno++;
1156 continue;
1157 }
1158 if (c == ' ' || c == '\t') {
1159 if (i == 0)
1160 continue;
1161 goto token;
1162 }
1163 if (c == '.' || c == ':') {
1164 if (i > 0 && buf[0] != '.' && buf[0] != ':') {
1165 ungetc(c, file.stream);
1166 goto token;
1167 }
1168 }
1169 if (i > 0 && (buf[0] == '.' || buf[0] == ':')) {
1170 if (c != '.' && c != ':' && c != '=') {
1171 ungetc(c, file.stream);
1172 goto token;
1173 }
1174 }
1175 if (c == ',' || c == ';' || c == '{' || c == '}' ||
1176 c == '(' || c == ')' || c == '[' || c == ']' || c == '|') {
1177 if (i == 0)
1178 return c;
1179 ungetc(c, file.stream);
1180 goto token;
1181 }
1182 buf[i++] = c;
1183 if (i >= 2) {
1184 if (buf[i - 2] == '-' && buf[i - 1] == '-') {
1185 if (i > 2) {
1186 ungetc('-', file.stream);
1187 ungetc('-', file.stream);
1188 i -= 2;
1189 goto token;
1190 }
1191 comment = 1;
1192 i = 0;
1193 continue;
1194 }
1195 }
1196 }
1197
1198 if (ferror(file.stream)) {
1199 yyerror(NULL);
1200 return ERROR;
1201 }
1202 if (i == 0)
1203 return 0;
1204
1205 token:
1206 buf[i] = '\0';
1207
1208 for (i = 0; keywords[i].name != NULL; i++) {
1209 if (strcmp(keywords[i].name, buf) == 0)
1210 return keywords[i].token;
1211 }
1212
1213 if (isupper(buf[0])) {
1214 for (i = 1; buf[i] != '\0'; i++) {
1215 if (!isalnum(buf[i]) && buf[i] != '-')
1216 break;
1217 }
1218 if (buf[i] == '\0' && buf[i - 1] != '-') {
1219 strlcpy(yylval.string, buf, sizeof(yylval.string));
1220 return typereference;
1221 }
1222 }
1223 if (islower(buf[0])) {
1224 for (i = 1; buf[i] != '\0'; i++) {
1225 if (!isalnum(buf[i]) && buf[i] != '-')
1226 break;
1227 }
1228 if (buf[i] == '\0'&& buf[i - 1] != '-') {
1229 strlcpy(yylval.string, buf, sizeof(yylval.string));
1230 return identifier;
1231 }
1232 }
1233
1234 if (buf[0] == '\'') {
1235 for (i = 1; buf[i] != '\0'; i++)
1236 continue;
1237 if (i < 3 || buf[i - 2] != '\'') {
1238 yyerror("incomplete binary or hexadecimal string");
1239 return ERROR;
1240 }
1241 if (tolower(buf[i - 1]) == 'b') {
1242 for (j = 1; j < i - 2; j++) {
1243 if (buf[j] != '0' && buf[j] != '1') {
1244 yyerror("invalid character in bstring");
1245 return ERROR;
1246 }
1247 }
1248 strlcpy(yylval.string, buf + 1, sizeof(yylval.string));
1249 yylval.string[i - 2] = '\0';
1250 return BSTRING;
1251 } else if (tolower(buf[i - 1]) == 'h') {
1252 for (j = 1; j < i - 2; j++) {
1253 if (!isxdigit(buf[j])) {
1254 yyerror("invalid character in hstring");
1255 return ERROR;
1256 }
1257 }
1258 strlcpy(yylval.string, buf + 1, sizeof(yylval.string));
1259 yylval.string[i - 2] = '\0';
1260 return HSTRING;
1261 }
1262 yyerror("no valid binary or hexadecimal string");
1263 return ERROR;
1264 }
1265 for (i = 0; buf[i] != '\0'; i++) {
1266 if (i == 0 && buf[i] == '-')
1267 continue;
1268 if (!isdigit(buf[i]))
1269 break;
1270 }
1271 if ((i == 1 && isdigit(buf[0])) || i > 1) {
1272 yylval.signednumber =
1273 strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr);
1274 if (errstr != NULL) {
1275 if (errno == ERANGE && isdigit(buf[0])) {
1276 errno = 0;
1277 yylval.number = strtoull(buf, &endptr, 10);
1278 if (errno == 0)
1279 return NUMBER;
1280 }
1281 yyerror("invalid number: %s: %s", buf, errstr);
1282 return ERROR;
1283 }
1284 if (buf[0] == '-')
1285 return SIGNEDNUMBER;
1286 yylval.number = yylval.signednumber;
1287 return NUMBER;
1288 }
1289
1290 yyerror("unknown token: %s", buf);
1291 return ERROR;
1292 }
1293
1294 void
mib_clear(void)1295 mib_clear(void)
1296 {
1297 struct module *m;
1298 struct item *iso;
1299
1300 while ((m = RB_ROOT(&modulesci)) != NULL)
1301 mib_modulefree(m);
1302
1303 /* iso */
1304 iso = RB_ROOT(&items);
1305 assert(strcmp(iso->name, "iso") == 0);
1306 RB_REMOVE(itemsgci, &itemsci, iso);
1307 RB_REMOVE(items, &items, iso);
1308 free(iso->oid.bo_id);
1309 free(iso);
1310 assert(RB_EMPTY(&modulesci));
1311 assert(RB_EMPTY(&modulescs));
1312 assert(RB_EMPTY(&items));
1313 assert(RB_EMPTY(&itemsci));
1314 }
1315
1316 void
mib_modulefree(struct module * m)1317 mib_modulefree(struct module *m)
1318 {
1319 struct item *item;
1320
1321 if (m == NULL)
1322 return;
1323
1324 if (RB_FIND(modulesci, &modulesci, m) == m)
1325 RB_REMOVE(modulesci, &modulesci, m);
1326 if (RB_FIND(modulescs, &modulescs, m) == m)
1327 RB_REMOVE(modulescs, &modulescs, m);
1328 free(m->imports);
1329
1330 while ((item = RB_ROOT(&m->itemscs)) != NULL) {
1331 RB_REMOVE(itemscs, &m->itemscs, item);
1332 if (RB_FIND(itemsci, &m->itemsci, item) == item)
1333 RB_REMOVE(itemsci, &m->itemsci, item);
1334 if (RB_FIND(items, &items, item) == item)
1335 RB_REMOVE(items, &items, item);
1336 if (RB_FIND(itemsgci, &itemsci, item) == item)
1337 RB_REMOVE(itemsgci, &itemsci, item);
1338 if (!item->resolved)
1339 free(item->oid_unresolved);
1340 else
1341 free(item->oid.bo_id);
1342 free(item);
1343 }
1344
1345 free(m);
1346 }
1347
1348 int
mib_imports_add(char * name,char ** symbols)1349 mib_imports_add(char *name, char **symbols)
1350 {
1351 size_t im, ism, isi;
1352 struct import *import;
1353
1354 for (im = 0; module->imports != NULL &&
1355 module->imports[im].name[0] != '\0'; im++) {
1356 if (strcmp(module->imports[im].name, name) == 0)
1357 break;
1358 }
1359 if (module->imports == NULL || module->imports[im].name[0] == '\0') {
1360 if ((import = reallocarray(module->imports, im + 2,
1361 sizeof(*module->imports))) == NULL) {
1362 yyerror("malloc");
1363 return -1;
1364 }
1365 module->imports = import;
1366 strlcpy(module->imports[im].name, name,
1367 sizeof(module->imports[im].name));
1368 module->imports[im].nsymbols = 0;
1369
1370 module->imports[im + 1].name[0] = '\0';
1371 }
1372
1373 import = &module->imports[im];
1374 for (isi = 0; symbols[isi] != NULL; isi++) {
1375 for (ism = 0; ism < import->nsymbols; ism++) {
1376 if (strcmp(symbols[isi],
1377 import->symbols[ism].name) == 0) {
1378 yyerror("symbol %s already imported",
1379 symbols[isi]);
1380 break;
1381 }
1382 }
1383 if (ism != import->nsymbols)
1384 continue;
1385
1386 if (import->nsymbols == nitems(import->symbols)) {
1387 yyerror("Too many symbols imported");
1388 return -1;
1389 }
1390 strlcpy(import->symbols[ism].name, symbols[isi],
1391 sizeof(import->symbols[ism].name));
1392 import->symbols[ism].item = NULL;
1393 import->nsymbols++;
1394 }
1395 return 0;
1396 }
1397
1398 int
mib_oid_append(struct oid_unresolved * oid,const struct objidcomponent * subid)1399 mib_oid_append(struct oid_unresolved *oid, const struct objidcomponent *subid)
1400 {
1401 if (oid->bo_n == nitems(oid->bo_id)) {
1402 yyerror("oid too long");
1403 return -1;
1404 }
1405
1406 switch (oid->bo_id[oid->bo_n].type = subid->type) {
1407 case OCT_DESCRIPTOR:
1408 strlcpy(oid->bo_id[oid->bo_n].name, subid->name,
1409 sizeof(oid->bo_id[oid->bo_n].name));
1410 break;
1411 case OCT_NUMBER:
1412 oid->bo_id[oid->bo_n].number = subid->number;
1413 break;
1414 case OCT_NAMEANDNUMBER:
1415 oid->bo_id[oid->bo_n].number = subid->number;
1416 strlcpy(oid->bo_id[oid->bo_n].name, subid->name,
1417 sizeof(oid->bo_id[oid->bo_n].name));
1418 }
1419 oid->bo_n++;
1420 return 0;
1421 }
1422
1423 int
mib_oid_concat(struct oid_unresolved * dst,const struct oid_unresolved * src)1424 mib_oid_concat(struct oid_unresolved *dst, const struct oid_unresolved *src)
1425 {
1426 size_t i;
1427
1428 for (i = 0; i < src->bo_n; i++)
1429 if (mib_oid_append(dst, &src->bo_id[i]) == -1)
1430 return -1;
1431 return 0;
1432 }
1433
1434 struct item *
mib_item(const char * name,enum item_type type)1435 mib_item(const char *name, enum item_type type)
1436 {
1437 struct item *item;
1438
1439 if ((item = calloc(1, sizeof(*item))) == NULL) {
1440 log_warn("malloc");
1441 return NULL;
1442 }
1443
1444 item->type = type;
1445 item->resolved = 0;
1446 item->module = module;
1447 (void)strlcpy(item->name, name, sizeof(item->name));
1448
1449 if (RB_INSERT(itemscs, &module->itemscs, item) != NULL) {
1450 yyerror("duplicate item %s", name);
1451 free(item);
1452 return NULL;
1453 }
1454
1455 return item;
1456 }
1457
1458 int
mib_item_oid(struct item * item,const struct oid_unresolved * oid)1459 mib_item_oid(struct item *item, const struct oid_unresolved *oid)
1460 {
1461 if ((item->oid_unresolved = calloc(1,
1462 sizeof(*item->oid_unresolved))) == NULL) {
1463 yyerror("malloc");
1464 return -1;
1465 }
1466
1467 *item->oid_unresolved = *oid;
1468 return 0;
1469 }
1470
1471 int
mib_macro(const char * name)1472 mib_macro(const char *name)
1473 {
1474 return mib_item(name, IT_MACRO) == NULL ? -1 : 0;
1475 }
1476
1477 struct item *
mib_oid(const char * name,const struct oid_unresolved * oid)1478 mib_oid(const char *name, const struct oid_unresolved *oid)
1479 {
1480 struct item *item;
1481
1482 if ((item = mib_item(name, IT_OID)) == NULL)
1483 return NULL;
1484
1485 if (mib_item_oid(item, oid) == -1)
1486 return NULL;
1487 return item;
1488 }
1489
1490 int
mib_applicationsyntax(const char * name)1491 mib_applicationsyntax(const char *name)
1492 {
1493 return mib_item(name, IT_APPLICATIONSYNTAX) == NULL ? -1 : 0;
1494 }
1495
1496 int
mib_moduleidentity(const char * name,time_t lastupdated,const char * organization,const char * contactinfo,const char * description,const struct oid_unresolved * oid)1497 mib_moduleidentity(const char *name, time_t lastupdated,
1498 const char *organization, const char *contactinfo, const char *description,
1499 const struct oid_unresolved *oid)
1500 {
1501 struct item *item;
1502
1503 if ((item = mib_item(name, IT_MODULE_IDENTITY)) == NULL)
1504 return -1;
1505
1506 if (mib_item_oid(item, oid) == -1)
1507 return -1;
1508
1509 module->lastupdated = lastupdated;
1510 return 0;
1511 }
1512
1513 int
mib_objectidentity(const char * name,enum status status,const char * description,const char * reference,const struct oid_unresolved * oid)1514 mib_objectidentity(const char *name, enum status status,
1515 const char *description, const char *reference,
1516 const struct oid_unresolved *oid)
1517 {
1518 struct item *item;
1519
1520 if ((item = mib_item(name, IT_OBJECT_IDENTITY)) == NULL)
1521 return -1;
1522
1523 item->objectidentity.status = status;
1524 if (mib_item_oid(item, oid) == -1)
1525 return -1;
1526
1527 return 0;
1528 }
1529
1530 int
mib_objecttype(const char * name,void * syntax,const char * units,enum access maxaccess,enum status status,const char * description,const char * reference,void * index,void * defval,const struct oid_unresolved * oid)1531 mib_objecttype(const char *name, void *syntax, const char *units,
1532 enum access maxaccess, enum status status, const char *description,
1533 const char *reference, void *index, void *defval,
1534 const struct oid_unresolved *oid)
1535 {
1536 struct item *item;
1537
1538 if ((item = mib_item(name, IT_OBJECT_TYPE)) == NULL)
1539 return -1;
1540
1541 item->objecttype.maxaccess = maxaccess;
1542 item->objecttype.status = status;
1543 if (mib_item_oid(item, oid) == -1)
1544 return -1;
1545 return 0;
1546 }
1547
1548 int
mib_notificationtype(const char * name,void * objects,enum status status,const char * description,const char * reference,const struct oid_unresolved * oid)1549 mib_notificationtype(const char *name, void *objects, enum status status,
1550 const char *description, const char *reference,
1551 const struct oid_unresolved *oid)
1552 {
1553 struct item *item;
1554
1555 if ((item = mib_item(name, IT_NOTIFICATION_TYPE)) == NULL)
1556 return -1;
1557
1558 item->notificationtype.status = status;
1559 if (mib_item_oid(item, oid) == -1)
1560 return -1;
1561 return 0;
1562 }
1563
1564 int
mib_textualconvetion(const char * name,const char * displayhint,enum status status,const char * description,const char * reference,void * syntax)1565 mib_textualconvetion(const char *name, const char *displayhint,
1566 enum status status, const char *description, const char *reference,
1567 void *syntax)
1568 {
1569 struct item *item;
1570
1571 if ((item = mib_item(name, IT_TEXTUAL_CONVENTION)) == NULL)
1572 return -1;
1573 item->textualconvention.status = status;
1574 return 0;
1575 }
1576
1577 int
mib_objectgroup(const char * name,void * objects,enum status status,const char * description,const char * reference,const struct oid_unresolved * oid)1578 mib_objectgroup(const char *name, void *objects, enum status status,
1579 const char *description, const char *reference,
1580 const struct oid_unresolved *oid)
1581 {
1582 struct item *item;
1583
1584 if ((item = mib_item(name, IT_OBJECT_GROUP)) == NULL)
1585 return -1;
1586
1587 if (mib_item_oid(item, oid) == -1)
1588 return -1;
1589 return 0;
1590 }
1591
1592 int
mib_notificationgroup(const char * name,void * notifications,enum status status,const char * description,const char * reference,const struct oid_unresolved * oid)1593 mib_notificationgroup(const char *name, void *notifications, enum status status,
1594 const char *description, const char *reference,
1595 const struct oid_unresolved *oid)
1596 {
1597 struct item *item;
1598
1599 if ((item = mib_item(name, IT_NOTIFICATION_GROUP)) == NULL)
1600 return -1;
1601
1602 if (mib_item_oid(item, oid) == -1)
1603 return -1;
1604 return 0;
1605 }
1606
1607 int
mib_modulecompliance(const char * name,enum status status,const char * description,const char * reference,void * mods,const struct oid_unresolved * oid)1608 mib_modulecompliance(const char *name, enum status status,
1609 const char *description, const char *reference, void *mods,
1610 const struct oid_unresolved *oid)
1611 {
1612 struct item *item;
1613
1614 if ((item = mib_item(name, IT_MODULE_COMPLIANCE)) == NULL)
1615 return -1;
1616
1617 if (mib_item_oid(item, oid) == -1)
1618 return -1;
1619 return 0;
1620 }
1621
1622 void
mib_parsefile(const char * path)1623 mib_parsefile(const char *path)
1624 {
1625 mib_defaults();
1626
1627 log_debug("mib parsing %s", path);
1628 if ((file.stream = fopen(path, "r")) == NULL) {
1629 log_warn("fopen");
1630 return;
1631 }
1632 file.lineno = 1;
1633 file.name = path;
1634 file.state = FILE_UNDEFINED;
1635
1636 if (yyparse() != 0) {
1637 mib_modulefree(module);
1638 module = NULL;
1639 }
1640
1641 fclose(file.stream);
1642 }
1643
1644 void
mib_parsedir(const char * path)1645 mib_parsedir(const char *path)
1646 {
1647 DIR *dir;
1648 struct dirent *dirent;
1649 char mibfile[PATH_MAX];
1650
1651 if ((dir = opendir(path)) == NULL) {
1652 log_warn("opendir(%s)", path);
1653 return;
1654 }
1655
1656 errno = 0;
1657 while ((dirent = readdir(dir)) != NULL) {
1658 if (dirent->d_name[0] == '.')
1659 continue;
1660 if (snprintf(mibfile, sizeof(mibfile), "%s/%s",
1661 path, dirent->d_name) >= (int)sizeof(mibfile))
1662 continue;
1663 if (dirent->d_type == DT_DIR) {
1664 mib_parsedir(mibfile);
1665 continue;
1666 }
1667 if (dirent->d_type != DT_REG)
1668 continue;
1669 mib_parsefile(mibfile);
1670 }
1671
1672 closedir(dir);
1673 }
1674
1675 struct item *
mib_item_parent(struct ber_oid * oid)1676 mib_item_parent(struct ber_oid *oid)
1677 {
1678 struct item *item, search;
1679
1680 search.oid.bo_n = oid->bo_n;
1681 search.oid.bo_id = oid->bo_id;
1682
1683 while (search.oid.bo_n > 0) {
1684 if ((item = RB_FIND(items, &items, &search)) != NULL)
1685 return item;
1686 search.oid.bo_n--;
1687 }
1688 return NULL;
1689 }
1690
1691 const char *
mib_string2oid(const char * str,struct ber_oid * oid)1692 mib_string2oid(const char *str, struct ber_oid *oid)
1693 {
1694 char mname[512], *descriptor, *digits;
1695 struct module *m = NULL, msearch;
1696 struct item *item = NULL, isearch;
1697 struct ber_oid oidbuf;
1698 size_t i;
1699
1700 oid->bo_n = 0;
1701
1702 if (isdigit(str[0])) {
1703 if (ober_string2oid(str, oid) == -1)
1704 return "invalid OID";
1705 return NULL;
1706 }
1707
1708 if (strlcpy(mname, str, sizeof(mname)) >= sizeof(mname))
1709 return "OID name too long";
1710
1711 if ((descriptor = strchr(mname, ':')) != NULL) {
1712 descriptor[0] = '\0';
1713 if (descriptor[1] != ':')
1714 return "module and descriptor must be separated by "
1715 "double colon";
1716 descriptor += 2;
1717 if (strlcpy(msearch.name, mname, sizeof(msearch.name)) >=
1718 sizeof(msearch.name))
1719 return "module not found";
1720 if ((m = RB_FIND(modulescs, &modulescs, &msearch)) == NULL) {
1721 m = RB_FIND(modulesci, &modulesci, &msearch);
1722 if (m == NULL)
1723 return "module not found";
1724 }
1725 } else
1726 descriptor = mname;
1727
1728 if ((digits = strchr(descriptor, '.')) != NULL) {
1729 digits++[0] = '\0';
1730 if (ober_string2oid(digits, &oidbuf) == -1)
1731 return "invalid OID";
1732 } else
1733 oidbuf.bo_n = 0;
1734
1735 if (strlcpy(isearch.name, descriptor, sizeof(isearch.name)) >=
1736 sizeof(isearch.name))
1737 return "descriptor not found";
1738
1739 if (m != NULL) {
1740 item = RB_FIND(itemscs, &m->itemscs, &isearch);
1741 if (item == NULL)
1742 item = RB_FIND(itemsci, &m->itemsci, &isearch);
1743 } else
1744 item = RB_FIND(itemsgci, &itemsci, &isearch);
1745 if (item == NULL)
1746 return "descriptor not found";
1747
1748 if (item->oid.bo_n + oidbuf.bo_n > nitems(oid->bo_id))
1749 return "OID too long";
1750
1751 for (i = 0; i < item->oid.bo_n; i++)
1752 oid->bo_id[oid->bo_n++] = item->oid.bo_id[i];
1753 for (i = 0; i < oidbuf.bo_n; i++)
1754 oid->bo_id[oid->bo_n++] = oidbuf.bo_id[i];
1755
1756 return NULL;
1757 }
1758
1759 char *
mib_oid2string(struct ber_oid * oid,char * buf,size_t buflen,enum mib_oidfmt fmt)1760 mib_oid2string(struct ber_oid *oid, char *buf, size_t buflen,
1761 enum mib_oidfmt fmt)
1762 {
1763 struct item *item;
1764 char digit[11];
1765 size_t i = 0;
1766
1767 buf[0] = '\0';
1768 if (fmt == MIB_OIDSYMBOLIC && (item = mib_item_parent(oid)) != NULL) {
1769 snprintf(buf, buflen, "%s::%s", item->module->name,
1770 item->name);
1771 i = item->oid.bo_n;
1772 }
1773
1774 for (; i < oid->bo_n; i++) {
1775 if (i != 0)
1776 strlcat(buf, ".", buflen);
1777 snprintf(digit, sizeof(digit), "%"PRIu32, oid->bo_id[i]);
1778 strlcat(buf, digit, buflen);
1779 }
1780
1781 return buf;
1782 }
1783
1784 void
mib_defaults(void)1785 mib_defaults(void)
1786 {
1787 struct oid_unresolved oid;
1788 struct item *iso;
1789
1790 if (!RB_EMPTY(&modulesci))
1791 return;
1792
1793 /* ASN.1 constant, not part of a module */
1794 if ((iso = calloc(1, sizeof(*iso))) == NULL)
1795 fatal("malloc");
1796 iso->type = IT_OID;
1797 iso->resolved = 1;
1798 iso->module = NULL;
1799 strlcpy(iso->name, "iso", sizeof(iso->name));
1800 if ((iso->oid.bo_id = calloc(1, sizeof(*iso->oid.bo_id))) == NULL)
1801 fatal("malloc");
1802 iso->oid.bo_id[0] = 1;
1803 iso->oid.bo_n = 1;
1804 RB_INSERT(items, &items, iso);
1805 RB_INSERT(itemsgci, &itemsci, iso);
1806
1807 file.state = FILE_SMI2;
1808 file.lineno = 0;
1809
1810 if ((module = calloc(1, sizeof(*module))) == NULL)
1811 fatal("malloc");
1812 RB_INIT(&module->itemscs);
1813 RB_INIT(&module->itemsci);
1814 module->resolved = 0;
1815
1816 strlcpy(module->name, "SNMPv2-SMI", sizeof(module->name));
1817 file.name = module->name;
1818 oid.bo_id[0].type = oid.bo_id[1].type = OCT_NUMBER;
1819 oid.bo_n = 2;
1820
1821 oid.bo_id[0].number = 1;
1822 oid.bo_id[1].number = 3;
1823 if (mib_oid("org", &oid) == NULL)
1824 exit(1);
1825
1826 oid.bo_id[0].number = oid.bo_id[1].number = 0;
1827 if (mib_oid("zeroDotZero", &oid) == NULL)
1828 exit(1);
1829
1830 oid.bo_id[0].type = OCT_DESCRIPTOR;
1831 strlcpy(oid.bo_id[0].name, "org", sizeof(oid.bo_id[0].name));
1832 oid.bo_id[1].number = 6;
1833 if (mib_oid("dod", &oid) == NULL)
1834 exit(1);
1835
1836 strlcpy(oid.bo_id[0].name, "dod", sizeof(oid.bo_id[0].name));
1837 oid.bo_id[1].number = 1;
1838 if (mib_oid("internet", &oid) == NULL)
1839 exit(1);
1840
1841 strlcpy(oid.bo_id[0].name, "internet", sizeof(oid.bo_id[0].name));
1842 oid.bo_id[1].number = 1;
1843 if (mib_oid("directory", &oid) == NULL)
1844 exit(1);
1845
1846 oid.bo_id[1].number = 2;
1847 if (mib_oid("mgmt", &oid) == NULL)
1848 exit(1);
1849
1850 strlcpy(oid.bo_id[0].name, "mgmt", sizeof(oid.bo_id[0].name));
1851 oid.bo_id[1].number = 1;
1852 if (mib_oid("mib-2", &oid) == NULL)
1853 exit(1);
1854
1855 strlcpy(oid.bo_id[0].name, "mib-2", sizeof(oid.bo_id[0].name));
1856 oid.bo_id[1].number = 10;
1857 if (mib_oid("transmission", &oid) == NULL)
1858 exit(1);
1859
1860 strlcpy(oid.bo_id[0].name, "internet", sizeof(oid.bo_id[0].name));
1861 oid.bo_id[1].number = 3;
1862 if (mib_oid("experimental", &oid) == NULL)
1863 exit(1);
1864
1865 oid.bo_id[1].number = 4;
1866 if (mib_oid("private", &oid) == NULL)
1867 exit(1);
1868
1869 oid.bo_id[1].number = 5;
1870 if (mib_oid("security", &oid) == NULL)
1871 exit(1);
1872
1873 oid.bo_id[1].number = 6;
1874 if (mib_oid("snmpV2", &oid) == NULL)
1875 exit(1);
1876
1877 strlcpy(oid.bo_id[0].name, "private", sizeof(oid.bo_id[0].name));
1878 oid.bo_id[1].number = 1;
1879 if (mib_oid("enterprises", &oid) == NULL)
1880 exit(1);
1881
1882 strlcpy(oid.bo_id[0].name, "snmpV2", sizeof(oid.bo_id[0].name));
1883 oid.bo_id[1].number = 1;
1884 if (mib_oid("snmpDomains", &oid) == NULL)
1885 exit(1);
1886
1887 oid.bo_id[1].number = 2;
1888 if (mib_oid("snmpProxys", &oid) == NULL)
1889 exit(1);
1890
1891 oid.bo_id[1].number = 3;
1892 if (mib_oid("snmpModules", &oid) == NULL)
1893 exit(1);
1894
1895 if (mib_macro("MODULE-IDENTITY") == -1 ||
1896 mib_macro("OBJECT-IDENTITY") == -1 ||
1897 mib_macro("OBJECT-TYPE") == -1 ||
1898 mib_macro("NOTIFICATION-TYPE") == -1)
1899 exit(1);
1900
1901 if (mib_applicationsyntax("Integer32") == -1 ||
1902 mib_applicationsyntax("IpAddress") == -1 ||
1903 mib_applicationsyntax("Counter32") == -1 ||
1904 mib_applicationsyntax("Gauge32") == -1 ||
1905 mib_applicationsyntax("Unsigned32") == -1 ||
1906 mib_applicationsyntax("TimeTicks") == -1 ||
1907 mib_applicationsyntax("Opaque") == -1 ||
1908 mib_applicationsyntax("Counter64") == -1)
1909 exit(1);
1910
1911 RB_INSERT(modulesci, &modulesci, module);
1912 RB_INSERT(modulescs, &modulescs, module);
1913
1914 if ((module = calloc(1, sizeof(*module))) == NULL)
1915 fatal("malloc");
1916 RB_INIT(&module->itemscs);
1917 RB_INIT(&module->itemsci);
1918 module->resolved = 0;
1919
1920 strlcpy(module->name, "SNMPv2-TC", sizeof(module->name));
1921 file.name = module->name;
1922
1923 if (mib_macro("TEXTUAL-CONVENTION") == -1)
1924 exit(1);
1925
1926 if (mib_textualconvetion(
1927 "DisplayString", "255a", CURRENT, "", NULL, NULL) == -1 ||
1928 mib_textualconvetion(
1929 "PhysAddress", "1x:", CURRENT, "", NULL, NULL) == -1 ||
1930 mib_textualconvetion(
1931 "MacAddress", "1x:", CURRENT, "", NULL, NULL) == -1 ||
1932 mib_textualconvetion(
1933 "TruthValue", NULL, CURRENT, "", NULL, NULL) == -1 ||
1934 mib_textualconvetion(
1935 "TestAndIncr", NULL, CURRENT, "", NULL, NULL) == -1 ||
1936 mib_textualconvetion(
1937 "AutonomousType", NULL, CURRENT, "", NULL, NULL) == -1 ||
1938 mib_textualconvetion(
1939 "InstancePointer", NULL, OBSOLETE, "", NULL, NULL) == -1 ||
1940 mib_textualconvetion(
1941 "VariablePointer", NULL, CURRENT, "", NULL, NULL) == -1 ||
1942 mib_textualconvetion(
1943 "RowPointer", NULL, CURRENT, "", NULL, NULL) == -1 ||
1944 mib_textualconvetion(
1945 "RowStatus", NULL, CURRENT, "", NULL, NULL) == -1 ||
1946 mib_textualconvetion(
1947 "TimeStamp", NULL, CURRENT, "", NULL, NULL) == -1 ||
1948 mib_textualconvetion(
1949 "TimeInterval", NULL, CURRENT, "", NULL, NULL) == -1 ||
1950 mib_textualconvetion(
1951 "DateAndTime", NULL, CURRENT, "", NULL, NULL) == -1 ||
1952 mib_textualconvetion(
1953 "StorageType", NULL, CURRENT, "", NULL, NULL) == -1 ||
1954 mib_textualconvetion(
1955 "TDomain", NULL, CURRENT, "", NULL, NULL) == -1 ||
1956 mib_textualconvetion(
1957 "TAddress", NULL, CURRENT, "", NULL, NULL) == -1)
1958 exit(1);
1959
1960 RB_INSERT(modulesci, &modulesci, module);
1961 RB_INSERT(modulescs, &modulescs, module);
1962
1963 if ((module = calloc(1, sizeof(*module))) == NULL)
1964 fatal("malloc");
1965 RB_INIT(&module->itemscs);
1966 RB_INIT(&module->itemsci);
1967 module->resolved = 0;
1968
1969 strlcpy(module->name, "SNMPv2-CONF", sizeof(module->name));
1970 file.name = module->name;
1971
1972 if (mib_macro("OBJECT-GROUP") == -1 ||
1973 mib_macro("NOTIFICATION-GROUP") == -1 ||
1974 mib_macro("MODULE-COMPLIANCE") == -1 ||
1975 mib_macro("AGENT-CAPABILITIES") == -1)
1976 exit(1);
1977
1978 RB_INSERT(modulesci, &modulesci, module);
1979 RB_INSERT(modulescs, &modulescs, module);
1980
1981 module = NULL;
1982 }
1983
1984 /*
1985 * Used only for resolving phase
1986 */
1987 struct item *
mib_item_find(struct item * orig,const char * name)1988 mib_item_find(struct item *orig, const char *name)
1989 {
1990 struct module *m = orig->module;
1991 struct item *item, search;
1992 struct import *import;
1993 size_t i, j;
1994
1995 strlcpy(search.name, name, sizeof(search.name));
1996 if ((item = RB_FIND(itemscs, &m->itemscs, &search)) != NULL) {
1997 if (mib_resolve_item(item) == -1)
1998 return NULL;
1999 return item;
2000 }
2001
2002 for (i = 0; m->imports != NULL && m->imports[i].name[0] != '\0'; i++) {
2003 import = &m->imports[i];
2004 for (j = 0; j < import->nsymbols; j++) {
2005 if (strcmp(name, import->symbols[j].name) == 0)
2006 return import->symbols[j].item;
2007 }
2008 }
2009
2010 log_warnx("%s::%s: item %s not found: disabling",
2011 m->name, orig->name, name);
2012
2013 return NULL;
2014 }
2015
2016 int
mib_resolve_oid(struct oid_resolved * dst,struct oid_unresolved * src,struct item * item)2017 mib_resolve_oid(struct oid_resolved *dst, struct oid_unresolved *src,
2018 struct item *item)
2019 {
2020 struct module *m = item->module;
2021 struct item *reference, search;
2022 struct ber_oid oid;
2023 size_t i, j, bo_n;
2024
2025 oid.bo_n = 0;
2026 for (i = 0; i < src->bo_n; i++) {
2027 switch (src->bo_id[i].type) {
2028 case OCT_DESCRIPTOR:
2029 if ((reference = mib_item_find(item,
2030 src->bo_id[i].name)) == NULL)
2031 return -1;
2032 for (j = 0; j < reference->oid.bo_n; j++)
2033 oid.bo_id[oid.bo_n++] =
2034 reference->oid.bo_id[j];
2035 break;
2036 case OCT_NUMBER:
2037 if (oid.bo_n == nitems(oid.bo_id)) {
2038 log_warnx("%s::%s: OID too long: disabling",
2039 m->name, item->name);
2040 return -1;
2041 }
2042 oid.bo_id[oid.bo_n++] = src->bo_id[i].number;
2043 break;
2044 case OCT_NAMEANDNUMBER:
2045 if (oid.bo_n == nitems(oid.bo_id)) {
2046 log_warnx("%s::%s: OID too long: disabling",
2047 m->name, item->name);
2048 return -1;
2049 }
2050 oid.bo_id[oid.bo_n++] = src->bo_id[i].number;
2051 if (i == src->bo_n - 1) {
2052 if (strcmp(src->bo_id[i].name, item->name) != 0) {
2053 log_warnx("%s::%s: last OBJECT "
2054 "IDENTIFIER component name doesn't "
2055 "match item: disabling", m->name,
2056 item->name);
2057 return -1;
2058 }
2059 break;
2060 }
2061 strlcpy(search.name, src->bo_id[i].name,
2062 sizeof(search.name));
2063 reference = RB_FIND(itemscs, &m->itemscs, &search);
2064 if (reference != NULL) {
2065 search.oid.bo_n = oid.bo_n;
2066 search.oid.bo_id = oid.bo_id;
2067 if (item_cmp_oid(reference, &search) != 0) {
2068 log_warnx("%s::%s: two different OIDs "
2069 "for same descriptor: disabling",
2070 m->name, item->name);
2071 return -1;
2072 }
2073 break;
2074 }
2075
2076 bo_n = src->bo_n;
2077 src->bo_n = i + 1;
2078 module = m;
2079 reference = mib_oid(src->bo_id[i].name, src);
2080 module = NULL;
2081 if (reference == NULL)
2082 return -1;
2083 if (mib_resolve_item(reference) == -1)
2084 return -1;
2085 src->bo_n = bo_n;
2086 break;
2087 }
2088 }
2089
2090 dst->bo_n = oid.bo_n;
2091 if ((dst->bo_id = calloc(dst->bo_n, sizeof(*dst->bo_id))) == NULL) {
2092 log_warn("malloc");
2093 return -1;
2094 }
2095 for (i = 0; i < oid.bo_n; i++)
2096 dst->bo_id[i] = oid.bo_id[i];
2097
2098 return 0;
2099 }
2100
2101 /*
2102 * No recursion protection. Assume MIBs do the right thing
2103 */
2104 int
mib_resolve_item(struct item * item)2105 mib_resolve_item(struct item *item)
2106 {
2107 struct item *prev;
2108 struct oid_resolved oid;
2109
2110 if (item->resolved)
2111 return 0;
2112
2113 item->resolved = 1;
2114
2115 if (item->type == IT_MACRO ||
2116 item->type == IT_APPLICATIONSYNTAX ||
2117 item->type == IT_TEXTUAL_CONVENTION)
2118 return 0;
2119
2120 if (mib_resolve_oid(&oid, item->oid_unresolved, item) == -1)
2121 return -1;
2122 free(item->oid_unresolved);
2123 item->oid = oid;
2124
2125 if ((prev = RB_INSERT(items, &items, item)) != NULL) {
2126 /* Prioritize an OID derived from a MACRO over a plain OID */
2127 if (prev->type == IT_OID && item->type != IT_OID) {
2128 RB_REMOVE(items, &items, prev);
2129 RB_INSERT(items, &items, item);
2130 }
2131 }
2132 RB_INSERT(itemsgci, &itemsci, item);
2133 RB_INSERT(itemsci, &item->module->itemsci, item);
2134
2135 return 0;
2136 }
2137
2138 int
mib_resolve_module(struct module * m)2139 mib_resolve_module(struct module *m)
2140 {
2141 struct module msearch;
2142 struct import *import;
2143 struct import_symbol *symbol;
2144 struct item *item, isearch;
2145 size_t i, j;
2146
2147 if (m->resolved)
2148 return 0;
2149
2150 m->resolved = 1;
2151
2152 for (i = 0; m->imports != NULL && m->imports[i].name[0] != '\0'; i++) {
2153 import = &m->imports[i];
2154 strlcpy(msearch.name, import->name, sizeof(msearch.name));
2155 import->module = RB_FIND(modulescs, &modulescs, &msearch);
2156 if (import->module == NULL ||
2157 mib_resolve_module(import->module) == -1) {
2158 log_warnx("%s: import %s not found: disabling",
2159 m->name, import->name);
2160 goto fail;
2161 }
2162
2163 for (j = 0; j < import->nsymbols; j++) {
2164 symbol = &import->symbols[j];
2165 strlcpy(isearch.name, symbol->name,
2166 sizeof(isearch.name));
2167 symbol->item = RB_FIND(itemscs,
2168 &import->module->itemscs, &isearch);
2169 if (symbol->item == NULL) {
2170 log_warnx("%s: symbol %s not found in %s: "
2171 "disabling", m->name, symbol->name,
2172 import->name);
2173 goto fail;
2174 }
2175 }
2176 }
2177
2178 RB_FOREACH(item, itemscs, &m->itemscs) {
2179 if (mib_resolve_item(item) == -1)
2180 goto fail;
2181 }
2182
2183 free(m->imports);
2184 m->imports = NULL;
2185
2186 return 0;
2187 fail:
2188 mib_modulefree(m);
2189 return -1;
2190 }
2191
2192 void
mib_resolve(void)2193 mib_resolve(void)
2194 {
2195 struct module *m;
2196
2197 mib_defaults();
2198 next:
2199 RB_FOREACH(m, modulescs, &modulescs) {
2200 if (mib_resolve_module(m) == -1) {
2201 /*
2202 * mib_resolve_module can recurse and remove,
2203 * for which RB_FOEACH_SAFE doesn't protect.
2204 */
2205 goto next;
2206 }
2207 }
2208 }
2209
2210 int
module_cmp_cs(struct module * m1,struct module * m2)2211 module_cmp_cs(struct module *m1, struct module *m2)
2212 {
2213 return strcmp(m1->name, m2->name);
2214 }
2215
2216 int
module_cmp_ci(struct module * m1,struct module * m2)2217 module_cmp_ci(struct module *m1, struct module *m2)
2218 {
2219 return strcasecmp(m1->name, m2->name);
2220 }
2221
2222 int
item_cmp_cs(struct item * d1,struct item * d2)2223 item_cmp_cs(struct item *d1, struct item *d2)
2224 {
2225 return strcmp(d1->name, d2->name);
2226 }
2227
2228 int
item_cmp_ci(struct item * d1,struct item * d2)2229 item_cmp_ci(struct item *d1, struct item *d2)
2230 {
2231 return strcasecmp(d1->name, d2->name);
2232 }
2233
2234 int
item_cmp_oid(struct item * i1,struct item * i2)2235 item_cmp_oid(struct item *i1, struct item *i2)
2236 {
2237 size_t i, min;
2238
2239 min = i1->oid.bo_n < i2->oid.bo_n ? i1->oid.bo_n : i2->oid.bo_n;
2240 for (i = 0; i < min; i++) {
2241 if (i1->oid.bo_id[i] < i2->oid.bo_id[i])
2242 return (-1);
2243 if (i1->oid.bo_id[i] > i2->oid.bo_id[i])
2244 return (1);
2245 }
2246 /* i1 is parent of i2 */
2247 if (i1->oid.bo_n < i2->oid.bo_n)
2248 return (-2);
2249 /* i1 is child of i2 */
2250 if (i1->oid.bo_n > i2->oid.bo_n)
2251 return 2;
2252 return (0);
2253 }
2254
2255 RB_GENERATE_STATIC(modulesci, module, entryci, module_cmp_ci);
2256 RB_GENERATE_STATIC(modulescs, module, entrycs, module_cmp_cs);
2257 RB_GENERATE_STATIC(itemsgci, item, entrygci, item_cmp_ci);
2258 RB_GENERATE_STATIC(itemsci, item, entryci, item_cmp_ci);
2259 RB_GENERATE_STATIC(itemscs, item, entrycs, item_cmp_cs);
2260 RB_GENERATE_STATIC(items, item, entry, item_cmp_oid);
2261