Index | Thread | Search

From:
Martijn van Duren <openbsd+tech@list.imperialat.at>
Subject:
snmpd: allow arbitrary string length in mib.y
To:
tech@openbsd.org
Date:
Sun, 19 Oct 2025 17:22:37 +0200

Download raw body.

Thread
  • Martijn van Duren:

    snmpd: allow arbitrary string length in mib.y

Hello,

Right now mib.y operates on text buffers of 16384 bytes. This is more
than enough for the MIB files we have in base, and was based on "this
supports enough MIB files that I'm happy with it for now" and I vaguely
remember hitting some limits when doubling the value, but can't quite
seem to recall where.
However, this limit did mean we use quite large buffers inside the
yacc parser, and still meant we had to drop a few MIB files that can
be found inside librenms' database, because of extremely long
DESCRIPTION sections.

With this diff we can gain the following files from librenms' database
in direct parsing:
- /var/www/librenms/mibs/cisco/CISCO-TC
- /var/www/librenms/mibs/cisco/CISCO-CLASS-BASED-QOS-MIB

We lose the following file because I moved the length checking into
yylex, which means that that identifiers and typereferences are now
checked early, and some variables from before fell through the
cracks. This includes enum labels (see RFC2578 section 7.1.1):
- /var/www/librenms/mibs/fortinet/MERU-TC

