xref: /openbsd/usr.sbin/snmpd/mib.y (revision 8539b8ce)
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