Then there's a couple of files who changed motivation, in which I'm
not too interested right now:
- /var/www/librenms/mibs/huawei/HUAWEI-ENTITY-TRAP-MIB
- /var/www/librenms/mibs/huawei/HUAWEI-TC-MIB
- /var/www/librenms/mibs/hp/BLADETYPE2-SWITCH-MIB
  (now can't be parsed instead of missing symbols)
- /var/www/librenms/mibs/cisco/CISCO-SWITCH-ENGINE-MIB
  (incorrect symbol import)
- /var/www/librenms/mibs/adva/CM-FACILITY-MIB
  (IPV6-TC still doesn't parse)
- /var/www/librenms/mibs/comware/HH3C-QOS-CAPABILITY-MIB
  (HH3C-OID-MIB still doesn't parse)
- /var/www/librenms/mibs/nokia/TIMETRA-OAM-TEST-MIB
  (IEEE8021-CFM-MIB still doesn't resolve)
- /var/www/librenms/mibs/nokia/1830/TN-OAM-TEST-MIB
  (IEEE8021-CFM-MIB still doesn't resolve)

With this we gain the following MIBs because they can now resolve all
their symbols:
- CISCO-VTP-MIB
- CISCO-PRIVATE-VLAN-MIB
- CISCO-AUTH-FRAMEWORK-MIB
- CISCO-CONFIG-MAN-MIB
- CISCO-SLB-MIB
- CISCO-ENHANCED-SLB-MIB
- CISCO-ENTITY-DIAG-MIB
- CISCO-ENTITY-EXT-MIB
- CISCO-ENTITY-SENSOR-MIB
- CISCO-ERR-DISABLE-MIB
- CISCO-IF-EXTENSION-MIB
- CISCO-IGMP-SNOOPING-MIB
- CISCO-MEDIA-GATEWAY-MIB
- CISCO-IPSEC-FLOW-MONITOR-MIB
- CISCO-LWAPP-WLAN-MIB
- CISCO-LWAPP-AP-MIB
- CISCO-LWAPP-RF-MIB
- CISCO-MAC-NOTIFICATION-MIB
- CISCO-PAGP-MIB
- CISCO-POWER-ETHERNET-EXT-MIB
- CISCO-PROCESS-MIB
- CISCO-SLB-EXT-MIB
- CISCO-SLB-HEALTH-MON-MIB
- CISCO-SNAPSHOT-MIB
- CISCO-STACKWISE-MIB
- CISCO-STP-EXTENSIONS-MIB
- CISCO-VLAN-IFTABLE-RELATIONSHIP-MIB
- CISCO-VLAN-MEMBERSHIP-MIB
- CISCO-WAN-OPTIMIZATION-MIB

While here also satisfy the includes when building with bison.

OK?

martijn@

diff f5e5829750f6127f5a1dc9c2407b424587303b2a 5b410676d7b6ff40dae953e6a4c1abd8a0ac1c12
commit - f5e5829750f6127f5a1dc9c2407b424587303b2a
commit + 5b410676d7b6ff40dae953e6a4c1abd8a0ac1c12
blob - ae33b64280fbcd9766287f60f2908d08fcfbf7f0
blob + de66c9e27c9bd33f317d0dd75f049004be12ed38
--- usr.sbin/snmpd/mib.y
+++ usr.sbin/snmpd/mib.y
@@ -19,8 +19,10 @@
 %{
 
 #include <sys/tree.h>
+#include <sys/types.h>
 
 #include <assert.h>
+#include <stddef.h>
 #include <ber.h>
 #include <ctype.h>
 #include <dirent.h>
@@ -30,6 +32,8 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <strings.h>
 #include <time.h>
 
@@ -44,12 +48,18 @@
 #define MODULENAME_MAX 64
 #define SYMBOLS_MAX 256
 #define IMPORTS_MAX 16
-#define TEXT_MAX 16384
 
 #ifndef nitems
 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
 #endif
 
+struct text {
+	char			 string[DESCRIPTOR_MAX + 1];
+	char			 file[PATH_MAX];
+	off_t			 start;
+	off_t			 end;
+};
+
 struct objidcomponent {
 	enum {
 		OCT_DESCRIPTOR,
@@ -202,29 +212,38 @@ int		 mib_item_oid(struct item *,
 int		 mib_macro(const char *);
 int		 mib_applicationsyntax(const char *);
 struct item	*mib_oid(const char *, const struct oid_unresolved *);
-int		 mib_moduleidentity(const char *, time_t, const char *,
-		    const char *, const char *, const struct oid_unresolved *);
-int		 mib_objectidentity(const char *, enum status, const char *,
-		    const char *, const struct oid_unresolved *);
-int		 mib_objecttype(const char *, void  *, const char *,
-		    enum access, enum status, const char *, const char *,
-		    void *, void *, const struct oid_unresolved *);
+int		 mib_moduleidentity(const char *, time_t, const struct text *,
+		    const struct text *, const struct text *,
+		    const struct oid_unresolved *);
+int		 mib_objectidentity(const char *, enum status,
+		    const struct text *, const struct text *,
+		    const struct oid_unresolved *);
+int		 mib_objecttype(const char *, void  *, const struct text *,
+		    enum access, enum status, const struct text *,
+		    const struct text *, void *, void *,
+		    const struct oid_unresolved *);
 int		 mib_notificationtype(const char *, void *, enum status,
-		    const char *, const char *, const struct oid_unresolved *);
-int		 mib_textualconvetion(const char *, const char *, enum status,
-		    const char *, const char *, void *);
+		    const struct text *, const struct text *,
+		    const struct oid_unresolved *);
+int		 mib_textualconvetion(const char *, const struct text *,
+		    enum status, const struct text *, const struct text *,
+		    void *);
 int		 mib_objectgroup(const char *, void *, enum status,
-		    const char *, const char *, const struct oid_unresolved *);
+		    const struct text *, const struct text *,
+		    const struct oid_unresolved *);
 int		 mib_notificationgroup(const char *, void *, enum status,
-		    const char *, const char *, const struct oid_unresolved *);
-int		 mib_modulecompliance(const char *, enum status, const char *,
-		    const char *, void *, const struct oid_unresolved *);
+		    const struct text *, const struct text *,
+		    const struct oid_unresolved *);
+int		 mib_modulecompliance(const char *, enum status,
+		    const struct text *, const struct text *, void *,
+		    const struct oid_unresolved *);
 struct item	*mib_item_find(struct item *, const char *);
 struct item	*mib_item_parent(struct ber_oid *);
-int		  mib_resolve_oid(struct oid_resolved *,
+int		 mib_resolve_oid(struct oid_resolved *,
 		    struct oid_unresolved *, struct item *);
 int		 mib_resolve_item(struct item *);
 int		 mib_resolve_module(struct module *);
+char		*text_get(struct text *, int *);
 int		 module_cmp_cs(struct module *, struct module *);
 int		 module_cmp_ci(struct module *, struct module *);
 int		 item_cmp_cs(struct item *, struct item *);
@@ -266,7 +285,7 @@ struct file {
 } file;
 
 typedef union {
-	char			 string[TEXT_MAX];
+	struct text		 text;
 	unsigned long long	 number;
 	long long		 signednumber;
 	char			 symbollist[SYMBOLS_MAX][DESCRIPTOR_MAX + 1];
@@ -280,7 +299,6 @@ typedef union {
 %}
 
 %token	ERROR
-%token	HSTRING BSTRING
 
 /* RFC2578 section 3.7 */
 %token	ABSENT ACCESS AGENTCAPABILITIES ANY APPLICATION AUGMENTS BEGIN
@@ -305,16 +323,16 @@ typedef union {
 /* X.208 */
 %token	PRODUCTION RANGESEPARATOR
 
-%token	<string>	typereference identifier TEXT HSTRING BSTRING
+%token	<text>		typereference identifier TEXT HSTRING BSTRING
 %token	<number>	NUMBER
 %token	<signednumber>	SIGNEDNUMBER
-%type	<string>	moduleidentifier smiv2moduleidentifier
+%type	<text>		moduleidentifier smiv2moduleidentifier
 %type	<import>	symbolsfrom
 %type	<symbollist>	symbollist
-%type	<string>	descriptor symbol
+%type	<text>		descriptor symbol
 %type	<objidcomponent>objidcomponentfirst objidcomponent
 %type	<oid>		objidcomponentlist objectidentifiervalue
-%type	<string>	displaypart referpart unitspart
+%type	<text>		displaypart referpart unitspart
 %type	<time>		lastupdated
 %type	<status>	status
 %type	<access>	access
@@ -335,13 +353,8 @@ module			: moduleidentifier DEFINITIONS PRODUCTION BEG
 				RB_INIT(&module->itemscs);
 				RB_INIT(&module->itemsci);
 				module->resolved = 0;
-				if (strlcpy(module->name, $1,
-				    sizeof(module->name)) >=
-				    sizeof(module->name)) {
-					yyerror("module name too long");
-					free(module);
-					YYERROR;
-				}
+				(void)strlcpy(module->name, $1.string,
+				    sizeof(module->name));
 			} imports moduleidentity modulebody END {
 				struct module *mprev;
 
@@ -367,12 +380,21 @@ module			: moduleidentifier DEFINITIONS PRODUCTION BEG
 			}
 			;
 
-moduleidentifier	: typereference { strlcpy($$, $1, sizeof($$)); }
+moduleidentifier	: typereference { $$ = $1; }
 			;
 
-smiv2moduleidentifier	: SNMPv2SMI { strlcpy($$, "SNMPv2-SMI", sizeof($$)); }
-			| SNMPv2CONF { strlcpy($$, "SNMPv2-CONF", sizeof($$)); }
-			| SNMPv2TC { strlcpy($$, "SNMPv2-TC", sizeof($$)); }
+smiv2moduleidentifier	: SNMPv2SMI {
+				strlcpy($$.string,
+				    "SNMPv2-SMI", sizeof($$.string));
+			}
+			| SNMPv2CONF {
+				strlcpy($$.string,
+				    "SNMPv2-CONF", sizeof($$.string));
+			}
+			| SNMPv2TC {
+				strlcpy($$.string,
+				    "SNMPv2-TC", sizeof($$.string));
+			}
 			;
 
 modulebody		: assignmentlist
@@ -393,7 +415,7 @@ symbolsfrom		: symbollist FROM moduleidentifier {
 					symbols[i] = $1[i];
 				symbols[i] = NULL;
 					
-				if (mib_imports_add($3, symbols) == -1)
+				if (mib_imports_add($3.string, symbols) == -1)
 					YYERROR;
 			}
 			| symbollist FROM smiv2moduleidentifier {
@@ -404,7 +426,7 @@ symbolsfrom		: symbollist FROM moduleidentifier {
 					symbols[i] = $1[i];
 				symbols[i] = NULL;
 					
-				if (mib_imports_add($3, symbols) == -1)
+				if (mib_imports_add($3.string, symbols) == -1)
 					YYERROR;
 
 				file.state = FILE_SMI2;
@@ -419,69 +441,92 @@ symbollist		: symbollist ',' symbol {
 					yyerror("too many symbols from module");
 					YYERROR;
 				}
-				if (strlcpy($$[i], $3, sizeof($$[i])) >=
-				    sizeof($$[i])) {
-					yyerror("symbol too long");
-					YYERROR;
-				}
+				(void)strlcpy($$[i], $3.string, sizeof($$[i]));
 				$$[i + 1][0] = '\0';
 			}
 			| symbol {
-				if (strlcpy($$[0], $1, sizeof($$[0])) >=
-				    sizeof($$[0])) {
-					yyerror("symbol too long");
-					YYERROR;
-				}
+				(void)strlcpy($$[0], $1.string, sizeof($$[0]));
 				$$[1][0] = '\0';
 			}
 			;
 
-symbol			: typereference { strlcpy($$, $1, sizeof($$)); }
-			| descriptor { strlcpy($$, $1, sizeof($$)); }
+symbol			: typereference { $$ = $1; }
+			| descriptor { $$ = $1; }
 			/* SNMPv2-SMI */
 			| MODULEIDENTITY {
-				strlcpy($$, "MODULE-IDENTITY", sizeof($$));
+				(void)strlcpy($$.string,
+				    "MODULE-IDENTITY", sizeof($$.string));
 			}
 			| OBJECTIDENTITY {
-				strlcpy($$, "OBJECT-IDENTITY", sizeof($$));
+				(void)strlcpy($$.string,
+				    "OBJECT-IDENTITY", sizeof($$.string));
 			}
-			| Integer32  { strlcpy($$, "Integer32", sizeof($$)); }
-			| IpAddress { strlcpy($$, "IpAddress", sizeof($$)); }
-			| Counter32 { strlcpy($$, "Counter32", sizeof($$)); }
-			| Gauge32 { strlcpy($$, "Gauge32", sizeof($$)); }
-			| Unsigned32 { strlcpy($$, "Unsigned32", sizeof($$)); }
-			| TimeTicks { strlcpy($$, "TimeTicks", sizeof($$)); }
-			| Opaque { strlcpy($$, "Opaque", sizeof($$)); }
-			| Counter64 { strlcpy($$, "Counter64", sizeof($$)); }
-			| OBJECTTYPE { strlcpy($$, "OBJECT-TYPE", sizeof($$)); }
+			| Integer32  {
+				(void)strlcpy($$.string,
+				    "Integer32", sizeof($$.string));
+			}
+			| IpAddress {
+				(void)strlcpy($$.string,
+					"IpAddress", sizeof($$.string));
+			}
+			| Counter32 {
+				(void)strlcpy($$.string,
+				    "Counter32", sizeof($$.string));
+			}
+			| Gauge32 {
+				(void)strlcpy($$.string,
+				    "Gauge32", sizeof($$.string));
+			}
+			| Unsigned32 {
+				(void)strlcpy($$.string,
+				    "Unsigned32", sizeof($$.string));
+			}
+			| TimeTicks {
+				(void)strlcpy($$.string,
+				    "TimeTicks", sizeof($$.string));
+			}
+			| Opaque {
+				(void)strlcpy($$.string,
+				    "Opaque", sizeof($$.string));
+			}
+			| Counter64 {
+				(void)strlcpy($$.string,
+				    "Counter64", sizeof($$.string));
+			}
+			| OBJECTTYPE {
+				(void)strlcpy($$.string,
+				    "OBJECT-TYPE", sizeof($$.string));
+			}
 			| NOTIFICATIONTYPE {
-				strlcpy($$, "NOTIFICATION-TYPE", sizeof($$));
+				(void)strlcpy($$.string,
+				    "NOTIFICATION-TYPE", sizeof($$.string));
 			}
 			/* SNMPv2-TC */
 			| TEXTUALCONVENTION {
-				strlcpy($$, "TEXTUAL-CONVENTION", sizeof($$));
+				(void)strlcpy($$.string,
+				    "TEXTUAL-CONVENTION", sizeof($$.string));
 			}
 			/* SNMPv2-CONF */
 			| OBJECTGROUP {
-				strlcpy($$, "OBJECT-GROUP", sizeof($$));
+				(void)strlcpy($$.string,
+				    "OBJECT-GROUP", sizeof($$.string));
 			}
 			| NOTIFICATIONGROUP {
-				strlcpy($$, "NOTIFICATION-GROUP", sizeof($$));
+				(void)strlcpy($$.string,
+				    "NOTIFICATION-GROUP", sizeof($$.string));
 			}
 			| MODULECOMPLIANCE {
-				strlcpy($$, "MODULE-COMPLIANCE", sizeof($$));
+				(void)strlcpy($$.string,
+				    "MODULE-COMPLIANCE", sizeof($$.string));
 			}
 			| AGENTCAPABILITIES {
-				strlcpy($$, "AGENT-CAPABILITIES", sizeof($$));
+				(void)strlcpy($$.string,
+				    "AGENT-CAPABILITIES", sizeof($$.string));
 			}
 			;
 
 descriptor		: identifier {
-				if (strlen($1) > DESCRIPTOR_MAX) {
-					yyerror("descriptor too long");
-					YYERROR;
-				}
-				strlcpy($$, $1, sizeof($$));
+				$$ = $1;
 			}
 			;
 
@@ -489,7 +534,7 @@ moduleidentity		: descriptor MODULEIDENTITY lastupdate
 			  ORGANIZATION TEXT CONTACTINFO TEXT DESCRIPTION TEXT
 			  revisionpart PRODUCTION objectidentifiervalue {
 				if (mib_moduleidentity(
-				    $1, $3, $5, $7, $9, &$12) == -1)
+				    $1.string, $3, &$5, &$7, &$9, &$12) == -1)
 					YYERROR;
 			}
 			;
@@ -499,23 +544,27 @@ lastupdated		: LASTUPDATED TEXT {
 				struct tm tm = {};
 				size_t len;
 
-				if ((len = strlen($2)) == 11)
+				if ((len = $2.end - $2.start) == 11)
 					snprintf(timebuf, sizeof(timebuf),
-					    "19%s", $2);
+					    "19%s", $2.string);
 				else if (len == 13)
-					strlcpy(timebuf, $2, sizeof(timebuf));
+					strlcpy(timebuf,
+					    $2.string, sizeof(timebuf));
 				else {
-					yyerror("Invalid LAST-UPDATED: %s", $2);
+					yyerror("Invalid LAST-UPDATED: %s",
+					    $2.string);
 					YYERROR;
 				}
 
 				if (strptime(timebuf, "%Y%m%d%H%MZ", &tm) == NULL) {
-					yyerror("Invalid LAST-UPDATED: %s", $2);
+					yyerror("Invalid LAST-UPDATED: %s",
+					    $2.string);
 					YYERROR;
 				}
 
 				if (($$ = mktime(&tm)) == -1) {
-					yyerror("Invalid LAST-UPDATED: %s", $2);
+					yyerror("Invalid LAST-UPDATED: %s",
+					    $2.string);
 					YYERROR;
 				}
 			}
@@ -538,41 +587,43 @@ assignmentlist		: assignment assignmentlist
 
 assignment		: descriptor OBJECT IDENTIFIER PRODUCTION
 			  objectidentifiervalue {
-				if (mib_oid($1, &$5) == NULL)
+				if (mib_oid($1.string, &$5) == NULL)
 					YYERROR;
 			}
 			| descriptor OBJECTIDENTITY STATUS status
 			  DESCRIPTION TEXT referpart PRODUCTION
 			  objectidentifiervalue {
-				const char *reference;
+				const struct text *reference;
 
-				reference = $7[0] == '\0' ? NULL : $7;
+				reference = $7.string[0] == '\0' ?
+				    NULL : &$7;
 
-				if (mib_objectidentity($1, $4, $6, reference,
-				    &$9) == -1)
+				if (mib_objectidentity($1.string, $4, &$6,
+				    reference, &$9) == -1)
 					YYERROR;
 			}
 			| descriptor OBJECTTYPE SYNTAX syntax unitspart
 			  MAXACCESS access STATUS status DESCRIPTION TEXT
 			  referpart indexpart defvalpart PRODUCTION
 			  objectidentifiervalue {
-				const char *units, *reference;
+				const struct text *units, *reference;
 
-				units = $5[0] == '\0' ? NULL : $5;
-				reference = $12[0] == '\0' ? NULL : $12;
+				units = $5.string[0] == '\0' ? NULL : &$5;
+				reference = $12.string[0] == '\0' ? NULL : &$12;
 
-				if (mib_objecttype($1, NULL, units, $7, $9, $11,
-				    reference, NULL, NULL, &$16) == -1)
+				if (mib_objecttype($1.string, NULL, units, $7,
+				    $9, &$11, reference,
+				    NULL, NULL, &$16) == -1)
 					YYERROR;
 			}
 			| descriptor NOTIFICATIONTYPE objectspart STATUS status
 			  DESCRIPTION TEXT referpart PRODUCTION
 			  objectidentifiervalue {
-				const char *reference;
+				const struct text *reference;
 
-				reference = $8[0] == '\0' ? NULL : $8;
+				reference = $8.string[0] == '\0' ? NULL : &$8;
 
-				if (mib_notificationtype($1, NULL, $5, $7,
+				if (mib_notificationtype($1.string, NULL, $5, &$7,
 				    reference, &$10) == -1)
 					YYERROR;
 			}
@@ -581,46 +632,46 @@ assignment		: descriptor OBJECT IDENTIFIER PRODUCTION
 			}
 			| typereference PRODUCTION TEXTUALCONVENTION displaypart
 			  STATUS status DESCRIPTION TEXT referpart SYNTAX syntax {
-				const char *displayhint, *reference;
+				const struct text *displayhint, *reference;
 
-				displayhint = $4[0] == '\0' ? NULL : $4;
-				reference = $9[0] == '\0' ? NULL : $9;
+				displayhint = $4.string[0] == '\0' ? NULL : &$4;
+				reference = $9.string[0] == '\0' ? NULL : &$9;
 
-				if (mib_textualconvetion($1, displayhint, $6,
-				    $8, reference, NULL) == -1)
+				if (mib_textualconvetion($1.string, displayhint,
+				    $6, &$8, reference, NULL) == -1)
 					YYERROR;
 			}
 			| descriptor MODULECOMPLIANCE STATUS status
 			  DESCRIPTION TEXT referpart compliancemodulepart
 			  PRODUCTION objectidentifiervalue {
-				const char *reference;
+				const struct text *reference;
 
-				reference = $7[0] == '\0' ? NULL : $7;
+				reference = $7.string[0] == '\0' ? NULL : &$7;
 
-				if (mib_modulecompliance($1, $4, $6, reference,
-				    NULL, &$10) == -1)
+				if (mib_modulecompliance($1.string, $4, &$6,
+				    reference, NULL, &$10) == -1)
 					YYERROR;
 			}
 			| descriptor OBJECTGROUP objectspart STATUS status
 			  DESCRIPTION TEXT referpart PRODUCTION
 			  objectidentifiervalue {
-				const char *reference;
+				const struct text *reference;
 
-				reference = $8[0] == '\0' ? NULL : $8;
+				reference = $8.string[0] == '\0' ? NULL : &$8;
 
-				if (mib_objectgroup($1, NULL, $5, $7, reference,
-				    &$10) == -1)
+				if (mib_objectgroup($1.string, NULL, $5, &$7,
+				    reference, &$10) == -1)
 					YYERROR;
 			}
 			| descriptor NOTIFICATIONGROUP notificationspart
 			  STATUS status DESCRIPTION TEXT referpart PRODUCTION
 			  objectidentifiervalue {
-				const char *reference;
+				const struct text *reference;
 
-				reference = $8[0] == '\0' ? NULL : $8;
+				reference = $8.string[0] == '\0' ? NULL : &$8;
 
-				if (mib_notificationgroup($1, NULL, $5, $7, reference,
-				    &$10) == -1)
+				if (mib_notificationgroup($1.string, NULL, $5,
+				    &$7, reference, &$10) == -1)
 					YYERROR;
 			}
 			| typereference PRODUCTION syntax
@@ -656,18 +707,18 @@ syntax			: type
 			;
 
 unitspart		: UNITS TEXT {
-				strlcpy($$, $2, sizeof($$));
+				$$ = $2;
 			}
 			| /* empty */ {
-				$$[0] = '\0';
+				$$ = (struct text){};
 			}
 			;
 
 referpart		: REFERENCE TEXT {
-				strlcpy($$, $2, sizeof($$));
+				$$ = $2;
 			}
 			| /* empty */ {
-				$$[0] = '\0';
+				$$ = (struct text){};
 			}
 			;
 
@@ -713,10 +764,10 @@ bitscomponent		: identifier
 			;
 
 displaypart		: DISPLAYHINT TEXT {
-				strlcpy($$, $2, sizeof($$));
+				$$ = $2;
 			}
 			| /* empty */ {
-				$$[0] = '\0';
+				$$ = (struct text){};
 			}
 			;
 
@@ -838,7 +889,7 @@ objidcomponentlist	: objidcomponent objidcomponentlist
 
 objidcomponentfirst	: descriptor {
 				$$.type = OCT_DESCRIPTOR;
-				strlcpy($$.name, $1, sizeof($$.name));
+				strlcpy($$.name, $1.string, sizeof($$.name));
 			}
 			| objidcomponent {
 				$$.type = $1.type;
@@ -865,7 +916,7 @@ objidcomponent		: NUMBER {
 					YYERROR;
 				}
 				$$.number = $3;
-				strlcpy($$.name, $1, sizeof($$.name));
+				strlcpy($$.name, $1.string, sizeof($$.name));
 			}
 			;
 
@@ -933,16 +984,16 @@ value			: SIGNEDNUMBER
 			;
 
 access			: descriptor {
-				if (strcmp($1, "not-accessible") == 0)
+				if (strcmp($1.string, "not-accessible") == 0)
 					$$ = NOTACCESSIBLE;
-				else if (
-				    strcmp($1, "accessible-for-notify") == 0)
+				else if (strcmp($1.string,
+				    "accessible-for-notify") == 0)
 					$$ = ACCESSIBLEFORNOTIFY;
-				else if (strcmp($1, "read-only") == 0)
+				else if (strcmp($1.string, "read-only") == 0)
 					$$ = READONLY;
-				else if (strcmp($1, "read-write") == 0)
+				else if (strcmp($1.string, "read-write") == 0)
 					$$ = READWRITE;
-				else if (strcmp($1, "read-create") == 0)
+				else if (strcmp($1.string, "read-create") == 0)
 					$$ = READCREATE;
 				else {
 					yyerror("invalid access");
@@ -952,11 +1003,11 @@ access			: descriptor {
 			;
 
 status			: descriptor {
-				if (strcmp($1, "current") == 0)
+				if (strcmp($1.string, "current") == 0)
 					$$ = CURRENT;
-				else if (strcmp($1, "deprecated") == 0)
+				else if (strcmp($1.string, "deprecated") == 0)
 					$$ = DEPRECATED;
-				else if (strcmp($1, "obsolete") == 0)
+				else if (strcmp($1.string, "obsolete") == 0)
 					$$ = OBSOLETE;
 				else {
 					yyerror("invalid status");
@@ -1106,48 +1157,60 @@ yylex(void)
 
 		{}
 	};
-	char buf[TEXT_MAX];
+	struct text text;
+	char lookback[2] = {};
 	size_t i = 0, j;
-	int c, comment = 0;
+	int c, comment = 0, quote = 0;
 	const char *errstr;
-	char *endptr;
+	char *endptr, *buf;
+	int dofree;
 
+	(void)strlcpy(text.file, file.name, sizeof(text.file));
 	while ((c = fgetc(file.stream)) != EOF) {
-		if (i == sizeof(buf)) {
-			yyerror("token too large");
-			return ERROR;
+		if (i == 0) {
+			text.start = ftello(file.stream) - 1;
+			if (c == '"' && !quote) {
+				quote = 1;
+				continue;
+			}
 		}
-		if (i > 0 && buf[0] == '"') {
+		if (quote) {
 			if (c == '"') {
-				buf[i] = '\0';
-				(void)strlcpy(yylval.string, buf + 1,
-				    sizeof(yylval.string));
+				text.end = ftello(file.stream) - 1;
+				yylval.text = text;
 				return TEXT;
 			}
 			if (c == '\n')
 				file.lineno++;
-			buf[i++] = c;
+			if (i < sizeof(text.string) - 1) {
+				text.string[i++] = c;
+				text.string[i] = '\0';
+			}
 			continue;
 		}
 		if (comment) {
 			if (c == '-') {
-				if (++comment == 3)
+				if (++comment == 3) {
 					comment = 0;
+					i = 0;
+				}
 			} else if (c == '\n') {
 				file.lineno++;
 				comment = 0;
+				i = 0;
 			} else
 				comment = 1;
 			continue;
 		}
 		if (c == '\n') {
 			if (i != 0) {
-				if (buf[i - 1] == '\r') {
+				if (text.string[i - 1] == '\r') {
 					i--;
 					if (i == 0) {
 						file.lineno++;
 						continue;
 					}
+					text.string[i] = '\0';
 				}
 				ungetc(c, file.stream);
 				goto token;
@@ -1158,15 +1221,17 @@ yylex(void)
 		if (c == ' ' || c == '\t') {
 			if (i == 0)
 				continue;
+			ungetc(c, file.stream);
 			goto token;
 		}
 		if (c == '.' || c == ':') {
-			if (i > 0 && buf[0] != '.' && buf[0] != ':') {
+			if (i > 0 &&
+			    text.string[0] != '.' && text.string[0] != ':') {
 				ungetc(c, file.stream);
 				goto token;
 			}
 		}
-		if (i > 0 && (buf[0] == '.' || buf[0] == ':')) {
+		if (i > 0 && (text.string[0] == '.' || text.string[0] == ':')) {
 			if (c != '.' && c != ':' && c != '=') {
 				ungetc(c, file.stream);
 				goto token;
@@ -1179,9 +1244,18 @@ yylex(void)
 			ungetc(c, file.stream);
 			goto token;
 		}
-		buf[i++] = c;
+		if (i < sizeof(text.string) - 1) {
+			text.string[i++] = c;
+			text.string[i] = '\0';
+		}
+		if (i < 2)
+			lookback[i] = c;
+		else {
+			lookback[0] = lookback[1];
+			lookback[1] = c;
+		}
 		if (i >= 2) {
-			if (buf[i - 2] == '-' && buf[i - 1] == '-') {
+			if (lookback[0] == '-' && lookback[1] == '-') {
 				if (i > 2) {
 					ungetc('-', file.stream);
 					ungetc('-', file.stream);
@@ -1189,7 +1263,6 @@ yylex(void)
 					goto token;
 				}
 				comment = 1;
-				i = 0;
 				continue;
 			}
 		}
@@ -1199,95 +1272,122 @@ yylex(void)
 		yyerror(NULL);
 		return ERROR;
 	}
-	if (i == 0)
+	if (i == 0 || comment)
 		return 0;
 
  token:
-	buf[i] = '\0';
-
+	text.end = ftello(file.stream);
 	for (i = 0; keywords[i].name != NULL; i++) {
-		if (strcmp(keywords[i].name, buf) == 0)
+		if (strcmp(keywords[i].name, text.string) == 0)
 			return keywords[i].token;
 	}
 
-	if (isupper(buf[0])) {
-		for (i = 1; buf[i] != '\0'; i++) {
-			if (!isalnum(buf[i]) && buf[i] != '-')
+	if (isupper(text.string[0])) {
+		if ((size_t)(text.end - text.start) >= sizeof(text.string)) {
+			yyerror("typereference too long");
+			return ERROR;
+		}
+		for (i = 1; text.string[i] != '\0'; i++) {
+			if (!isalnum(text.string[i]) && text.string[i] != '-')
 				break;
 		}
-		if (buf[i] == '\0' && buf[i - 1] != '-') {
-			strlcpy(yylval.string, buf, sizeof(yylval.string));
+		if (text.string[i] == '\0' && text.string[i - 1] != '-') {
+			yylval.text = text;
 			return typereference;
 		}
 	}
-	if (islower(buf[0])) {
-		for (i = 1; buf[i] != '\0'; i++) {
-			if (!isalnum(buf[i]) && buf[i] != '-')
+	if (islower(text.string[0])) {
+		if ((size_t)(text.end - text.start) >= sizeof(text.string)) {
+			yyerror("identifier too long");
+			return ERROR;
+		}
+		for (i = 1; text.string[i] != '\0'; i++) {
+			if (!isalnum(text.string[i]) && text.string[i] != '-')
 				break;
 		}
-		if (buf[i] == '\0'&& buf[i - 1] != '-') {
-			strlcpy(yylval.string, buf, sizeof(yylval.string));
+		if (text.string[i] == '\0' && text.string[i - 1] != '-') {
+			yylval.text = text;
 			return identifier;
 		}
 	}
 
-	if (buf[0] == '\'') {
-		for (i = 1; buf[i] != '\0'; i++)
-			continue;
+	if (text.string[0] == '\'') {
+		i = text.end - text.start;
+		if ((buf = text_get(&text, &dofree)) == NULL) {
+			yyerror("failed to get full text: %s", strerror(errno));
+			return ERROR;
+		}
 		if (i < 3 || buf[i - 2] != '\'') {
 			yyerror("incomplete binary or hexadecimal string");
 			return ERROR;
 		}
+		buf[i - 2] = '\0';
+		strlcpy(yylval.text.file, text.file, sizeof(yylval.text.file));
+		yylval.text.start = text.start + 1;
+		yylval.text.end = text.end - 2;
+
 		if (tolower(buf[i - 1]) == 'b') {
 			for (j = 1; j < i - 2; j++) {
 				if (buf[j] != '0' && buf[j] != '1') {
 					yyerror("invalid character in bstring");
+					if (dofree)
+						free(buf);
 					return ERROR;
 				}
 			}
-			strlcpy(yylval.string, buf + 1, sizeof(yylval.string));
-			yylval.string[i - 2] = '\0';
+			strlcpy(yylval.text.string, buf + 1,
+			    sizeof(yylval.text.string));
+			if (dofree)
+				free(buf);
 			return BSTRING;
 		} else if (tolower(buf[i - 1]) == 'h') {
 			for (j = 1; j < i - 2; j++) {
 				if (!isxdigit(buf[j])) {
 					yyerror("invalid character in hstring");
+					if (dofree)
+						free(buf);
 					return ERROR;
 				}
 			}
-			strlcpy(yylval.string, buf + 1, sizeof(yylval.string));
-			yylval.string[i - 2] = '\0';
+			strlcpy(yylval.text.string, buf + 1,
+			    sizeof(yylval.text.string));
+			if (dofree)
+				free(buf);
 			return HSTRING;
 		}
 		yyerror("no valid binary or hexadecimal string");
+		if (dofree)
+			free(buf);
 		return ERROR;
 	}
-	for (i = 0; buf[i] != '\0'; i++) {
-		if (i == 0 && buf[i] == '-')
+	for (i = 0; text.string[i] != '\0'; i++) {
+		if (i == 0 && text.string[i] == '-')
 			continue;
-		if (!isdigit(buf[i]))
+		if (!isdigit(text.string[i]))
 			break;
 	}
-	if ((i == 1 && isdigit(buf[0])) || i > 1) {
+	if ((i == 1 && isdigit(text.string[0])) || i > 1) {
+		/* string length check is implicit here */
 		yylval.signednumber =
-		    strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr);
+		    strtonum(text.string, LLONG_MIN, LLONG_MAX, &errstr);
 		if (errstr != NULL) {
-			if (errno == ERANGE && isdigit(buf[0])) {
+			if (errno == ERANGE && isdigit(text.string[0])) {
 				errno = 0;
-				yylval.number = strtoull(buf, &endptr, 10);
+				yylval.number =
+				    strtoull(text.string, &endptr, 10);
 				if (errno == 0)
 					return NUMBER;
 			}
-			yyerror("invalid number: %s: %s", buf, errstr);
+			yyerror("invalid number: %s: %s", text.string, errstr);
 			return ERROR;
 		}
-		if (buf[0] == '-')
+		if (text.string[0] == '-')
 			return SIGNEDNUMBER;
 		yylval.number = yylval.signednumber;
 		return NUMBER;
 	}
 
-	yyerror("unknown token: %s", buf);
+	yyerror("unknown token: %s", text.string);
 	return ERROR;
 }
 
@@ -1495,8 +1595,8 @@ mib_applicationsyntax(const char *name)
 
 int
 mib_moduleidentity(const char *name, time_t lastupdated,
-    const char *organization, const char *contactinfo, const char *description,
-    const struct oid_unresolved *oid)
+    const struct text *organization, const struct text *contactinfo,
+    const struct text *description, const struct oid_unresolved *oid)
 {
 	struct item *item;
 
@@ -1512,7 +1612,7 @@ mib_moduleidentity(const char *name, time_t lastupdate
 
 int
 mib_objectidentity(const char *name, enum status status,
-    const char *description, const char *reference,
+    const struct text *description, const struct text *reference,
     const struct oid_unresolved *oid)
 {
 	struct item *item;
@@ -1528,9 +1628,9 @@ mib_objectidentity(const char *name, enum status statu
 }
 
 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,
+mib_objecttype(const char *name, void *syntax, const struct text *units,
+    enum access maxaccess, enum status status, const struct text *description,
+    const struct text *reference, void *index, void *defval,
     const struct oid_unresolved *oid)
 {
 	struct item *item;
@@ -1547,7 +1647,7 @@ mib_objecttype(const char *name, void *syntax, const c
 
 int
 mib_notificationtype(const char *name, void *objects, enum status status,
-    const char *description, const char *reference,
+    const struct text *description, const struct text *reference,
     const struct oid_unresolved *oid)
 {
 	struct item *item;
@@ -1562,9 +1662,9 @@ mib_notificationtype(const char *name, void *objects, 
 }
 
 int
-mib_textualconvetion(const char *name, const char *displayhint,
-    enum status status, const char *description, const char *reference,
-    void *syntax)
+mib_textualconvetion(const char *name, const struct text *displayhint,
+    enum status status, const struct text *description,
+    const struct text *reference, void *syntax)
 {
 	struct item *item;
 
@@ -1576,7 +1676,7 @@ mib_textualconvetion(const char *name, const char *dis
 
 int
 mib_objectgroup(const char *name, void *objects, enum status status,
-    const char *description, const char *reference,
+    const struct text *description, const struct text *reference,
     const struct oid_unresolved *oid)
 {
 	struct item *item;
@@ -1591,7 +1691,7 @@ mib_objectgroup(const char *name, void *objects, enum 
 
 int
 mib_notificationgroup(const char *name, void *notifications, enum status status,
-    const char *description, const char *reference,
+    const struct text *description, const struct text *reference,
     const struct oid_unresolved *oid)
 {
 	struct item *item;
@@ -1606,7 +1706,7 @@ mib_notificationgroup(const char *name, void *notifica
 
 int
 mib_modulecompliance(const char *name, enum status status,
-    const char *description, const char *reference, void *mods,
+    const struct text *description, const struct text *reference, void *mods,
     const struct oid_unresolved *oid)
 {
 	struct item *item;
@@ -1639,6 +1739,8 @@ mib_parsefile(const char *path)
 	}
 
 	fclose(file.stream);
+	file.name = NULL;
+	file.stream = NULL;
 }
 
 void
@@ -1786,6 +1888,11 @@ mib_defaults(void)
 {
 	struct oid_unresolved oid;
 	struct item *iso;
+	const struct text ds = {
+		.string = "255a"
+	}, x = {
+		.string = "1x:"
+	}, empty = {};
 
 	if (!RB_EMPTY(&modulesci))
 		return;
@@ -1924,37 +2031,37 @@ mib_defaults(void)
 		exit(1);
 
 	if (mib_textualconvetion(
-	    "DisplayString", "255a", CURRENT, "", NULL, NULL) == -1 ||
+	    "DisplayString", &ds, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "PhysAddress", "1x:", CURRENT, "", NULL, NULL) == -1 ||
+	    "PhysAddress", &x, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "MacAddress", "1x:", CURRENT, "", NULL, NULL) == -1 ||
+	    "MacAddress", &x, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "TruthValue", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "TruthValue", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "TestAndIncr", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "TestAndIncr", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "AutonomousType", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "AutonomousType", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "InstancePointer", NULL, OBSOLETE, "", NULL, NULL) == -1 ||
+	    "InstancePointer", NULL, OBSOLETE, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "VariablePointer", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "VariablePointer", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "RowPointer", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "RowPointer", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "RowStatus", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "RowStatus", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "TimeStamp", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "TimeStamp", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "TimeInterval", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "TimeInterval", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "DateAndTime", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "DateAndTime", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "StorageType", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "StorageType", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "TDomain", NULL, CURRENT, "", NULL, NULL) == -1 ||
+	    "TDomain", NULL, CURRENT, &empty, NULL, NULL) == -1 ||
 	    mib_textualconvetion(
-	    "TAddress", NULL, CURRENT, "", NULL, NULL) == -1)
+	    "TAddress", NULL, CURRENT, &empty, NULL, NULL) == -1)
 		exit(1);
 
 	RB_INSERT(modulesci, &modulesci, module);
@@ -2207,6 +2314,50 @@ mib_resolve(void)
 	}
 }
 
+char *
+text_get(struct text *text, int *dofree)
+{
+	off_t curoff;
+	FILE *f;
+	char *buf;
+
+	if ((size_t)(text->end - text->start) < sizeof(text->string)) {
+		*dofree = 0;
+		return text->string;
+	}
+
+	if (file.name != NULL && strcmp(file.name, text->file) == 0) {
+		curoff = ftello(file.stream);
+		f = file.stream;
+	} else {
+		curoff = -1;
+		if ((f = fopen(text->file, "r")) == NULL)
+			return NULL;
+	}
+	fseek(f, text->start, SEEK_SET);
+	if ((buf = malloc((text->end - text->start) + 1)) == NULL) {
+		if (curoff == -1)
+			fclose(f);
+		return NULL;
+	}
+	if (fread(buf, 1, (size_t)(text->end - text->start), f) !=
+	    (size_t)(text->end - text->start)) {
+		if (curoff == -1)
+			fclose(f);
+		free(buf);
+		return NULL;
+	}
+	if (curoff == -1)
+		fclose(f);
+	else
+		fseeko(file.stream, curoff, SEEK_SET);
+	buf[text->end - text->start] = '\0';
+
+	*dofree = 1;
+
+	return buf;
+}
+
 int
 module_cmp_cs(struct module *m1, struct module *m2)
 {
blob - 3882b915ebd85bcac9b41fff40c89a9a2633c88b
blob + 6ec2d878be69600647b4bcc152c63e3798408cd5
--- usr.sbin/snmpd/parse.y
+++ usr.sbin/snmpd/parse.y
@@ -37,6 +37,7 @@
 
 #include <openssl/sha.h>
 
+#include <stddef.h>
 #include <ber.h>
 #include <ctype.h>
 #include <err.h>
@@ -48,7 +49,9 @@
 #include <pwd.h>
 #include <stdarg.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 #include <strings.h>
 #include <syslog.h>
 #include <unistd.h>