xref: /openbsd-src/usr.sbin/snmpd/parse.y (revision ad2d1a44bc433c192a9a3526b4215ecc6d4aea61)
1*ad2d1a44Santon /*	$OpenBSD: parse.y,v 1.91 2024/06/03 06:14:32 anton Exp $	*/
246e6c55bSreyk 
346e6c55bSreyk /*
48ed9427bSreyk  * Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
546e6c55bSreyk  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
646e6c55bSreyk  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
746e6c55bSreyk  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
846e6c55bSreyk  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
946e6c55bSreyk  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
1046e6c55bSreyk  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
1146e6c55bSreyk  *
1246e6c55bSreyk  * Permission to use, copy, modify, and distribute this software for any
1346e6c55bSreyk  * purpose with or without fee is hereby granted, provided that the above
1446e6c55bSreyk  * copyright notice and this permission notice appear in all copies.
1546e6c55bSreyk  *
1646e6c55bSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1746e6c55bSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1846e6c55bSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1946e6c55bSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2046e6c55bSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2146e6c55bSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2246e6c55bSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2346e6c55bSreyk  */
2446e6c55bSreyk 
2546e6c55bSreyk %{
2646e6c55bSreyk #include <sys/stat.h>
2746e6c55bSreyk #include <sys/queue.h>
28a9292d2aSmartijn #include <sys/socket.h>
29a9292d2aSmartijn #include <sys/time.h>
30a9292d2aSmartijn #include <sys/types.h>
31a9292d2aSmartijn #include <sys/un.h>
3260cc2743Smartijn #include <sys/utsname.h>
3346e6c55bSreyk 
3446e6c55bSreyk #include <arpa/inet.h>
3546e6c55bSreyk 
36a9292d2aSmartijn #include <netinet/in.h>
37a9292d2aSmartijn 
3873b5c081Smartijn #include <openssl/sha.h>
3973b5c081Smartijn 
40a9292d2aSmartijn #include <ber.h>
4146e6c55bSreyk #include <ctype.h>
4246e6c55bSreyk #include <err.h>
4346e6c55bSreyk #include <errno.h>
444100cc5fSmartijn #include <grp.h>
45756b4b7aSmartijn #include <inttypes.h>
4646e6c55bSreyk #include <limits.h>
4746e6c55bSreyk #include <netdb.h>
484100cc5fSmartijn #include <pwd.h>
49a9292d2aSmartijn #include <stdarg.h>
50a9292d2aSmartijn #include <stdint.h>
51a9292d2aSmartijn #include <stdio.h>
52a9292d2aSmartijn #include <strings.h>
534a1d3eaaSsthen #include <syslog.h>
54a9292d2aSmartijn #include <unistd.h>
5546e6c55bSreyk 
569352f69fSmartijn #include "application.h"
57a9292d2aSmartijn #include "log.h"
5846e6c55bSreyk #include "mib.h"
59a9292d2aSmartijn #include "snmpd.h"
60a9292d2aSmartijn #include "snmp.h"
6146e6c55bSreyk 
6246e6c55bSreyk TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
6346e6c55bSreyk static struct file {
6446e6c55bSreyk 	TAILQ_ENTRY(file)	 entry;
6546e6c55bSreyk 	FILE			*stream;
6646e6c55bSreyk 	char			*name;
67588ec6bcSdenis 	size_t			 ungetpos;
68588ec6bcSdenis 	size_t			 ungetsize;
69588ec6bcSdenis 	u_char			*ungetbuf;
70588ec6bcSdenis 	int			 eof_reached;
7146e6c55bSreyk 	int			 lineno;
7246e6c55bSreyk 	int			 errors;
735bcdf83cSmpf } *file, *topfile;
7446e6c55bSreyk struct file	*pushfile(const char *, int);
7546e6c55bSreyk int		 popfile(void);
7646e6c55bSreyk int		 check_file_secrecy(int, const char *);
7746e6c55bSreyk int		 yyparse(void);
7846e6c55bSreyk int		 yylex(void);
790f79392cSdoug int		 yyerror(const char *, ...)
800f79392cSdoug     __attribute__((__format__ (printf, 1, 2)))
810f79392cSdoug     __attribute__((__nonnull__ (1)));
8246e6c55bSreyk int		 kw_cmp(const void *, const void *);
8346e6c55bSreyk int		 lookup(char *);
84588ec6bcSdenis int		 igetc(void);
8546e6c55bSreyk int		 lgetc(int);
86588ec6bcSdenis void		 lungetc(int);
8746e6c55bSreyk int		 findeol(void);
8846e6c55bSreyk 
8946e6c55bSreyk TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
9046e6c55bSreyk struct sym {
9146e6c55bSreyk 	TAILQ_ENTRY(sym)	 entry;
9246e6c55bSreyk 	int			 used;
9346e6c55bSreyk 	int			 persist;
9446e6c55bSreyk 	char			*nam;
9546e6c55bSreyk 	char			*val;
9646e6c55bSreyk };
9746e6c55bSreyk int		 symset(const char *, const char *, int);
9846e6c55bSreyk char		*symget(const char *);
9946e6c55bSreyk 
10017240de1Smartijn struct oid_sym {
10117240de1Smartijn 	char			*descriptor;
10217240de1Smartijn 	char			 file[PATH_MAX];
10317240de1Smartijn 	int			 lineno;
10417240de1Smartijn };
10517240de1Smartijn 
10617240de1Smartijn struct object_sym {
10717240de1Smartijn 	struct oid_sym		 oid;
10817240de1Smartijn 	char			*name;
10917240de1Smartijn 	int			 isint;
11017240de1Smartijn 	union {
11117240de1Smartijn 		int32_t		 intval;
11217240de1Smartijn 		char		*sval;
11317240de1Smartijn 	};
11417240de1Smartijn };
11517240de1Smartijn 
11617240de1Smartijn struct trapcmd_sym {
11717240de1Smartijn 	struct oid_sym	 oid;
11817240de1Smartijn 	struct trapcmd	*cmd;
11917240de1Smartijn };
12017240de1Smartijn 
12117240de1Smartijn struct trapaddress_sym {
12217240de1Smartijn 	struct oid_sym	 oid;
12317240de1Smartijn 	struct trap_address *tr;
12417240de1Smartijn };
12517240de1Smartijn 
12646e6c55bSreyk struct snmpd			*conf = NULL;
12746e6c55bSreyk static int			 errors = 0;
1286a925a1dSreyk static struct usmuser		*user = NULL;
129c3100810Smartijn static int			 mibparsed = 0;
13017240de1Smartijn 
13117240de1Smartijn static struct oid_sym		*blocklist = NULL;
13217240de1Smartijn static size_t			 nblocklist = 0;
13317240de1Smartijn static struct oid_sym		 sysoid = {};
13417240de1Smartijn static struct object_sym	*objects = NULL;
13517240de1Smartijn static size_t			 nobjects = 0;
13617240de1Smartijn static struct trapcmd_sym	*trapcmds = NULL;
13717240de1Smartijn static size_t			 ntrapcmds = 0;
13817240de1Smartijn static struct trapaddress_sym	*trapaddresses = NULL;
13917240de1Smartijn static size_t			 ntrapaddresses = 0;
14046e6c55bSreyk 
14173b5c081Smartijn static uint8_t			 engineid[SNMPD_MAXENGINEIDLEN];
14273b5c081Smartijn static int32_t			 enginepen;
14373b5c081Smartijn static size_t			 engineidlen;
14473b5c081Smartijn 
145*ad2d1a44Santon static unsigned char		 sha256[SHA256_DIGEST_LENGTH];
146*ad2d1a44Santon 
14717240de1Smartijn int		 resolve_oid(struct ber_oid *, struct oid_sym *);
14817240de1Smartijn int		 resolve_oids(void);
14970787abdSmartijn int		 host(const char *, const char *, int, int,
150967754d5Smartijn 		    struct sockaddr_storage *, int);
15120f2292fSmartijn int		 listen_add(struct sockaddr_storage *, int, int);
15246e6c55bSreyk 
15346e6c55bSreyk typedef struct {
15446e6c55bSreyk 	union {
15546e6c55bSreyk 		int64_t		 number;
15646e6c55bSreyk 		char		*string;
15746e6c55bSreyk 		struct host	*host;
15846e6c55bSreyk 		struct timeval	 tv;
15917240de1Smartijn 		struct oid_sym	 oid;
1604100cc5fSmartijn 		struct agentx_master ax;
16146e6c55bSreyk 		struct {
16246e6c55bSreyk 			int		 type;
16346e6c55bSreyk 			void		*data;
16446e6c55bSreyk 			long long	 value;
16546e6c55bSreyk 		}		 data;
1666a925a1dSreyk 		enum usmauth	 auth;
1676a925a1dSreyk 		enum usmpriv	 enc;
16846e6c55bSreyk 	} v;
16946e6c55bSreyk 	int lineno;
17046e6c55bSreyk } YYSTYPE;
17146e6c55bSreyk 
1724100cc5fSmartijn #define axm_opts	axm_fd
1734100cc5fSmartijn #define AXM_PATH	1 << 0
1744100cc5fSmartijn #define AXM_OWNER	1 << 1
1754100cc5fSmartijn #define AXM_GROUP	1 << 2
1764100cc5fSmartijn #define AXM_MODE	1 << 3
1774100cc5fSmartijn 
17846e6c55bSreyk %}
17946e6c55bSreyk 
18046e6c55bSreyk %token	INCLUDE
181c92471afSmartijn %token	LISTEN ON READ WRITE NOTIFY SNMPV1 SNMPV2 SNMPV3
1824100cc5fSmartijn %token	AGENTX PATH OWNER GROUP MODE
18373b5c081Smartijn %token	ENGINEID PEN OPENBSD IP4 IP6 MAC TEXT OCTETS AGENTID HOSTHASH
18482baf71dSsthen %token	SYSTEM CONTACT DESCR LOCATION NAME OBJECTID SERVICES RTFILTER
1859b15f147Sreyk %token	READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP RECEIVER
186c92471afSmartijn %token	SECLEVEL NONE AUTH ENC USER AUTHKEY ENCKEY ERROR
187be2edbd6Smartijn %token	HANDLE DEFAULT SRCADDR TCP UDP BLOCKLIST PORT
188c3100810Smartijn %token	MIB DIRECTORY
18946e6c55bSreyk %token	<v.string>	STRING
19046e6c55bSreyk %token	<v.number>	NUMBER
191ab858812Smartijn %type	<v.string>	usmuser community optcommunity
19273f6022eSmartijn %type	<v.number>	listenproto listenflag listenflags
193756b4b7aSmartijn %type	<v.string>	srcaddr port
19473f6022eSmartijn %type	<v.number>	optwrite yesno seclevel
1959352f69fSmartijn %type	<v.data>	cmd hostauth hostauthv3 usmauthopts usmauthopt
19670201ef1Sblambert %type	<v.oid>		oid hostoid trapoid
1976a925a1dSreyk %type	<v.auth>	auth
1986a925a1dSreyk %type	<v.enc>		enc
1994100cc5fSmartijn %type	<v.ax>		agentxopts agentxopt
20046e6c55bSreyk 
20146e6c55bSreyk %%
20246e6c55bSreyk 
20346e6c55bSreyk grammar		: /* empty */
20446e6c55bSreyk 		| grammar include '\n'
20546e6c55bSreyk 		| grammar '\n'
20646e6c55bSreyk 		| grammar varset '\n'
20746e6c55bSreyk 		| grammar main '\n'
20846e6c55bSreyk 		| grammar system '\n'
2099352f69fSmartijn 		| grammar object '\n'
210c3100810Smartijn 		| grammar mib '\n'
21146e6c55bSreyk 		| grammar error '\n'		{ file->errors++; }
21246e6c55bSreyk 		;
21346e6c55bSreyk 
21446e6c55bSreyk include		: INCLUDE STRING		{
21546e6c55bSreyk 			struct file	*nfile;
21646e6c55bSreyk 
21746e6c55bSreyk 			if ((nfile = pushfile($2, 0)) == NULL) {
21846e6c55bSreyk 				yyerror("failed to include file %s", $2);
21946e6c55bSreyk 				free($2);
22046e6c55bSreyk 				YYERROR;
22146e6c55bSreyk 			}
22246e6c55bSreyk 			free($2);
22346e6c55bSreyk 
22446e6c55bSreyk 			file = nfile;
22546e6c55bSreyk 			lungetc('\n');
22646e6c55bSreyk 		}
2278bc0bdcaSsthen 		;
22846e6c55bSreyk 
22946e6c55bSreyk varset		: STRING '=' STRING	{
2300c7b4ca6Sbenno 			char *s = $1;
2310c7b4ca6Sbenno 			while (*s++) {
2320c7b4ca6Sbenno 				if (isspace((unsigned char)*s)) {
2330c7b4ca6Sbenno 					yyerror("macro name cannot contain "
2340c7b4ca6Sbenno 					    "whitespace");
23516a0a906Skrw 					free($1);
23616a0a906Skrw 					free($3);
2370c7b4ca6Sbenno 					YYERROR;
2380c7b4ca6Sbenno 				}
2390c7b4ca6Sbenno 			}
24046e6c55bSreyk 			if (symset($1, $3, 0) == -1)
24146e6c55bSreyk 				fatal("cannot store variable");
24246e6c55bSreyk 			free($1);
24346e6c55bSreyk 			free($3);
24446e6c55bSreyk 		}
24546e6c55bSreyk 		;
24646e6c55bSreyk 
24782baf71dSsthen yesno		:  STRING			{
24882baf71dSsthen 			if (!strcmp($1, "yes"))
24982baf71dSsthen 				$$ = 1;
25082baf71dSsthen 			else if (!strcmp($1, "no"))
25182baf71dSsthen 				$$ = 0;
25282baf71dSsthen 			else {
25382baf71dSsthen 				yyerror("syntax error, "
25482baf71dSsthen 				    "either yes or no expected");
25582baf71dSsthen 				free($1);
25682baf71dSsthen 				YYERROR;
25782baf71dSsthen 			}
25882baf71dSsthen 			free($1);
25982baf71dSsthen 		}
26082baf71dSsthen 		;
26182baf71dSsthen 
26273f6022eSmartijn main		: LISTEN ON listen_udptcp
2634100cc5fSmartijn 		| AGENTX agentxopts {
2644100cc5fSmartijn 			struct agentx_master *master, *test;
2654100cc5fSmartijn 			struct group *grp;
2664100cc5fSmartijn 
2674100cc5fSmartijn 			if ((master = malloc(sizeof(*master))) == NULL) {
2684100cc5fSmartijn 				yyerror("malloc");
2694100cc5fSmartijn 				YYERROR;
2704100cc5fSmartijn 			}
2714100cc5fSmartijn 			master->axm_fd = -1;
2724100cc5fSmartijn 			master->axm_sun.sun_len = sizeof(master->axm_sun);
2734100cc5fSmartijn 			master->axm_sun.sun_family = AF_UNIX;
2744100cc5fSmartijn 			if ($2.axm_opts & AXM_PATH)
2754100cc5fSmartijn 				strlcpy(master->axm_sun.sun_path,
2764100cc5fSmartijn 				    $2.axm_sun.sun_path,
2774100cc5fSmartijn 				    sizeof(master->axm_sun.sun_path));
2784100cc5fSmartijn 			else
2794100cc5fSmartijn 				strlcpy(master->axm_sun.sun_path,
2804100cc5fSmartijn 				    AGENTX_MASTER_PATH,
2814100cc5fSmartijn 				    sizeof(master->axm_sun.sun_path));
2824100cc5fSmartijn 			master->axm_owner = $2.axm_opts & AXM_OWNER ?
2834100cc5fSmartijn 			    $2.axm_owner : 0;
2844100cc5fSmartijn 			if ($2.axm_opts & AXM_GROUP)
2854100cc5fSmartijn 				master->axm_group = $2.axm_group;
2864100cc5fSmartijn 			else {
2874100cc5fSmartijn 				if ((grp = getgrnam(AGENTX_GROUP)) == NULL) {
2884100cc5fSmartijn 					yyerror("agentx: group %s not found",
2894100cc5fSmartijn 					    AGENTX_GROUP);
2904100cc5fSmartijn 					YYERROR;
2914100cc5fSmartijn 				}
2924100cc5fSmartijn 				master->axm_group = grp->gr_gid;
2934100cc5fSmartijn 			}
2944100cc5fSmartijn 			master->axm_mode = $2.axm_opts & AXM_MODE ?
2954100cc5fSmartijn 			    $2.axm_mode : 0660;
2964100cc5fSmartijn 
2974100cc5fSmartijn 			TAILQ_FOREACH(test, &conf->sc_agentx_masters,
2984100cc5fSmartijn 			    axm_entry) {
2994100cc5fSmartijn 				if (strcmp(test->axm_sun.sun_path,
3004100cc5fSmartijn 				    master->axm_sun.sun_path) == 0) {
3014100cc5fSmartijn 					yyerror("agentx: duplicate entry: %s",
3024100cc5fSmartijn 					    test->axm_sun.sun_path);
3034100cc5fSmartijn 					YYERROR;
3044100cc5fSmartijn 				}
3054100cc5fSmartijn 			}
3064100cc5fSmartijn 
3074100cc5fSmartijn 			TAILQ_INSERT_TAIL(&conf->sc_agentx_masters, master,
3084100cc5fSmartijn 			    axm_entry);
3094100cc5fSmartijn 		}
31073b5c081Smartijn 		| engineid_local {
31173b5c081Smartijn 			if (conf->sc_engineid_len != 0) {
31273b5c081Smartijn 				yyerror("Redefinition of engineid");
31373b5c081Smartijn 				YYERROR;
31473b5c081Smartijn 			}
31573b5c081Smartijn 			memcpy(conf->sc_engineid, engineid, engineidlen);
31673b5c081Smartijn 			conf->sc_engineid_len = engineidlen;
31773b5c081Smartijn 		}
31846e6c55bSreyk 		| READONLY COMMUNITY STRING	{
31946e6c55bSreyk 			if (strlcpy(conf->sc_rdcommunity, $3,
32046e6c55bSreyk 			    sizeof(conf->sc_rdcommunity)) >=
32146e6c55bSreyk 			    sizeof(conf->sc_rdcommunity)) {
32246e6c55bSreyk 				yyerror("r/o community name too long");
32346e6c55bSreyk 				free($3);
32446e6c55bSreyk 				YYERROR;
32546e6c55bSreyk 			}
32646e6c55bSreyk 			free($3);
32746e6c55bSreyk 		}
32846e6c55bSreyk 		| READWRITE COMMUNITY STRING	{
32946e6c55bSreyk 			if (strlcpy(conf->sc_rwcommunity, $3,
33046e6c55bSreyk 			    sizeof(conf->sc_rwcommunity)) >=
33146e6c55bSreyk 			    sizeof(conf->sc_rwcommunity)) {
33246e6c55bSreyk 				yyerror("r/w community name too long");
33346e6c55bSreyk 				free($3);
33446e6c55bSreyk 				YYERROR;
33546e6c55bSreyk 			}
33646e6c55bSreyk 			free($3);
33746e6c55bSreyk 		}
33846e6c55bSreyk 		| TRAP COMMUNITY STRING		{
33946e6c55bSreyk 			if (strlcpy(conf->sc_trcommunity, $3,
34046e6c55bSreyk 			    sizeof(conf->sc_trcommunity)) >=
34146e6c55bSreyk 			    sizeof(conf->sc_trcommunity)) {
3422374dcc3Sblambert 				yyerror("trap community name too long");
34346e6c55bSreyk 				free($3);
34446e6c55bSreyk 				YYERROR;
34546e6c55bSreyk 			}
34646e6c55bSreyk 			free($3);
34746e6c55bSreyk 		}
348967754d5Smartijn 		| TRAP RECEIVER	host
349ab858812Smartijn 		| TRAP HANDLE trapoid cmd {
35017240de1Smartijn 			struct trapcmd_sym *ttrapcmds;
35170201ef1Sblambert 
35217240de1Smartijn 			if ((ttrapcmds = recallocarray(trapcmds, ntrapcmds,
35317240de1Smartijn 			    ntrapcmds + 1, sizeof(*trapcmds))) == NULL) {
35417240de1Smartijn 				yyerror("malloc");
35517240de1Smartijn 				free($3.descriptor);
35617240de1Smartijn 				free($4.data);
35770201ef1Sblambert 				YYERROR;
35870201ef1Sblambert 			}
35917240de1Smartijn 
36017240de1Smartijn 			trapcmds = ttrapcmds;
36117240de1Smartijn 			trapcmds[ntrapcmds].oid = $3;
36217240de1Smartijn 			trapcmds[ntrapcmds++].cmd = $4.data;
36370201ef1Sblambert 		}
364614c3698Smartijn 		| BLOCKLIST oid {
36517240de1Smartijn 			struct oid_sym *tblocklist;
366614c3698Smartijn 
36717240de1Smartijn 			if ((tblocklist = recallocarray(blocklist, nblocklist,
36817240de1Smartijn 			    nblocklist + 1, sizeof(*blocklist))) == NULL) {
369614c3698Smartijn 				yyerror("malloc");
37017240de1Smartijn 				free($2.descriptor);
371614c3698Smartijn 				YYERROR;
372614c3698Smartijn 			}
37317240de1Smartijn 			blocklist = tblocklist;
37417240de1Smartijn 			blocklist[nblocklist++] = $2;
375614c3698Smartijn 		}
37682baf71dSsthen 		| RTFILTER yesno		{
377ab8dd476Smartijn 			conf->sc_rtfilter = $2;
37882baf71dSsthen 		}
379ab858812Smartijn 		| seclevel {
380ab858812Smartijn 			conf->sc_min_seclevel = $1;
3816a925a1dSreyk 		}
3826a925a1dSreyk 		| USER STRING			{
3836a925a1dSreyk 			const char *errstr;
3846a925a1dSreyk 			user = usm_newuser($2, &errstr);
3856a925a1dSreyk 			if (user == NULL) {
386c5e00159Sflorian 				yyerror("%s", errstr);
3876a925a1dSreyk 				free($2);
3886a925a1dSreyk 				YYERROR;
3896a925a1dSreyk 			}
3906a925a1dSreyk 		} userspecs {
3916a925a1dSreyk 			const char *errstr;
3926a925a1dSreyk 			if (usm_checkuser(user, &errstr) < 0) {
393c5e00159Sflorian 				yyerror("%s", errstr);
3946a925a1dSreyk 				YYERROR;
3956a925a1dSreyk 			}
3966a925a1dSreyk 			user = NULL;
3976a925a1dSreyk 		}
39846e6c55bSreyk 		;
39946e6c55bSreyk 
40073f6022eSmartijn listenproto	: /* empty */			{ $$ = SOCK_DGRAM; }
40173f6022eSmartijn 		| UDP 				{ $$ = SOCK_DGRAM; }
402a7950217Smartijn 		| TCP				{ $$ = SOCK_STREAM; }
40320f2292fSmartijn 		;
40420f2292fSmartijn 
40573f6022eSmartijn listenflags	: /* empty */ { $$ = 0; }
40673f6022eSmartijn 		| listenflags listenflag { $$ |= $2; }
40773f6022eSmartijn 		;
40873f6022eSmartijn 
40973f6022eSmartijn listenflag	: READ { $$ = ADDRESS_FLAG_READ; }
41020f2292fSmartijn 		| WRITE { $$ = ADDRESS_FLAG_WRITE; }
41120f2292fSmartijn 		| NOTIFY { $$ = ADDRESS_FLAG_NOTIFY; }
412c92471afSmartijn 		| SNMPV1 { $$ = ADDRESS_FLAG_SNMPV1; }
413c92471afSmartijn 		| SNMPV2 { $$ = ADDRESS_FLAG_SNMPV2; }
414c92471afSmartijn 		| SNMPV3 { $$ = ADDRESS_FLAG_SNMPV3; }
41520f2292fSmartijn 		;
41620f2292fSmartijn 
41773f6022eSmartijn listen_udptcp	: listenproto STRING port listenflags	{
418756b4b7aSmartijn 			struct sockaddr_storage ss[16];
41973f6022eSmartijn 			int nhosts, j;
42073f6022eSmartijn 			char *address[2], *port = $3;
42173f6022eSmartijn 			size_t addresslen = 1, i;
422756b4b7aSmartijn 
42320f2292fSmartijn 			if (port == NULL) {
42473f6022eSmartijn 				if (($4 & ADDRESS_FLAG_PERM) ==
425c92471afSmartijn 				    ADDRESS_FLAG_NOTIFY)
42620f2292fSmartijn 					port = SNMPTRAP_PORT;
42720f2292fSmartijn 				else
42820f2292fSmartijn 					port = SNMP_PORT;
42920f2292fSmartijn 			}
43020f2292fSmartijn 
43173f6022eSmartijn 			if (strcmp($2, "any") == 0) {
43273f6022eSmartijn 				addresslen = 2;
43373f6022eSmartijn 				address[0] = "0.0.0.0";
43473f6022eSmartijn 				address[1] = "::";
43573f6022eSmartijn 			} else {
43673f6022eSmartijn 				addresslen = 1;
43773f6022eSmartijn 				address[0] = $2;
43873f6022eSmartijn 			}
43973f6022eSmartijn 
44073f6022eSmartijn 			for (i = 0; i < addresslen; i++) {
44170787abdSmartijn 				if ((nhosts = host(address[i], port, AF_UNSPEC,
44270787abdSmartijn 				    $1, ss, nitems(ss))) < 1) {
44373f6022eSmartijn 					yyerror("invalid address: %s", $2);
444756b4b7aSmartijn 					free($2);
44573f6022eSmartijn 					free($3);
446756b4b7aSmartijn 					YYERROR;
447756b4b7aSmartijn 				}
448756b4b7aSmartijn 				if (nhosts > (int)nitems(ss))
44973f6022eSmartijn 					log_warn("%s:%s resolves to more than "
45073f6022eSmartijn 					    "%zu hosts", $2, port, nitems(ss));
451756b4b7aSmartijn 
45273f6022eSmartijn 				for (j = 0; j < nhosts; j++) {
45373f6022eSmartijn 					if (listen_add(&(ss[j]), $1, $4) == -1) {
454756b4b7aSmartijn 						yyerror("calloc");
455756b4b7aSmartijn 						YYERROR;
456756b4b7aSmartijn 					}
457756b4b7aSmartijn 				}
458756b4b7aSmartijn 			}
459756b4b7aSmartijn 			free($2);
46073f6022eSmartijn 			free($3);
461756b4b7aSmartijn 		}
4620c569d7eSgerhard 		;
463756b4b7aSmartijn 
464756b4b7aSmartijn port		: /* empty */			{
46520f2292fSmartijn 			$$ = NULL;
466756b4b7aSmartijn 		}
467756b4b7aSmartijn 		| PORT STRING			{
468756b4b7aSmartijn 			$$ = $2;
469756b4b7aSmartijn 		}
470756b4b7aSmartijn 		| PORT NUMBER			{
471756b4b7aSmartijn 			char *number;
472756b4b7aSmartijn 
473756b4b7aSmartijn 			if ($2 > UINT16_MAX) {
474756b4b7aSmartijn 				yyerror("port number too large");
475756b4b7aSmartijn 				YYERROR;
476756b4b7aSmartijn 			}
477756b4b7aSmartijn 			if ($2 < 1) {
478756b4b7aSmartijn 				yyerror("port number too small");
479756b4b7aSmartijn 				YYERROR;
480756b4b7aSmartijn 			}
481756b4b7aSmartijn 			if (asprintf(&number, "%"PRId64, $2) == -1) {
482756b4b7aSmartijn 				yyerror("malloc");
483756b4b7aSmartijn 				YYERROR;
484756b4b7aSmartijn 			}
485756b4b7aSmartijn 			$$ = number;
486756b4b7aSmartijn 		}
487756b4b7aSmartijn 		;
488756b4b7aSmartijn 
4894100cc5fSmartijn agentxopt	: PATH STRING			{
4904100cc5fSmartijn 			if ($2[0] != '/') {
4914100cc5fSmartijn 				yyerror("agentx path: must be absolute");
4924100cc5fSmartijn 				YYERROR;
4934100cc5fSmartijn 			}
4944100cc5fSmartijn 			if (strlcpy($$.axm_sun.sun_path, $2,
4954100cc5fSmartijn 			    sizeof($$.axm_sun.sun_path)) >=
4964100cc5fSmartijn 			    sizeof($$.axm_sun.sun_path)) {
4974100cc5fSmartijn 				yyerror("agentx path: too long");
4984100cc5fSmartijn 				YYERROR;
4994100cc5fSmartijn 			}
5004100cc5fSmartijn 			$$.axm_opts = AXM_PATH;
5014100cc5fSmartijn 		}
5024100cc5fSmartijn 		| OWNER NUMBER			{
5034100cc5fSmartijn 			if ($2 > UID_MAX) {
5044100cc5fSmartijn 				yyerror("agentx owner: too large");
5054100cc5fSmartijn 				YYERROR;
5064100cc5fSmartijn 			}
5074100cc5fSmartijn 			$$.axm_owner = $2;
5084100cc5fSmartijn 			$$.axm_opts = AXM_OWNER;
5094100cc5fSmartijn 		}
5104100cc5fSmartijn 		| OWNER STRING			{
5114100cc5fSmartijn 			struct passwd *pw;
5124100cc5fSmartijn 			const char *errstr;
5134100cc5fSmartijn 
5144100cc5fSmartijn 			$$.axm_owner = strtonum($2, 0, UID_MAX, &errstr);
5154100cc5fSmartijn 			if (errstr != NULL && errno == ERANGE) {
5164100cc5fSmartijn 				yyerror("agentx owner: %s", errstr);
5174100cc5fSmartijn 				YYERROR;
5184100cc5fSmartijn 			}
5194100cc5fSmartijn 			if ((pw = getpwnam($2)) == NULL) {
5204100cc5fSmartijn 				yyerror("agentx owner: user not found");
5214100cc5fSmartijn 				YYERROR;
5224100cc5fSmartijn 			}
5234100cc5fSmartijn 			$$.axm_owner = pw->pw_uid;
5244100cc5fSmartijn 			$$.axm_opts = AXM_OWNER;
5254100cc5fSmartijn 		}
5264100cc5fSmartijn 		| GROUP NUMBER			{
5274100cc5fSmartijn 			if ($2 > GID_MAX) {
5284100cc5fSmartijn 				yyerror("agentx group: too large");
5294100cc5fSmartijn 				YYERROR;
5304100cc5fSmartijn 			}
5314100cc5fSmartijn 			$$.axm_group = $2;
5324100cc5fSmartijn 			$$.axm_opts = AXM_GROUP;
5334100cc5fSmartijn 		}
5344100cc5fSmartijn 		| GROUP STRING			{
5354100cc5fSmartijn 			struct group *gr;
5364100cc5fSmartijn 			const char *errstr;
5374100cc5fSmartijn 
5384100cc5fSmartijn 			$$.axm_group = strtonum($2, 0, GID_MAX, &errstr);
5394100cc5fSmartijn 			if (errstr != NULL && errno == ERANGE) {
5404100cc5fSmartijn 				yyerror("agentx group: %s", errstr);
5414100cc5fSmartijn 				YYERROR;
5424100cc5fSmartijn 			}
5434100cc5fSmartijn 			if ((gr = getgrnam($2)) == NULL) {
5444100cc5fSmartijn 				yyerror("agentx group: group not found");
5454100cc5fSmartijn 				YYERROR;
5464100cc5fSmartijn 			}
5474100cc5fSmartijn 			$$.axm_group = gr->gr_gid;
5484100cc5fSmartijn 			$$.axm_opts = AXM_GROUP;
5494100cc5fSmartijn 		}
5504100cc5fSmartijn 		| MODE NUMBER			{
5514100cc5fSmartijn 			long mode;
5524100cc5fSmartijn 			char *endptr, str[21];
5534100cc5fSmartijn 
5544100cc5fSmartijn 			snprintf(str, sizeof(str), "%lld", $2);
5554100cc5fSmartijn 			errno = 0;
5564100cc5fSmartijn 			mode = strtol(str, &endptr, 8);
5574100cc5fSmartijn 			if (errno != 0 || endptr[0] != '\0' ||
5584100cc5fSmartijn 			    mode <= 0 || mode > 0777) {
5594100cc5fSmartijn 				yyerror("agentx mode: invalid");
5604100cc5fSmartijn 				YYERROR;
5614100cc5fSmartijn 			}
5624100cc5fSmartijn 			$$.axm_mode = mode;
5634100cc5fSmartijn 			$$.axm_opts = AXM_MODE;
5644100cc5fSmartijn 		}
5654100cc5fSmartijn 		;
5664100cc5fSmartijn 
5674100cc5fSmartijn agentxopts	: /* empty */			{
5684100cc5fSmartijn 			bzero(&$$, sizeof($$));
5694100cc5fSmartijn 		}
5704100cc5fSmartijn 		| agentxopts agentxopt {
5714100cc5fSmartijn 			if ($$.axm_opts & $2.axm_opts) {
5724100cc5fSmartijn 				yyerror("agentx: duplicate option");
5734100cc5fSmartijn 				YYERROR;
5744100cc5fSmartijn 			}
5754100cc5fSmartijn 			switch ($2.axm_opts) {
5764100cc5fSmartijn 			case AXM_PATH:
5774100cc5fSmartijn 				strlcpy($$.axm_sun.sun_path,
5784100cc5fSmartijn 				    $2.axm_sun.sun_path,
5794100cc5fSmartijn 				    sizeof($$.axm_sun.sun_path));
5804100cc5fSmartijn 				break;
5814100cc5fSmartijn 			case AXM_OWNER:
5824100cc5fSmartijn 				$$.axm_owner = $2.axm_owner;
5834100cc5fSmartijn 				break;
5844100cc5fSmartijn 			case AXM_GROUP:
5854100cc5fSmartijn 				$$.axm_group = $2.axm_group;
5864100cc5fSmartijn 				break;
5874100cc5fSmartijn 			case AXM_MODE:
5884100cc5fSmartijn 				$$.axm_mode = $2.axm_mode;
5894100cc5fSmartijn 				break;
5904100cc5fSmartijn 			}
5914100cc5fSmartijn 			$$.axm_opts |= $2.axm_opts;
5924100cc5fSmartijn 		}
5934100cc5fSmartijn 		;
5944100cc5fSmartijn 
59573b5c081Smartijn enginefmt	: IP4 STRING			{
59673b5c081Smartijn 			struct in_addr addr;
59773b5c081Smartijn 
59873b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_IPv4;
59973b5c081Smartijn 			if (inet_pton(AF_INET, $2, &addr) != 1) {
60073b5c081Smartijn 				yyerror("Invalid ipv4 address: %s", $2);
60173b5c081Smartijn 				free($2);
60273b5c081Smartijn 				YYERROR;
60373b5c081Smartijn 			}
60473b5c081Smartijn 			memcpy(engineid + engineidlen, &addr,
60573b5c081Smartijn 			    sizeof(engineid) - engineidlen);
60673b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
60773b5c081Smartijn 			engineidlen += sizeof(addr);
60873b5c081Smartijn 			free($2);
60973b5c081Smartijn 		}
61073b5c081Smartijn 		| IP6 STRING			{
61173b5c081Smartijn 			struct in6_addr addr;
61273b5c081Smartijn 
61373b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_IPv6;
61473b5c081Smartijn 			if (inet_pton(AF_INET6, $2, &addr) != 1) {
61573b5c081Smartijn 				yyerror("Invalid ipv6 address: %s", $2);
61673b5c081Smartijn 				free($2);
61773b5c081Smartijn 				YYERROR;
61873b5c081Smartijn 			}
61973b5c081Smartijn 			memcpy(engineid + engineidlen, &addr,
62073b5c081Smartijn 			    sizeof(engineid) - engineidlen);
62173b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
62273b5c081Smartijn 			engineidlen += sizeof(addr);
62373b5c081Smartijn 			free($2);
62473b5c081Smartijn 		}
62573b5c081Smartijn 		| MAC STRING			{
62673b5c081Smartijn 			size_t i;
62773b5c081Smartijn 
62873b5c081Smartijn 			if (strlen($2) != 5 * 3 + 2) {
62973b5c081Smartijn 				yyerror("Invalid mac address: %s", $2);
63073b5c081Smartijn 				free($2);
63173b5c081Smartijn 				YYERROR;
63273b5c081Smartijn 			}
63373b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_MAC;
63473b5c081Smartijn 			for (i = 0; i < 6; i++) {
63573b5c081Smartijn 				if (fromhexstr(engineid + engineidlen + i,
63673b5c081Smartijn 				    $2 + (i * 3), 2) == NULL ||
63773b5c081Smartijn 				    $2[i * 3 + 2] != (i < 5 ? ':' : '\0')) {
63873b5c081Smartijn 					yyerror("Invalid mac address: %s", $2);
63973b5c081Smartijn 					free($2);
64073b5c081Smartijn 					YYERROR;
64173b5c081Smartijn 				}
64273b5c081Smartijn 			}
64373b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
64473b5c081Smartijn 			engineidlen += 6;
64573b5c081Smartijn 			free($2);
64673b5c081Smartijn 		}
64773b5c081Smartijn 		| TEXT STRING			{
64873b5c081Smartijn 			size_t i, fmtstart;
64973b5c081Smartijn 
65073b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_TEXT;
65173b5c081Smartijn 			for (i = 0, fmtstart = engineidlen;
65273b5c081Smartijn 			    i < sizeof(engineid) - engineidlen && $2[i] != '\0';
65373b5c081Smartijn 			    i++) {
65473b5c081Smartijn 				if (!isprint($2[i])) {
65573b5c081Smartijn 					yyerror("invalid text character");
65673b5c081Smartijn 					free($2);
65773b5c081Smartijn 					YYERROR;
65873b5c081Smartijn 				}
65973b5c081Smartijn 				engineid[fmtstart + i] = $2[i];
66073b5c081Smartijn 				engineidlen++;
66173b5c081Smartijn 			}
66273b5c081Smartijn 			if (i == 0 || $2[i] != '\0') {
66373b5c081Smartijn 				yyerror("Invalid text length: %s", $2);
66473b5c081Smartijn 				free($2);
66573b5c081Smartijn 				YYERROR;
66673b5c081Smartijn 			}
66773b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
66873b5c081Smartijn 			free($2);
66973b5c081Smartijn 		}
67073b5c081Smartijn 		| OCTETS STRING			{
67173b5c081Smartijn 			if (strlen($2) / 2 > sizeof(engineid) - 1) {
67273b5c081Smartijn 				yyerror("Invalid octets length: %s", $2);
67373b5c081Smartijn 				free($2);
67473b5c081Smartijn 				YYERROR;
67573b5c081Smartijn 			}
67673b5c081Smartijn 
67773b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_OCT;
67873b5c081Smartijn 			if (fromhexstr(engineid + engineidlen, $2,
67973b5c081Smartijn 			    strlen($2)) == NULL) {
68073b5c081Smartijn 				yyerror("Invalid octets: %s", $2);
68173b5c081Smartijn 				free($2);
68273b5c081Smartijn 				YYERROR;
68373b5c081Smartijn 			}
68473b5c081Smartijn 			engineidlen += strlen($2) / 2;
68573b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
68673b5c081Smartijn 			free($2);
68773b5c081Smartijn 		}
68873b5c081Smartijn 		| AGENTID STRING		{
68973b5c081Smartijn 			if (strlen($2) / 2 != 8) {
69073b5c081Smartijn 				yyerror("Invalid agentid length: %s", $2);
69173b5c081Smartijn 				free($2);
69273b5c081Smartijn 				YYERROR;
69373b5c081Smartijn 			}
69473b5c081Smartijn 
69573b5c081Smartijn 			if (fromhexstr(engineid + engineidlen, $2,
69673b5c081Smartijn 			    strlen($2)) == NULL) {
69773b5c081Smartijn 				yyerror("Invalid agentid: %s", $2);
69873b5c081Smartijn 				free($2);
69973b5c081Smartijn 				YYERROR;
70073b5c081Smartijn 			}
70173b5c081Smartijn 			engineidlen += 8;
70273b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_OLD;
70373b5c081Smartijn 			free($2);
70473b5c081Smartijn 		}
70573b5c081Smartijn 		| HOSTHASH STRING		{
70673b5c081Smartijn 			if (enginepen != PEN_OPENBSD) {
70773b5c081Smartijn 				yyerror("hosthash only allowed for pen "
70873b5c081Smartijn 				    "openbsd");
70973b5c081Smartijn 				YYERROR;
71073b5c081Smartijn 			}
71173b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_HH;
71273b5c081Smartijn 			memcpy(engineid + engineidlen,
713*ad2d1a44Santon 			    SHA256($2, strlen($2), sha256),
71473b5c081Smartijn 			    sizeof(engineid) - engineidlen);
71573b5c081Smartijn 			engineidlen = sizeof(engineid);
71673b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
71773b5c081Smartijn 			free($2);
71873b5c081Smartijn 		}
71973b5c081Smartijn 		| NUMBER STRING			{
72073b5c081Smartijn 			if (enginepen == PEN_OPENBSD) {
72173b5c081Smartijn 				yyerror("%lld is only allowed when pen is not "
72273b5c081Smartijn 				    "openbsd", $1);
72373b5c081Smartijn 				YYERROR;
72473b5c081Smartijn 			}
72573b5c081Smartijn 
72673b5c081Smartijn 			if ($1 < 128 || $1 > 255) {
72773b5c081Smartijn 				yyerror("Invalid format number: %lld\n", $1);
72873b5c081Smartijn 				YYERROR;
72973b5c081Smartijn 			}
73073b5c081Smartijn 			if (strlen($2) / 2 > sizeof(engineid) - 1) {
73173b5c081Smartijn 				yyerror("Invalid octets length: %s", $2);
73273b5c081Smartijn 				free($2);
73373b5c081Smartijn 				YYERROR;
73473b5c081Smartijn 			}
73573b5c081Smartijn 
73673b5c081Smartijn 			engineid[engineidlen++] = (uint8_t)$1;
73773b5c081Smartijn 			if (fromhexstr(engineid + engineidlen, $2,
73873b5c081Smartijn 			    strlen($2)) == NULL) {
73973b5c081Smartijn 				yyerror("Invalid octets: %s", $2);
74073b5c081Smartijn 				free($2);
74173b5c081Smartijn 				YYERROR;
74273b5c081Smartijn 			}
74373b5c081Smartijn 			engineidlen += strlen($2) / 2;
74473b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
74573b5c081Smartijn 			free($2);
74673b5c081Smartijn 		}
74773b5c081Smartijn 		;
74873b5c081Smartijn 
74973b5c081Smartijn enginefmt_local	: enginefmt
75073b5c081Smartijn 		| HOSTHASH			{
75173b5c081Smartijn 			char hostname[HOST_NAME_MAX + 1];
75273b5c081Smartijn 
75373b5c081Smartijn 			if (enginepen != PEN_OPENBSD) {
75473b5c081Smartijn 				yyerror("hosthash only allowed for pen "
75573b5c081Smartijn 				    "openbsd");
75673b5c081Smartijn 				YYERROR;
75773b5c081Smartijn 			}
75873b5c081Smartijn 
75973b5c081Smartijn 			if (gethostname(hostname, sizeof(hostname)) == -1) {
76073b5c081Smartijn 				yyerror("gethostname: %s", strerror(errno));
76173b5c081Smartijn 				YYERROR;
76273b5c081Smartijn 			}
76373b5c081Smartijn 
76473b5c081Smartijn 			engineid[engineidlen++] = SNMP_ENGINEID_FMT_HH;
76573b5c081Smartijn 			memcpy(engineid + engineidlen,
766*ad2d1a44Santon 			    SHA256(hostname, strlen(hostname), sha256),
76773b5c081Smartijn 			    sizeof(engineid) - engineidlen);
76873b5c081Smartijn 			engineidlen = sizeof(engineid);
76973b5c081Smartijn 			engineid[0] |= SNMP_ENGINEID_NEW;
77073b5c081Smartijn 		}
77173b5c081Smartijn 		;
77273b5c081Smartijn 
77373b5c081Smartijn pen		: /* empty */			{
77473b5c081Smartijn 			enginepen = PEN_OPENBSD;
77573b5c081Smartijn 		}
77673b5c081Smartijn 		| PEN NUMBER			{
77773b5c081Smartijn 			if ($2 > INT32_MAX) {
77873b5c081Smartijn 				yyerror("pen number too large");
77973b5c081Smartijn 				YYERROR;
78073b5c081Smartijn 			}
78173b5c081Smartijn 			if ($2 <= 0) {
78273b5c081Smartijn 				yyerror("pen number too small");
78373b5c081Smartijn 				YYERROR;
78473b5c081Smartijn 			}
78573b5c081Smartijn 			enginepen = $2;
78673b5c081Smartijn 		}
78773b5c081Smartijn 		| PEN OPENBSD			{
78873b5c081Smartijn 			enginepen = PEN_OPENBSD;
78973b5c081Smartijn 		}
79073b5c081Smartijn 		;
79173b5c081Smartijn 
79273b5c081Smartijn engineid_local	: ENGINEID pen			{
79373b5c081Smartijn 			uint32_t npen = htonl(enginepen);
79473b5c081Smartijn 
79573b5c081Smartijn 			memcpy(engineid, &npen, sizeof(enginepen));
79673b5c081Smartijn 			engineidlen = sizeof(enginepen);
79773b5c081Smartijn 		} enginefmt_local
79873b5c081Smartijn 
79946e6c55bSreyk system		: SYSTEM sysmib
80046e6c55bSreyk 		;
80146e6c55bSreyk 
80246e6c55bSreyk sysmib		: CONTACT STRING		{
80360cc2743Smartijn 			if (conf->sc_system.sys_contact[0] != '\0') {
80460cc2743Smartijn 				yyerror("system contact already defined");
80560cc2743Smartijn 				free($2);
80660cc2743Smartijn 				YYERROR;
80760cc2743Smartijn 			}
80860cc2743Smartijn 			if (strlcpy(conf->sc_system.sys_contact, $2,
80960cc2743Smartijn 			    sizeof(conf->sc_system.sys_contact)) >=
81060cc2743Smartijn 			    sizeof(conf->sc_system.sys_contact)) {
81160cc2743Smartijn 				yyerror("system contact too long");
81260cc2743Smartijn 				free($2);
81360cc2743Smartijn 				YYERROR;
81460cc2743Smartijn 			}
81560cc2743Smartijn 			free($2);
81646e6c55bSreyk 		}
81746e6c55bSreyk 		| DESCR STRING			{
81860cc2743Smartijn 			if (conf->sc_system.sys_descr[0] != '\0') {
81960cc2743Smartijn 				yyerror("system description already defined");
82060cc2743Smartijn 				free($2);
82160cc2743Smartijn 				YYERROR;
82260cc2743Smartijn 			}
82360cc2743Smartijn 			if (strlcpy(conf->sc_system.sys_descr, $2,
82460cc2743Smartijn 			    sizeof(conf->sc_system.sys_descr)) >=
82560cc2743Smartijn 			    sizeof(conf->sc_system.sys_descr)) {
82660cc2743Smartijn 				yyerror("system description too long");
82760cc2743Smartijn 				free($2);
82860cc2743Smartijn 				YYERROR;
82960cc2743Smartijn 			}
83060cc2743Smartijn 			free($2);
83146e6c55bSreyk 		}
83246e6c55bSreyk 		| LOCATION STRING		{
83360cc2743Smartijn 			if (conf->sc_system.sys_location[0] != '\0') {
83460cc2743Smartijn 				yyerror("system location already defined");
83560cc2743Smartijn 				free($2);
83660cc2743Smartijn 				YYERROR;
83760cc2743Smartijn 			}
83860cc2743Smartijn 			if (strlcpy(conf->sc_system.sys_location, $2,
83960cc2743Smartijn 			    sizeof(conf->sc_system.sys_location)) >=
84060cc2743Smartijn 			    sizeof(conf->sc_system.sys_location)) {
84160cc2743Smartijn 				yyerror("system location too long");
84260cc2743Smartijn 				free($2);
84360cc2743Smartijn 				YYERROR;
84460cc2743Smartijn 			}
84560cc2743Smartijn 			free($2);
84646e6c55bSreyk 		}
84746e6c55bSreyk 		| NAME STRING			{
84860cc2743Smartijn 			if (conf->sc_system.sys_name[0] != '\0') {
84960cc2743Smartijn 				yyerror("system name already defined");
85060cc2743Smartijn 				free($2);
85160cc2743Smartijn 				YYERROR;
85260cc2743Smartijn 			}
85360cc2743Smartijn 			if (strlcpy(conf->sc_system.sys_name, $2,
85460cc2743Smartijn 			    sizeof(conf->sc_system.sys_name)) >=
85560cc2743Smartijn 			    sizeof(conf->sc_system.sys_name)) {
85660cc2743Smartijn 				yyerror("system name too long");
85760cc2743Smartijn 				free($2);
85860cc2743Smartijn 				YYERROR;
85960cc2743Smartijn 			}
86060cc2743Smartijn 			free($2);
86146e6c55bSreyk 		}
86246e6c55bSreyk 		| OBJECTID oid			{
86317240de1Smartijn 			if (sysoid.descriptor != NULL) {
86460cc2743Smartijn 				yyerror("system oid already defined");
86517240de1Smartijn 				free($2.descriptor);
86660cc2743Smartijn 				YYERROR;
86760cc2743Smartijn 			}
86817240de1Smartijn 			sysoid = $2;
86946e6c55bSreyk 		}
87046e6c55bSreyk 		| SERVICES NUMBER		{
87160cc2743Smartijn 			if (conf->sc_system.sys_services != -1) {
87260cc2743Smartijn 				yyerror("system services already defined");
87360cc2743Smartijn 				YYERROR;
87460cc2743Smartijn 			}
87560cc2743Smartijn 			if ($2 < 0) {
87660cc2743Smartijn 				yyerror("system services too small");
87760cc2743Smartijn 				YYERROR;
87860cc2743Smartijn 			} else if ($2 > 127) {
87960cc2743Smartijn 				yyerror("system services too large");
88060cc2743Smartijn 				YYERROR;
88160cc2743Smartijn 			}
88260cc2743Smartijn 			conf->sc_system.sys_services = $2;
88346e6c55bSreyk 		}
88446e6c55bSreyk 		;
88546e6c55bSreyk 
8869352f69fSmartijn object		: OBJECTID oid NAME STRING optwrite 	{
88717240de1Smartijn 			struct object_sym *tobjects;
888d791c660Smartijn 
88917240de1Smartijn 			if ((tobjects = recallocarray(objects, nobjects,
89017240de1Smartijn 			    nobjects + 1, sizeof(*objects))) == NULL) {
89117240de1Smartijn 				yyerror("malloc");
89217240de1Smartijn 				free($2.descriptor);
8939352f69fSmartijn 				free($4);
89446e6c55bSreyk 			}
89517240de1Smartijn 			objects = tobjects;
89617240de1Smartijn 			nobjects++;
89717240de1Smartijn 			objects[nobjects - 1].oid = $2;
89817240de1Smartijn 			objects[nobjects - 1].name = $4;
89917240de1Smartijn 		} objectvalue
90046e6c55bSreyk 		;
90146e6c55bSreyk 
9029352f69fSmartijn objectvalue	: INTEGER NUMBER			{
9039352f69fSmartijn 			if ($2 < INT32_MIN) {
9049352f69fSmartijn 				yyerror("number too small");
9059352f69fSmartijn 				YYERROR;
9069352f69fSmartijn 			}
9079352f69fSmartijn 			if ($2 > INT32_MAX) {
9089352f69fSmartijn 				yyerror("number too large");
9099352f69fSmartijn 				YYERROR;
9109352f69fSmartijn 			}
91117240de1Smartijn 			objects[nobjects - 1].isint = 1;
91217240de1Smartijn 			objects[nobjects - 1].intval = $2;
91346e6c55bSreyk 		}
91446e6c55bSreyk 		| OCTETSTRING STRING			{
91517240de1Smartijn 			objects[nobjects - 1].isint = 0;
91617240de1Smartijn 			objects[nobjects - 1].sval = $2;
91746e6c55bSreyk 		}
91846e6c55bSreyk 		;
91946e6c55bSreyk 
92046e6c55bSreyk optwrite	: READONLY				{ $$ = 0; }
92146e6c55bSreyk 		| READWRITE				{ $$ = 1; }
92246e6c55bSreyk 		;
92346e6c55bSreyk 
92446e6c55bSreyk oid		: STRING				{
92517240de1Smartijn 			$$.descriptor = $1;
92617240de1Smartijn 			strlcpy($$.file, file->name, sizeof($$.file));
92717240de1Smartijn 			$$.lineno = file->lineno;
92846e6c55bSreyk 		}
92946e6c55bSreyk 		;
93046e6c55bSreyk 
93170201ef1Sblambert trapoid		: oid					{ $$ = $1; }
93270201ef1Sblambert 		| DEFAULT				{
93317240de1Smartijn 			if (($$.descriptor = strdup("1.3")) == NULL) {
93417240de1Smartijn 				yyerror("malloc");
93570201ef1Sblambert 				YYERROR;
93670201ef1Sblambert 			}
93717240de1Smartijn 			strlcpy($$.file, file->name, sizeof($$.file));
93817240de1Smartijn 			$$.lineno = file->lineno;
93970201ef1Sblambert 		}
94070201ef1Sblambert 		;
94170201ef1Sblambert 
94217240de1Smartijn hostoid		: /* empty */				{
94317240de1Smartijn 			$$.descriptor = NULL;
94417240de1Smartijn 			strlcpy($$.file, file->name, sizeof($$.file));
94517240de1Smartijn 			$$.lineno = file->lineno;
94617240de1Smartijn 		}
947769bc708Sreyk 		| OBJECTID oid				{ $$ = $2; }
948769bc708Sreyk 		;
949769bc708Sreyk 
950ab858812Smartijn usmuser		: USER STRING				{
951ab858812Smartijn 			if (strlen($2) > SNMPD_MAXUSERNAMELEN) {
952ab858812Smartijn 				yyerror("User name too long: %s", $2);
953ab858812Smartijn 				free($2);
954ab858812Smartijn 				YYERROR;
955ab858812Smartijn 			}
956ab858812Smartijn 			$$ = $2;
957ab858812Smartijn 		}
958ab858812Smartijn 		;
959ab858812Smartijn 
960ab858812Smartijn community	: COMMUNITY STRING			{
961ab858812Smartijn 			if (strlen($2) > SNMPD_MAXCOMMUNITYLEN) {
962ab858812Smartijn 				yyerror("Community too long: %s", $2);
963ab858812Smartijn 				free($2);
964ab858812Smartijn 				YYERROR;
965ab858812Smartijn 			}
966ab858812Smartijn 			$$ = $2;
967ab858812Smartijn 		}
968ab858812Smartijn 		;
969ab858812Smartijn 
970ab858812Smartijn optcommunity	: /* empty */				{ $$ = NULL; }
971ab858812Smartijn 		| community				{ $$ = $1; }
972ab858812Smartijn 		;
973ab858812Smartijn 
974ab858812Smartijn usmauthopt	: usmuser				{
975ab858812Smartijn 			$$.data = $1;
976ab858812Smartijn 			$$.value = -1;
977ab858812Smartijn 		}
978ab858812Smartijn 		| seclevel				{
979ab858812Smartijn 			$$.data = 0;
980ab858812Smartijn 			$$.value = $1;
981ab858812Smartijn 		}
982ab858812Smartijn 		;
983ab858812Smartijn 
984ab858812Smartijn usmauthopts	: /* empty */				{
985ab858812Smartijn 			$$.data = NULL;
986ab858812Smartijn 			$$.value = -1;
987ab858812Smartijn 		}
988ab858812Smartijn 		| usmauthopts usmauthopt		{
989ab858812Smartijn 			if ($2.data != NULL) {
990ab858812Smartijn 				if ($$.data != NULL) {
991ab858812Smartijn 					yyerror("user redefined");
992ab858812Smartijn 					free($2.data);
993ab858812Smartijn 					YYERROR;
994ab858812Smartijn 				}
995ab858812Smartijn 				$$.data = $2.data;
996ab858812Smartijn 			} else {
997ab858812Smartijn 				if ($$.value != -1) {
998ab858812Smartijn 					yyerror("seclevel redefined");
999ab858812Smartijn 					YYERROR;
1000ab858812Smartijn 				}
1001ab858812Smartijn 				$$.value = $2.value;
1002ab858812Smartijn 			}
1003ab858812Smartijn 		}
1004ab858812Smartijn 		;
1005ab858812Smartijn 
1006ab858812Smartijn hostauthv3	: usmauthopts				{
1007ab858812Smartijn 			if ($1.data == NULL) {
1008ab858812Smartijn 				yyerror("user missing");
1009ab858812Smartijn 				YYERROR;
1010ab858812Smartijn 			}
1011ab858812Smartijn 			$$.data = $1.data;
1012ab858812Smartijn 			$$.value = $1.value;
1013ab858812Smartijn 		}
1014ab858812Smartijn 		;
1015ab858812Smartijn 
1016ab858812Smartijn hostauth	: hostauthv3				{
1017ab858812Smartijn 			$$.type = SNMP_V3;
1018ab858812Smartijn 			$$.data = $1.data;
1019ab858812Smartijn 			$$.value = $1.value;
1020ab858812Smartijn 		}
1021ab858812Smartijn 		| SNMPV2 optcommunity			{
1022ab858812Smartijn 			$$.type = SNMP_V2;
1023ab858812Smartijn 			$$.data = $2;
1024ab858812Smartijn 		}
1025ab858812Smartijn 		| SNMPV3 hostauthv3			{
1026ab858812Smartijn 			$$.type = SNMP_V3;
1027ab858812Smartijn 			$$.data = $2.data;
1028ab858812Smartijn 			$$.value = $2.value;
1029ab858812Smartijn 		}
1030769bc708Sreyk 		;
1031769bc708Sreyk 
1032f005ecdcSjca srcaddr		: /* empty */				{ $$ = NULL; }
1033f005ecdcSjca 		| SRCADDR STRING			{ $$ = $2; }
1034f005ecdcSjca 		;
1035f005ecdcSjca 
1036ab858812Smartijn hostdef		: STRING hostoid hostauth srcaddr	{
103717240de1Smartijn 			struct sockaddr_storage ss, ssl = {};
1038967754d5Smartijn 			struct trap_address *tr;
103917240de1Smartijn 			struct trapaddress_sym *ttrapaddresses;
1040967754d5Smartijn 
104170787abdSmartijn 			if (host($1, SNMPTRAP_PORT, AF_UNSPEC, SOCK_DGRAM,
104270787abdSmartijn 			    &ss, 1) <= 0) {
10439b15f147Sreyk 				yyerror("invalid host: %s", $1);
10449b15f147Sreyk 				free($1);
104517240de1Smartijn 				free($2.descriptor);
1046ab858812Smartijn 				free($3.data);
1047967754d5Smartijn 				free($4);
10489b15f147Sreyk 				YYERROR;
10499b15f147Sreyk 			}
10509b15f147Sreyk 			free($1);
1051967754d5Smartijn 			if ($4 != NULL) {
105270787abdSmartijn 				if (host($4, "0", ss.ss_family, SOCK_DGRAM,
105370787abdSmartijn 				    &ss, 1) <= 0) {
105435b9b084Smartijn 					yyerror("invalid source-address: %s",
105535b9b084Smartijn 					    $4);
105617240de1Smartijn 					free($2.descriptor);
1057ab858812Smartijn 					free($3.data);
1058967754d5Smartijn 					free($4);
1059967754d5Smartijn 					YYERROR;
1060967754d5Smartijn 				}
1061967754d5Smartijn 				free($4);
1062967754d5Smartijn 			}
106317240de1Smartijn 
106417240de1Smartijn 			ttrapaddresses = reallocarray(trapaddresses,
106517240de1Smartijn 			    ntrapaddresses + 1, sizeof(*trapaddresses));
106617240de1Smartijn 			if (ttrapaddresses == NULL) {
106717240de1Smartijn 				yyerror("malloc");
106817240de1Smartijn 				free($2.descriptor);
106917240de1Smartijn 				free($3.data);
107017240de1Smartijn 				YYERROR;
107117240de1Smartijn 			}
107217240de1Smartijn 			trapaddresses = ttrapaddresses;
107317240de1Smartijn 			ntrapaddresses++;
107417240de1Smartijn 
107517240de1Smartijn 			if ((tr = calloc(1, sizeof(*tr))) == NULL) {
107617240de1Smartijn 				yyerror("calloc");
107717240de1Smartijn 				free($2.descriptor);
107817240de1Smartijn 				free($3.data);
107917240de1Smartijn 				ntrapaddresses--;
108017240de1Smartijn 				YYERROR;
108117240de1Smartijn 			}
108217240de1Smartijn 
108317240de1Smartijn 			tr->ta_ss = ss;
108417240de1Smartijn 			tr->ta_sslocal = ssl;
1085ab858812Smartijn 			tr->ta_version = $3.type;
108639d554e5Smartijn 			if ($3.type == SNMP_V2) {
1087ab858812Smartijn 				(void)strlcpy(tr->ta_community, $3.data,
1088ab858812Smartijn 				    sizeof(tr->ta_community));
1089ab858812Smartijn 				free($3.data);
1090ab858812Smartijn 			} else {
1091ab858812Smartijn 				tr->ta_usmusername = $3.data;
1092ab858812Smartijn 				tr->ta_seclevel = $3.value;
1093ab858812Smartijn 			}
109417240de1Smartijn 
109517240de1Smartijn 			trapaddresses[ntrapaddresses - 1].oid = $2;
109617240de1Smartijn 			trapaddresses[ntrapaddresses - 1].tr = tr;
10979b15f147Sreyk 		}
10989b15f147Sreyk 		;
10999b15f147Sreyk 
11009b15f147Sreyk hostlist	: /* empty */
11019b15f147Sreyk 		| hostlist comma hostdef
11029b15f147Sreyk 		;
11039b15f147Sreyk 
11049b15f147Sreyk host		: hostdef
11059b15f147Sreyk 		| '{' hostlist '}'
11069b15f147Sreyk 		;
11079b15f147Sreyk 
11089b15f147Sreyk comma		: /* empty */
11099b15f147Sreyk 		| ','
11109b15f147Sreyk 		;
11119b15f147Sreyk 
1112ab858812Smartijn seclevel	: SECLEVEL NONE	{ $$ = 0; }
1113ab858812Smartijn 		| SECLEVEL AUTH	{ $$ = SNMP_MSGFLAG_AUTH; }
1114ab858812Smartijn 		| SECLEVEL ENC	{ $$ = SNMP_MSGFLAG_AUTH | SNMP_MSGFLAG_PRIV; }
11156a925a1dSreyk 		;
11166a925a1dSreyk 
11176a925a1dSreyk userspecs	: /* empty */
11186a925a1dSreyk 		| userspecs userspec
11196a925a1dSreyk 		;
11206a925a1dSreyk 
11216a925a1dSreyk userspec	: AUTHKEY STRING		{
11226a925a1dSreyk 			user->uu_authkey = $2;
11236a925a1dSreyk 		}
11246a925a1dSreyk 		| AUTH auth			{
11256a925a1dSreyk 			user->uu_auth = $2;
11266a925a1dSreyk 		}
11276a925a1dSreyk 		| ENCKEY STRING			{
11286a925a1dSreyk 			user->uu_privkey = $2;
11296a925a1dSreyk 		}
11306a925a1dSreyk 		| ENC enc			{
11316a925a1dSreyk 			user->uu_priv = $2;
11326a925a1dSreyk 		}
11336a925a1dSreyk 		;
11346a925a1dSreyk 
11356a925a1dSreyk auth		: STRING			{
1136b3c4c4d6Sreyk 			if (strcasecmp($1, "hmac-md5") == 0 ||
1137b3c4c4d6Sreyk 			    strcasecmp($1, "hmac-md5-96") == 0)
11386a925a1dSreyk 				$$ = AUTH_MD5;
1139b3c4c4d6Sreyk 			else if (strcasecmp($1, "hmac-sha1") == 0 ||
1140b3c4c4d6Sreyk 			     strcasecmp($1, "hmac-sha1-96") == 0)
11416a925a1dSreyk 				$$ = AUTH_SHA1;
11428360a08aSmartijn 			else if (strcasecmp($1, "hmac-sha224") == 0 ||
11438360a08aSmartijn 			    strcasecmp($1, "usmHMAC128SHA224AuthProtocol") == 0)
11448360a08aSmartijn 				$$ = AUTH_SHA224;
11458360a08aSmartijn 			else if (strcasecmp($1, "hmac-sha256") == 0 ||
11468360a08aSmartijn 			    strcasecmp($1, "usmHMAC192SHA256AuthProtocol") == 0)
11478360a08aSmartijn 				$$ = AUTH_SHA256;
11488360a08aSmartijn 			else if (strcasecmp($1, "hmac-sha384") == 0 ||
11498360a08aSmartijn 			    strcasecmp($1, "usmHMAC256SHA384AuthProtocol") == 0)
11508360a08aSmartijn 				$$ = AUTH_SHA384;
11518360a08aSmartijn 			else if (strcasecmp($1, "hmac-sha512") == 0 ||
11528360a08aSmartijn 			    strcasecmp($1, "usmHMAC384SHA512AuthProtocol") == 0)
11538360a08aSmartijn 				$$ = AUTH_SHA512;
11546a925a1dSreyk 			else {
11556a925a1dSreyk 				yyerror("syntax error, bad auth hmac");
11566a925a1dSreyk 				free($1);
11576a925a1dSreyk 				YYERROR;
11586a925a1dSreyk 			}
11596a925a1dSreyk 			free($1);
11606a925a1dSreyk 		}
11616a925a1dSreyk 		;
11626a925a1dSreyk 
11636a925a1dSreyk enc		: STRING			{
1164b3c4c4d6Sreyk 			if (strcasecmp($1, "des") == 0 ||
1165b3c4c4d6Sreyk 			    strcasecmp($1, "cbc-des") == 0)
11666a925a1dSreyk 				$$ = PRIV_DES;
1167b3c4c4d6Sreyk 			else if (strcasecmp($1, "aes") == 0 ||
1168b3c4c4d6Sreyk 			    strcasecmp($1, "cfb128-aes-128") == 0)
11696a925a1dSreyk 				$$ = PRIV_AES;
11706a925a1dSreyk 			else {
11716a925a1dSreyk 				yyerror("syntax error, bad encryption cipher");
11726a925a1dSreyk 				free($1);
11736a925a1dSreyk 				YYERROR;
11746a925a1dSreyk 			}
11756a925a1dSreyk 			free($1);
11766a925a1dSreyk 
11776a925a1dSreyk 		}
11786a925a1dSreyk 		;
11796a925a1dSreyk 
118070201ef1Sblambert cmd		: STRING		{
118170201ef1Sblambert 			struct trapcmd	*cmd;
118270201ef1Sblambert 			size_t		 span, limit;
118370201ef1Sblambert 			char		*pos, **args, **args2;
118470201ef1Sblambert 			int		 nargs = 32;		/* XXX */
118570201ef1Sblambert 
118670201ef1Sblambert 			if ((cmd = calloc(1, sizeof(*cmd))) == NULL ||
118770201ef1Sblambert 			    (args = calloc(nargs, sizeof(char *))) == NULL) {
118870201ef1Sblambert 				free(cmd);
118970201ef1Sblambert 				free($1);
119070201ef1Sblambert 				YYERROR;
119170201ef1Sblambert 			}
119270201ef1Sblambert 
119370201ef1Sblambert 			pos = $1;
119470201ef1Sblambert 			limit = strlen($1);
119570201ef1Sblambert 
11969f7b078aStb 			while (pos < $1 + limit &&
11979f7b078aStb 			    (span = strcspn(pos, " \t")) != 0) {
119870201ef1Sblambert 				pos[span] = '\0';
119970201ef1Sblambert 				args[cmd->cmd_argc] = strdup(pos);
120070201ef1Sblambert 				if (args[cmd->cmd_argc] == NULL) {
120170201ef1Sblambert 					trapcmd_free(cmd);
120270201ef1Sblambert 					free(args);
120370201ef1Sblambert 					free($1);
120470201ef1Sblambert 					YYERROR;
120570201ef1Sblambert 				}
120670201ef1Sblambert 				cmd->cmd_argc++;
120770201ef1Sblambert 				if (cmd->cmd_argc >= nargs - 1) {
120870201ef1Sblambert 					nargs *= 2;
120970201ef1Sblambert 					args2 = calloc(nargs, sizeof(char *));
121070201ef1Sblambert 					if (args2 == NULL) {
121170201ef1Sblambert 						trapcmd_free(cmd);
121270201ef1Sblambert 						free(args);
121370201ef1Sblambert 						free($1);
121470201ef1Sblambert 						YYERROR;
121570201ef1Sblambert 					}
121670201ef1Sblambert 					args = args2;
121770201ef1Sblambert 				}
121870201ef1Sblambert 				pos += span + 1;
121970201ef1Sblambert 			}
122070201ef1Sblambert 			free($1);
122170201ef1Sblambert 			cmd->cmd_argv = args;
122270201ef1Sblambert 			$$.data = cmd;
122370201ef1Sblambert 		}
122470201ef1Sblambert 		;
122570201ef1Sblambert 
1226c3100810Smartijn mib		: MIB DIRECTORY STRING		{
1227c3100810Smartijn 			mib_parsedir($3);
1228c3100810Smartijn 			mibparsed = 1;
1229c3100810Smartijn 		}
1230c3100810Smartijn 		;
1231c3100810Smartijn 
123246e6c55bSreyk %%
123346e6c55bSreyk 
123446e6c55bSreyk struct keywords {
123546e6c55bSreyk 	const char	*k_name;
123646e6c55bSreyk 	int		 k_val;
123746e6c55bSreyk };
123846e6c55bSreyk 
123946e6c55bSreyk int
yyerror(const char * fmt,...)124046e6c55bSreyk yyerror(const char *fmt, ...)
124146e6c55bSreyk {
124246e6c55bSreyk 	va_list		 ap;
1243e78bcbddSbluhm 	char		*msg;
124446e6c55bSreyk 
124546e6c55bSreyk 	file->errors++;
124646e6c55bSreyk 	va_start(ap, fmt);
1247e78bcbddSbluhm 	if (vasprintf(&msg, fmt, ap) == -1)
1248e78bcbddSbluhm 		fatalx("yyerror vasprintf");
124946e6c55bSreyk 	va_end(ap);
1250e78bcbddSbluhm 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
1251e78bcbddSbluhm 	free(msg);
125246e6c55bSreyk 	return (0);
125346e6c55bSreyk }
125446e6c55bSreyk 
125546e6c55bSreyk int
kw_cmp(const void * k,const void * e)125646e6c55bSreyk kw_cmp(const void *k, const void *e)
125746e6c55bSreyk {
125846e6c55bSreyk 	return (strcmp(k, ((const struct keywords *)e)->k_name));
125946e6c55bSreyk }
126046e6c55bSreyk 
126146e6c55bSreyk int
lookup(char * s)126246e6c55bSreyk lookup(char *s)
126346e6c55bSreyk {
126446e6c55bSreyk 	/* this has to be sorted always */
126546e6c55bSreyk 	static const struct keywords keywords[] = {
126673b5c081Smartijn 		{ "agentid",			AGENTID },
12674100cc5fSmartijn 		{ "agentx",			AGENTX },
12686a925a1dSreyk 		{ "auth",			AUTH },
12696a925a1dSreyk 		{ "authkey",			AUTHKEY },
1270614c3698Smartijn 		{ "blocklist",			BLOCKLIST },
127146e6c55bSreyk 		{ "community",			COMMUNITY },
127246e6c55bSreyk 		{ "contact",			CONTACT },
127370201ef1Sblambert 		{ "default",			DEFAULT },
127446e6c55bSreyk 		{ "description",		DESCR },
1275c3100810Smartijn 		{ "directory",			DIRECTORY },
12766a925a1dSreyk 		{ "enc",			ENC },
12776a925a1dSreyk 		{ "enckey",			ENCKEY },
127873b5c081Smartijn 		{ "engineid",			ENGINEID },
127982baf71dSsthen 		{ "filter-routes",		RTFILTER },
12804100cc5fSmartijn 		{ "group",			GROUP },
128170201ef1Sblambert 		{ "handle",			HANDLE },
128273b5c081Smartijn 		{ "hosthash",			HOSTHASH },
128346e6c55bSreyk 		{ "include",			INCLUDE },
128446e6c55bSreyk 		{ "integer",			INTEGER },
128573b5c081Smartijn 		{ "ipv4",			IP4 },
128673b5c081Smartijn 		{ "ipv6",			IP6 },
128746e6c55bSreyk 		{ "listen",			LISTEN },
128846e6c55bSreyk 		{ "location",			LOCATION },
128973b5c081Smartijn 		{ "mac",			MAC },
1290c3100810Smartijn 		{ "mib",			MIB },
12914100cc5fSmartijn 		{ "mode",			MODE },
129246e6c55bSreyk 		{ "name",			NAME },
12936a925a1dSreyk 		{ "none",			NONE },
129420f2292fSmartijn 		{ "notify",			NOTIFY },
129573b5c081Smartijn 		{ "octets",			OCTETS },
129646e6c55bSreyk 		{ "oid",			OBJECTID },
129746e6c55bSreyk 		{ "on",				ON },
129873b5c081Smartijn 		{ "openbsd",			OPENBSD },
12994100cc5fSmartijn 		{ "owner",			OWNER },
13004100cc5fSmartijn 		{ "path",			PATH },
130173b5c081Smartijn 		{ "pen",			PEN },
1302756b4b7aSmartijn 		{ "port",			PORT },
130320f2292fSmartijn 		{ "read",			READ },
130446e6c55bSreyk 		{ "read-only",			READONLY },
130546e6c55bSreyk 		{ "read-write",			READWRITE },
13069b15f147Sreyk 		{ "receiver",			RECEIVER },
13076a925a1dSreyk 		{ "seclevel",			SECLEVEL },
130846e6c55bSreyk 		{ "services",			SERVICES },
1309c92471afSmartijn 		{ "snmpv1",			SNMPV1 },
1310c92471afSmartijn 		{ "snmpv2c",			SNMPV2 },
1311c92471afSmartijn 		{ "snmpv3",			SNMPV3 },
1312f005ecdcSjca 		{ "source-address",		SRCADDR },
131346e6c55bSreyk 		{ "string",			OCTETSTRING },
131446e6c55bSreyk 		{ "system",			SYSTEM },
13157bfcc0c0Smpf 		{ "tcp",			TCP },
131673b5c081Smartijn 		{ "text",			TEXT },
13176a925a1dSreyk 		{ "trap",			TRAP },
13187bfcc0c0Smpf 		{ "udp",			UDP },
131920f2292fSmartijn 		{ "user",			USER },
132020f2292fSmartijn 		{ "write",			WRITE }
132146e6c55bSreyk 	};
132246e6c55bSreyk 	const struct keywords	*p;
132346e6c55bSreyk 
132446e6c55bSreyk 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
132546e6c55bSreyk 	    sizeof(keywords[0]), kw_cmp);
132646e6c55bSreyk 
132746e6c55bSreyk 	if (p)
132846e6c55bSreyk 		return (p->k_val);
132946e6c55bSreyk 	else
133046e6c55bSreyk 		return (STRING);
133146e6c55bSreyk }
133246e6c55bSreyk 
1333588ec6bcSdenis #define START_EXPAND	1
1334588ec6bcSdenis #define DONE_EXPAND	2
133546e6c55bSreyk 
1336588ec6bcSdenis static int	expanding;
1337588ec6bcSdenis 
1338588ec6bcSdenis int
igetc(void)1339588ec6bcSdenis igetc(void)
1340588ec6bcSdenis {
1341588ec6bcSdenis 	int	c;
1342588ec6bcSdenis 
1343588ec6bcSdenis 	while (1) {
1344588ec6bcSdenis 		if (file->ungetpos > 0)
1345588ec6bcSdenis 			c = file->ungetbuf[--file->ungetpos];
1346588ec6bcSdenis 		else c = getc(file->stream);
1347588ec6bcSdenis 
1348588ec6bcSdenis 		if (c == START_EXPAND)
1349588ec6bcSdenis 			expanding = 1;
1350588ec6bcSdenis 		else if (c == DONE_EXPAND)
1351588ec6bcSdenis 			expanding = 0;
1352588ec6bcSdenis 		else
1353588ec6bcSdenis 			break;
1354588ec6bcSdenis 	}
1355588ec6bcSdenis 	return (c);
1356588ec6bcSdenis }
135746e6c55bSreyk 
135846e6c55bSreyk int
lgetc(int quotec)135946e6c55bSreyk lgetc(int quotec)
136046e6c55bSreyk {
136146e6c55bSreyk 	int		c, next;
136246e6c55bSreyk 
136346e6c55bSreyk 	if (quotec) {
1364588ec6bcSdenis 		if ((c = igetc()) == EOF) {
136546e6c55bSreyk 			yyerror("reached end of file while parsing quoted string");
13665bcdf83cSmpf 			if (file == topfile || popfile() == EOF)
136746e6c55bSreyk 				return (EOF);
136846e6c55bSreyk 			return (quotec);
136946e6c55bSreyk 		}
137046e6c55bSreyk 		return (c);
137146e6c55bSreyk 	}
137246e6c55bSreyk 
1373588ec6bcSdenis 	while ((c = igetc()) == '\\') {
1374588ec6bcSdenis 		next = igetc();
137546e6c55bSreyk 		if (next != '\n') {
137646e6c55bSreyk 			c = next;
137746e6c55bSreyk 			break;
137846e6c55bSreyk 		}
137946e6c55bSreyk 		yylval.lineno = file->lineno;
138046e6c55bSreyk 		file->lineno++;
138146e6c55bSreyk 	}
138246e6c55bSreyk 	if (c == '\t' || c == ' ') {
138346e6c55bSreyk 		/* Compress blanks to a single space. */
138446e6c55bSreyk 		do {
138546e6c55bSreyk 			c = getc(file->stream);
138646e6c55bSreyk 		} while (c == '\t' || c == ' ');
138746e6c55bSreyk 		ungetc(c, file->stream);
138846e6c55bSreyk 		c = ' ';
138946e6c55bSreyk 	}
139046e6c55bSreyk 
1391588ec6bcSdenis 	if (c == EOF) {
1392588ec6bcSdenis 		/*
1393588ec6bcSdenis 		 * Fake EOL when hit EOF for the first time. This gets line
1394588ec6bcSdenis 		 * count right if last line in included file is syntactically
1395588ec6bcSdenis 		 * invalid and has no newline.
1396588ec6bcSdenis 		 */
1397588ec6bcSdenis 		if (file->eof_reached == 0) {
1398588ec6bcSdenis 			file->eof_reached = 1;
1399588ec6bcSdenis 			return ('\n');
1400588ec6bcSdenis 		}
140146e6c55bSreyk 		while (c == EOF) {
14025bcdf83cSmpf 			if (file == topfile || popfile() == EOF)
140346e6c55bSreyk 				return (EOF);
1404588ec6bcSdenis 			c = igetc();
1405588ec6bcSdenis 		}
140646e6c55bSreyk 	}
140746e6c55bSreyk 	return (c);
140846e6c55bSreyk }
140946e6c55bSreyk 
1410588ec6bcSdenis void
lungetc(int c)141146e6c55bSreyk lungetc(int c)
141246e6c55bSreyk {
141346e6c55bSreyk 	if (c == EOF)
1414588ec6bcSdenis 		return;
1415588ec6bcSdenis 
1416588ec6bcSdenis 	if (file->ungetpos >= file->ungetsize) {
1417588ec6bcSdenis 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
1418588ec6bcSdenis 		if (p == NULL)
1419a062aa9dSkrw 			err(1, "%s", __func__);
1420588ec6bcSdenis 		file->ungetbuf = p;
1421588ec6bcSdenis 		file->ungetsize *= 2;
142246e6c55bSreyk 	}
1423588ec6bcSdenis 	file->ungetbuf[file->ungetpos++] = c;
142446e6c55bSreyk }
142546e6c55bSreyk 
142646e6c55bSreyk int
findeol(void)142746e6c55bSreyk findeol(void)
142846e6c55bSreyk {
142946e6c55bSreyk 	int	c;
143046e6c55bSreyk 
143146e6c55bSreyk 	/* skip to either EOF or the first real EOL */
143246e6c55bSreyk 	while (1) {
143346e6c55bSreyk 		c = lgetc(0);
143446e6c55bSreyk 		if (c == '\n') {
143546e6c55bSreyk 			file->lineno++;
143646e6c55bSreyk 			break;
143746e6c55bSreyk 		}
143846e6c55bSreyk 		if (c == EOF)
143946e6c55bSreyk 			break;
144046e6c55bSreyk 	}
144146e6c55bSreyk 	return (ERROR);
144246e6c55bSreyk }
144346e6c55bSreyk 
144446e6c55bSreyk int
yylex(void)144546e6c55bSreyk yylex(void)
144646e6c55bSreyk {
144708f6ba19Snaddy 	char	 buf[8096];
144808f6ba19Snaddy 	char	*p, *val;
144946e6c55bSreyk 	int	 quotec, next, c;
145046e6c55bSreyk 	int	 token;
145146e6c55bSreyk 
145246e6c55bSreyk top:
145346e6c55bSreyk 	p = buf;
14541be5e896Sreyk 	while ((c = lgetc(0)) == ' ' || c == '\t')
145546e6c55bSreyk 		; /* nothing */
145646e6c55bSreyk 
145746e6c55bSreyk 	yylval.lineno = file->lineno;
145846e6c55bSreyk 	if (c == '#')
145946e6c55bSreyk 		while ((c = lgetc(0)) != '\n' && c != EOF)
146046e6c55bSreyk 			; /* nothing */
1461588ec6bcSdenis 	if (c == '$' && !expanding) {
146246e6c55bSreyk 		while (1) {
146346e6c55bSreyk 			if ((c = lgetc(0)) == EOF)
146446e6c55bSreyk 				return (0);
146546e6c55bSreyk 
146646e6c55bSreyk 			if (p + 1 >= buf + sizeof(buf) - 1) {
146746e6c55bSreyk 				yyerror("string too long");
146846e6c55bSreyk 				return (findeol());
146946e6c55bSreyk 			}
147046e6c55bSreyk 			if (isalnum(c) || c == '_') {
1471015d7b4dSbenno 				*p++ = c;
147246e6c55bSreyk 				continue;
147346e6c55bSreyk 			}
147446e6c55bSreyk 			*p = '\0';
147546e6c55bSreyk 			lungetc(c);
147646e6c55bSreyk 			break;
147746e6c55bSreyk 		}
147846e6c55bSreyk 		val = symget(buf);
147946e6c55bSreyk 		if (val == NULL) {
148046e6c55bSreyk 			yyerror("macro '%s' not defined", buf);
148146e6c55bSreyk 			return (findeol());
148246e6c55bSreyk 		}
1483588ec6bcSdenis 		p = val + strlen(val) - 1;
1484588ec6bcSdenis 		lungetc(DONE_EXPAND);
1485588ec6bcSdenis 		while (p >= val) {
148608f6ba19Snaddy 			lungetc((unsigned char)*p);
1487588ec6bcSdenis 			p--;
1488588ec6bcSdenis 		}
1489588ec6bcSdenis 		lungetc(START_EXPAND);
149046e6c55bSreyk 		goto top;
149146e6c55bSreyk 	}
149246e6c55bSreyk 
149346e6c55bSreyk 	switch (c) {
149446e6c55bSreyk 	case '\'':
149546e6c55bSreyk 	case '"':
149646e6c55bSreyk 		quotec = c;
149746e6c55bSreyk 		while (1) {
149846e6c55bSreyk 			if ((c = lgetc(quotec)) == EOF)
149946e6c55bSreyk 				return (0);
150046e6c55bSreyk 			if (c == '\n') {
150146e6c55bSreyk 				file->lineno++;
150246e6c55bSreyk 				continue;
150346e6c55bSreyk 			} else if (c == '\\') {
150446e6c55bSreyk 				if ((next = lgetc(quotec)) == EOF)
150546e6c55bSreyk 					return (0);
1506a1533359Ssashan 				if (next == quotec || next == ' ' ||
1507a1533359Ssashan 				    next == '\t')
150846e6c55bSreyk 					c = next;
1509daf24110Shenning 				else if (next == '\n') {
1510daf24110Shenning 					file->lineno++;
151146e6c55bSreyk 					continue;
1512daf24110Shenning 				} else
151346e6c55bSreyk 					lungetc(next);
151446e6c55bSreyk 			} else if (c == quotec) {
151546e6c55bSreyk 				*p = '\0';
151646e6c55bSreyk 				break;
151741eef22fSjsg 			} else if (c == '\0') {
151841eef22fSjsg 				yyerror("syntax error");
151941eef22fSjsg 				return (findeol());
152046e6c55bSreyk 			}
152146e6c55bSreyk 			if (p + 1 >= buf + sizeof(buf) - 1) {
152246e6c55bSreyk 				yyerror("string too long");
152346e6c55bSreyk 				return (findeol());
152446e6c55bSreyk 			}
1525015d7b4dSbenno 			*p++ = c;
152646e6c55bSreyk 		}
152746e6c55bSreyk 		yylval.v.string = strdup(buf);
152846e6c55bSreyk 		if (yylval.v.string == NULL)
1529a062aa9dSkrw 			err(1, "%s", __func__);
153046e6c55bSreyk 		return (STRING);
153146e6c55bSreyk 	}
153246e6c55bSreyk 
153346e6c55bSreyk #define allowed_to_end_number(x) \
153446e6c55bSreyk 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
153546e6c55bSreyk 
153646e6c55bSreyk 	if (c == '-' || isdigit(c)) {
153746e6c55bSreyk 		do {
153846e6c55bSreyk 			*p++ = c;
1539915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
154046e6c55bSreyk 				yyerror("string too long");
154146e6c55bSreyk 				return (findeol());
154246e6c55bSreyk 			}
154346e6c55bSreyk 		} while ((c = lgetc(0)) != EOF && isdigit(c));
154446e6c55bSreyk 		lungetc(c);
154546e6c55bSreyk 		if (p == buf + 1 && buf[0] == '-')
154646e6c55bSreyk 			goto nodigits;
154746e6c55bSreyk 		if (c == EOF || allowed_to_end_number(c)) {
154846e6c55bSreyk 			const char *errstr = NULL;
154946e6c55bSreyk 
155046e6c55bSreyk 			*p = '\0';
155146e6c55bSreyk 			yylval.v.number = strtonum(buf, LLONG_MIN,
155246e6c55bSreyk 			    LLONG_MAX, &errstr);
155346e6c55bSreyk 			if (errstr) {
155446e6c55bSreyk 				yyerror("\"%s\" invalid number: %s",
155546e6c55bSreyk 				    buf, errstr);
155646e6c55bSreyk 				return (findeol());
155746e6c55bSreyk 			}
155846e6c55bSreyk 			return (NUMBER);
155946e6c55bSreyk 		} else {
156046e6c55bSreyk nodigits:
156146e6c55bSreyk 			while (p > buf + 1)
156208f6ba19Snaddy 				lungetc((unsigned char)*--p);
156308f6ba19Snaddy 			c = (unsigned char)*--p;
156446e6c55bSreyk 			if (c == '-')
156546e6c55bSreyk 				return (c);
156646e6c55bSreyk 		}
156746e6c55bSreyk 	}
156846e6c55bSreyk 
156946e6c55bSreyk #define allowed_in_string(x) \
157046e6c55bSreyk 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
157146e6c55bSreyk 	x != '{' && x != '}' && \
157246e6c55bSreyk 	x != '!' && x != '=' && x != '#' && \
157346e6c55bSreyk 	x != ','))
157446e6c55bSreyk 
157546e6c55bSreyk 	if (isalnum(c) || c == ':' || c == '_') {
157646e6c55bSreyk 		do {
157746e6c55bSreyk 			*p++ = c;
1578915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
157946e6c55bSreyk 				yyerror("string too long");
158046e6c55bSreyk 				return (findeol());
158146e6c55bSreyk 			}
158246e6c55bSreyk 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
158346e6c55bSreyk 		lungetc(c);
158446e6c55bSreyk 		*p = '\0';
158546e6c55bSreyk 		if ((token = lookup(buf)) == STRING)
158646e6c55bSreyk 			if ((yylval.v.string = strdup(buf)) == NULL)
1587a062aa9dSkrw 				err(1, "%s", __func__);
158846e6c55bSreyk 		return (token);
158946e6c55bSreyk 	}
159046e6c55bSreyk 	if (c == '\n') {
159146e6c55bSreyk 		yylval.lineno = file->lineno;
159246e6c55bSreyk 		file->lineno++;
159346e6c55bSreyk 	}
159446e6c55bSreyk 	if (c == EOF)
159546e6c55bSreyk 		return (0);
159646e6c55bSreyk 	return (c);
159746e6c55bSreyk }
159846e6c55bSreyk 
159946e6c55bSreyk int
check_file_secrecy(int fd,const char * fname)160046e6c55bSreyk check_file_secrecy(int fd, const char *fname)
160146e6c55bSreyk {
160246e6c55bSreyk 	struct stat	st;
160346e6c55bSreyk 
160446e6c55bSreyk 	if (fstat(fd, &st)) {
160546e6c55bSreyk 		log_warn("cannot stat %s", fname);
160646e6c55bSreyk 		return (-1);
160746e6c55bSreyk 	}
160846e6c55bSreyk 	if (st.st_uid != 0 && st.st_uid != getuid()) {
160946e6c55bSreyk 		log_warnx("%s: owner not root or current user", fname);
161046e6c55bSreyk 		return (-1);
161146e6c55bSreyk 	}
16127140c133Shenning 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
16137140c133Shenning 		log_warnx("%s: group writable or world read/writable", fname);
161446e6c55bSreyk 		return (-1);
161546e6c55bSreyk 	}
161646e6c55bSreyk 	return (0);
161746e6c55bSreyk }
161846e6c55bSreyk 
161946e6c55bSreyk struct file *
pushfile(const char * name,int secret)162046e6c55bSreyk pushfile(const char *name, int secret)
162146e6c55bSreyk {
162246e6c55bSreyk 	struct file	*nfile;
162346e6c55bSreyk 
16247fc93de0Stobias 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
16256a3d55f9Skrw 		log_warn("%s", __func__);
162646e6c55bSreyk 		return (NULL);
162746e6c55bSreyk 	}
16287fc93de0Stobias 	if ((nfile->name = strdup(name)) == NULL) {
16296a3d55f9Skrw 		log_warn("%s", __func__);
16307fc93de0Stobias 		free(nfile);
16317fc93de0Stobias 		return (NULL);
16327fc93de0Stobias 	}
163346e6c55bSreyk 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
16346a3d55f9Skrw 		log_warn("%s: %s", __func__, nfile->name);
163546e6c55bSreyk 		free(nfile->name);
163646e6c55bSreyk 		free(nfile);
163746e6c55bSreyk 		return (NULL);
163846e6c55bSreyk 	} else if (secret &&
163946e6c55bSreyk 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
164046e6c55bSreyk 		fclose(nfile->stream);
164146e6c55bSreyk 		free(nfile->name);
164246e6c55bSreyk 		free(nfile);
164346e6c55bSreyk 		return (NULL);
164446e6c55bSreyk 	}
1645588ec6bcSdenis 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1646588ec6bcSdenis 	nfile->ungetsize = 16;
1647588ec6bcSdenis 	nfile->ungetbuf = malloc(nfile->ungetsize);
1648588ec6bcSdenis 	if (nfile->ungetbuf == NULL) {
16496a3d55f9Skrw 		log_warn("%s", __func__);
1650588ec6bcSdenis 		fclose(nfile->stream);
1651588ec6bcSdenis 		free(nfile->name);
1652588ec6bcSdenis 		free(nfile);
1653588ec6bcSdenis 		return (NULL);
1654588ec6bcSdenis 	}
165546e6c55bSreyk 	TAILQ_INSERT_TAIL(&files, nfile, entry);
165646e6c55bSreyk 	return (nfile);
165746e6c55bSreyk }
165846e6c55bSreyk 
165946e6c55bSreyk int
popfile(void)166046e6c55bSreyk popfile(void)
166146e6c55bSreyk {
166246e6c55bSreyk 	struct file	*prev;
166346e6c55bSreyk 
16645bcdf83cSmpf 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
166546e6c55bSreyk 		prev->errors += file->errors;
16665bcdf83cSmpf 
166746e6c55bSreyk 	TAILQ_REMOVE(&files, file, entry);
166846e6c55bSreyk 	fclose(file->stream);
166946e6c55bSreyk 	free(file->name);
1670588ec6bcSdenis 	free(file->ungetbuf);
167146e6c55bSreyk 	free(file);
167246e6c55bSreyk 	file = prev;
16735bcdf83cSmpf 	return (file ? 0 : EOF);
167446e6c55bSreyk }
167546e6c55bSreyk 
167617240de1Smartijn int
resolve_oid(struct ber_oid * dst,struct oid_sym * src)167717240de1Smartijn resolve_oid(struct ber_oid *dst, struct oid_sym *src)
167817240de1Smartijn {
167917240de1Smartijn 	struct file f = { .name = src->file, };
168017240de1Smartijn 	const char *error;
168117240de1Smartijn 
168217240de1Smartijn 	file = &f;
168317240de1Smartijn 	yylval.lineno = src->lineno;
168417240de1Smartijn 
168517240de1Smartijn 	if ((error = mib_string2oid(src->descriptor, dst)) != NULL) {
168617240de1Smartijn 		if (smi_string2oid(src->descriptor, dst) == -1) {
168717240de1Smartijn 			yyerror("%s", error);
168817240de1Smartijn 			free(src->descriptor);
168917240de1Smartijn 			return -1;
169017240de1Smartijn 		}
169117240de1Smartijn 		yyerror("deprecated oid format");
169217240de1Smartijn 	}
169317240de1Smartijn 	free(src->descriptor);
169417240de1Smartijn 
169517240de1Smartijn 	return 0;
169617240de1Smartijn }
169717240de1Smartijn 
169817240de1Smartijn int
resolve_oids(void)169917240de1Smartijn resolve_oids(void)
170017240de1Smartijn {
170117240de1Smartijn 	struct file f;
170217240de1Smartijn 	struct ber_oid oid;
170317240de1Smartijn 	const char *error;
170417240de1Smartijn 	size_t i;
170517240de1Smartijn 
170617240de1Smartijn 	conf->sc_blocklist = calloc(nblocklist, sizeof(*conf->sc_blocklist));
170717240de1Smartijn 	if (conf->sc_blocklist == NULL)
170817240de1Smartijn 		fatal("malloc");
170917240de1Smartijn 
171017240de1Smartijn 	conf->sc_nblocklist = nblocklist;
171117240de1Smartijn 	for (i = 0; i < nblocklist; i++) {
171217240de1Smartijn 		if (resolve_oid(&conf->sc_blocklist[i], &blocklist[i]) == -1)
171317240de1Smartijn 			return -1;
171417240de1Smartijn 	}
171517240de1Smartijn 	free(blocklist);
171617240de1Smartijn 
171717240de1Smartijn 	if (sysoid.descriptor != NULL) {
171817240de1Smartijn 		if (resolve_oid(&conf->sc_system.sys_oid, &sysoid) == -1)
171917240de1Smartijn 			return -1;
172017240de1Smartijn 	}
172117240de1Smartijn 
172217240de1Smartijn 	for (i = 0; i < nobjects; i++) {
172317240de1Smartijn 		if (resolve_oid(&oid, &objects[i].oid) == -1)
172417240de1Smartijn 			return -1;
172517240de1Smartijn 		file = &f;
172617240de1Smartijn 		f.name = objects[i].oid.file;
172717240de1Smartijn 		yylval.lineno = objects[i].oid.lineno;
172817240de1Smartijn 		if ((error = smi_insert(&oid, objects[i].name)) != NULL) {
172917240de1Smartijn 			yyerror("%s", error);
173017240de1Smartijn 			return -1;
173117240de1Smartijn 		}
173217240de1Smartijn 		if (objects[i].isint) {
173317240de1Smartijn 			if ((error = appl_internal_object_int(
173417240de1Smartijn 			    &oid, objects[i].intval)) != NULL) {
173517240de1Smartijn 				yyerror("%s", error);
173617240de1Smartijn 				return -1;
173717240de1Smartijn 			}
173817240de1Smartijn 		} else {
173917240de1Smartijn 			if ((error = appl_internal_object_string(
174017240de1Smartijn 			    &oid, objects[i].sval)) != NULL) {
174117240de1Smartijn 				yyerror("%s", error);
174217240de1Smartijn 				return -1;
174317240de1Smartijn 			}
174417240de1Smartijn 		}
174517240de1Smartijn 		free(objects[i].name);
174617240de1Smartijn 	}
174717240de1Smartijn 	free(objects);
174817240de1Smartijn 
174917240de1Smartijn 	for (i = 0; i < ntrapcmds; i++) {
175017240de1Smartijn 		if (resolve_oid(
175117240de1Smartijn 		    &trapcmds[i].cmd->cmd_oid, &trapcmds[i].oid) == -1)
175217240de1Smartijn 			return -1;
175317240de1Smartijn 		f.name = trapcmds[i].oid.file;
175417240de1Smartijn 		yylval.lineno = trapcmds[i].oid.lineno;
175517240de1Smartijn 		file = &f;
175617240de1Smartijn 		if (trapcmd_add(trapcmds[i].cmd) != 0) {
175717240de1Smartijn 			yyerror("duplicate oid");
175817240de1Smartijn 			return -1;
175917240de1Smartijn 		}
176017240de1Smartijn 	}
176117240de1Smartijn 	free(trapcmds);
176217240de1Smartijn 
176317240de1Smartijn 	for (i = 0; i < ntrapaddresses; i++) {
1764ba93604fSmartijn 		if (trapaddresses[i].oid.descriptor == NULL)
1765ba93604fSmartijn 			trapaddresses[i].tr->ta_oid.bo_n = 0;
1766ba93604fSmartijn 		else {
1767ba93604fSmartijn 			if (resolve_oid(&trapaddresses[i].tr->ta_oid,
1768ba93604fSmartijn 			    &trapaddresses[i].oid) == -1)
176917240de1Smartijn 				return -1;
1770ba93604fSmartijn 		}
177117240de1Smartijn 		TAILQ_INSERT_TAIL(&conf->sc_trapreceivers,
177217240de1Smartijn 		    trapaddresses[i].tr, entry);
177317240de1Smartijn 	}
177417240de1Smartijn 	free(trapaddresses);
177517240de1Smartijn 
177617240de1Smartijn 	return 0;
177717240de1Smartijn }
177817240de1Smartijn 
177946e6c55bSreyk struct snmpd *
parse_config(const char * filename,u_int flags)178046e6c55bSreyk parse_config(const char *filename, u_int flags)
178146e6c55bSreyk {
1782967754d5Smartijn 	struct sockaddr_storage ss;
178360cc2743Smartijn 	struct utsname u;
178446e6c55bSreyk 	struct sym	*sym, *next;
17857bfcc0c0Smpf 	struct address	*h;
1786c92471afSmartijn 	struct trap_address	*tr;
1787c92471afSmartijn 	const struct usmuser	*up;
1788c92471afSmartijn 	const char	*errstr;
178973b5c081Smartijn 	char		 hostname[HOST_NAME_MAX + 1];
17907bfcc0c0Smpf 	int		 found;
179173b5c081Smartijn 	uint32_t	 npen = htonl(PEN_OPENBSD);
179246e6c55bSreyk 
179346e6c55bSreyk 	if ((conf = calloc(1, sizeof(*conf))) == NULL) {
17946a3d55f9Skrw 		log_warn("%s", __func__);
179546e6c55bSreyk 		return (NULL);
179646e6c55bSreyk 	}
179746e6c55bSreyk 
179860cc2743Smartijn 	conf->sc_system.sys_services = -1;
179946e6c55bSreyk 	conf->sc_flags = flags;
180017240de1Smartijn 
1801f0bcdb5cSmartijn 	conf->sc_oidfmt =
1802f0bcdb5cSmartijn 	    flags & SNMPD_F_NONAMES ?  MIB_OIDNUMERIC : MIB_OIDSYMBOLIC;
180317240de1Smartijn 
180446e6c55bSreyk 	conf->sc_confpath = filename;
1805c7cb8e65Sjca 	TAILQ_INIT(&conf->sc_addresses);
18064100cc5fSmartijn 	TAILQ_INIT(&conf->sc_agentx_masters);
18079b15f147Sreyk 	TAILQ_INIT(&conf->sc_trapreceivers);
1808c92471afSmartijn 	conf->sc_min_seclevel = SNMP_MSGFLAG_AUTH | SNMP_MSGFLAG_PRIV;
180946e6c55bSreyk 
181046e6c55bSreyk 	if ((file = pushfile(filename, 0)) == NULL) {
181146e6c55bSreyk 		free(conf);
181246e6c55bSreyk 		return (NULL);
181346e6c55bSreyk 	}
18147d88274aSmpf 	topfile = file;
181546e6c55bSreyk 	setservent(1);
181646e6c55bSreyk 
181746e6c55bSreyk 	yyparse();
181846e6c55bSreyk 	errors = file->errors;
181946e6c55bSreyk 	popfile();
182046e6c55bSreyk 
182146e6c55bSreyk 	endservent();
182246e6c55bSreyk 
182317240de1Smartijn 	if (errors) {
182417240de1Smartijn 		free(conf);
182517240de1Smartijn 		return (NULL);
182617240de1Smartijn 	}
182717240de1Smartijn 
1828c3100810Smartijn 	if (!mibparsed)
1829c3100810Smartijn 		mib_parsedir("/usr/share/snmp/mibs");
1830c3100810Smartijn 	mib_resolve();
1831c3100810Smartijn 
183217240de1Smartijn 	if (resolve_oids() == -1) {
183317240de1Smartijn 		free(conf);
183417240de1Smartijn 		return NULL;
183517240de1Smartijn 	}
183617240de1Smartijn 
183760cc2743Smartijn 	if (uname(&u) == -1)
183860cc2743Smartijn 		fatal("uname");
183960cc2743Smartijn 
184060cc2743Smartijn 	if (conf->sc_system.sys_descr[0] == '\0')
184160cc2743Smartijn 		snprintf(conf->sc_system.sys_descr,
184260cc2743Smartijn 		    sizeof(conf->sc_system.sys_descr), "%s %s %s %s %s",
184360cc2743Smartijn 		    u.sysname, u.nodename, u.release, u.version, u.machine);
184460cc2743Smartijn 	if (conf->sc_system.sys_oid.bo_n == 0)
184560cc2743Smartijn 		conf->sc_system.sys_oid = OID(MIB_SYSOID_DEFAULT);
184660cc2743Smartijn 	if (conf->sc_system.sys_contact[0] == '\0')
184760cc2743Smartijn 		snprintf(conf->sc_system.sys_contact,
184860cc2743Smartijn 		    sizeof(conf->sc_system.sys_contact), "root@%s", u.nodename);
184960cc2743Smartijn 	if (conf->sc_system.sys_name[0] == '\0')
185060cc2743Smartijn 		snprintf(conf->sc_system.sys_name,
185160cc2743Smartijn 		    sizeof(conf->sc_system.sys_name), "%s", u.nodename);
185260cc2743Smartijn 	if (conf->sc_system.sys_services == -1)
185360cc2743Smartijn 		conf->sc_system.sys_services = 0;
185460cc2743Smartijn 
185560cc2743Smartijn 
185673b5c081Smartijn 	/* Must be identical to enginefmt_local:HOSTHASH */
185773b5c081Smartijn 	if (conf->sc_engineid_len == 0) {
185873b5c081Smartijn 		if (gethostname(hostname, sizeof(hostname)) == -1)
185973b5c081Smartijn 			fatal("gethostname");
186073b5c081Smartijn 		memcpy(conf->sc_engineid, &npen, sizeof(npen));
186173b5c081Smartijn 		conf->sc_engineid_len += sizeof(npen);
186273b5c081Smartijn 		conf->sc_engineid[conf->sc_engineid_len++] |=
186373b5c081Smartijn 		    SNMP_ENGINEID_FMT_HH;
186473b5c081Smartijn 		memcpy(conf->sc_engineid + conf->sc_engineid_len,
1865*ad2d1a44Santon 		    SHA256(hostname, strlen(hostname), sha256),
186673b5c081Smartijn 		    sizeof(conf->sc_engineid) - conf->sc_engineid_len);
186773b5c081Smartijn 		conf->sc_engineid_len = sizeof(conf->sc_engineid);
186873b5c081Smartijn 		conf->sc_engineid[0] |= SNMP_ENGINEID_NEW;
186973b5c081Smartijn 	}
187073b5c081Smartijn 
18717bfcc0c0Smpf 	/* Setup default listen addresses */
1872c7cb8e65Sjca 	if (TAILQ_EMPTY(&conf->sc_addresses)) {
187370787abdSmartijn 		if (host("0.0.0.0", SNMP_PORT, AF_INET, SOCK_DGRAM,
187470787abdSmartijn 		    &ss, 1) != 1)
1875967754d5Smartijn 			fatal("Unexpected resolving of 0.0.0.0");
187620f2292fSmartijn 		if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
1877967754d5Smartijn 			fatal("calloc");
187870787abdSmartijn 		if (host("::", SNMP_PORT, AF_INET6, SOCK_DGRAM, &ss, 1) != 1)
1879967754d5Smartijn 			fatal("Unexpected resolving of ::");
188020f2292fSmartijn 		if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
1881967754d5Smartijn 			fatal("calloc");
18827bfcc0c0Smpf 	}
1883c92471afSmartijn 
1884c92471afSmartijn 	if ((up = usm_check_mincred(conf->sc_min_seclevel, &errstr)) != NULL)
1885c92471afSmartijn 		fatalx("user '%s': %s", up->uu_name, errstr);
1886c92471afSmartijn 
18877bfcc0c0Smpf 	found = 0;
18887bfcc0c0Smpf 	TAILQ_FOREACH(h, &conf->sc_addresses, entry) {
188920f2292fSmartijn 		if (h->flags & ADDRESS_FLAG_NOTIFY)
18907bfcc0c0Smpf 			found = 1;
18917bfcc0c0Smpf 	}
189217240de1Smartijn 	if (ntrapcmds && !found) {
189320f2292fSmartijn 		log_warnx("trap handler needs at least one notify listener");
18947bfcc0c0Smpf 		free(conf);
18957bfcc0c0Smpf 		return (NULL);
18967bfcc0c0Smpf 	}
189717240de1Smartijn 	if (!ntrapcmds && found) {
189820f2292fSmartijn 		log_warnx("notify listener needs at least one trap handler");
189920f2292fSmartijn 		free(conf);
190020f2292fSmartijn 		return (NULL);
1901c7cb8e65Sjca 	}
1902c7cb8e65Sjca 
1903c92471afSmartijn 	TAILQ_FOREACH(tr, &conf->sc_trapreceivers, entry) {
1904ab858812Smartijn 		if (tr->ta_version == SNMP_V2 &&
1905ab858812Smartijn 		    tr->ta_community[0] == '\0' &&
1906ab858812Smartijn 		    conf->sc_trcommunity[0] == '\0') {
1907c92471afSmartijn 			log_warnx("trap receiver: missing community");
1908c92471afSmartijn 			free(conf);
1909c92471afSmartijn 			return (NULL);
1910c92471afSmartijn 		}
1911ab858812Smartijn 		if (tr->ta_version == SNMP_V3) {
1912ab858812Smartijn 			tr->ta_usmuser = usm_finduser(tr->ta_usmusername);
1913ab858812Smartijn 			if (tr->ta_usmuser == NULL) {
1914ab858812Smartijn 				log_warnx("trap receiver: user not defined: %s",
1915ab858812Smartijn 				    tr->ta_usmusername);
1916ab858812Smartijn 				free(conf);
1917ab858812Smartijn 				return (NULL);
1918ab858812Smartijn 			}
1919c92471afSmartijn 		}
1920c92471afSmartijn 	}
1921c92471afSmartijn 
192246e6c55bSreyk 	/* Free macros and check which have not been used. */
192346bca67bSkrw 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
192446e6c55bSreyk 		if ((conf->sc_flags & SNMPD_F_VERBOSE) && !sym->used)
192546e6c55bSreyk 			fprintf(stderr, "warning: macro '%s' not "
192646e6c55bSreyk 			    "used\n", sym->nam);
192746e6c55bSreyk 		if (!sym->persist) {
192846e6c55bSreyk 			free(sym->nam);
192946e6c55bSreyk 			free(sym->val);
193046e6c55bSreyk 			TAILQ_REMOVE(&symhead, sym, entry);
193146e6c55bSreyk 			free(sym);
193246e6c55bSreyk 		}
193346e6c55bSreyk 	}
193446e6c55bSreyk 
193546e6c55bSreyk 	return (conf);
193646e6c55bSreyk }
193746e6c55bSreyk 
193846e6c55bSreyk int
symset(const char * nam,const char * val,int persist)193946e6c55bSreyk symset(const char *nam, const char *val, int persist)
194046e6c55bSreyk {
194146e6c55bSreyk 	struct sym	*sym;
194246e6c55bSreyk 
194354c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
194454c95b7aSkrw 		if (strcmp(nam, sym->nam) == 0)
194554c95b7aSkrw 			break;
194654c95b7aSkrw 	}
194746e6c55bSreyk 
194846e6c55bSreyk 	if (sym != NULL) {
194946e6c55bSreyk 		if (sym->persist == 1)
195046e6c55bSreyk 			return (0);
195146e6c55bSreyk 		else {
195246e6c55bSreyk 			free(sym->nam);
195346e6c55bSreyk 			free(sym->val);
195446e6c55bSreyk 			TAILQ_REMOVE(&symhead, sym, entry);
195546e6c55bSreyk 			free(sym);
195646e6c55bSreyk 		}
195746e6c55bSreyk 	}
195846e6c55bSreyk 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
195946e6c55bSreyk 		return (-1);
196046e6c55bSreyk 
196146e6c55bSreyk 	sym->nam = strdup(nam);
196246e6c55bSreyk 	if (sym->nam == NULL) {
196346e6c55bSreyk 		free(sym);
196446e6c55bSreyk 		return (-1);
196546e6c55bSreyk 	}
196646e6c55bSreyk 	sym->val = strdup(val);
196746e6c55bSreyk 	if (sym->val == NULL) {
196846e6c55bSreyk 		free(sym->nam);
196946e6c55bSreyk 		free(sym);
197046e6c55bSreyk 		return (-1);
197146e6c55bSreyk 	}
197246e6c55bSreyk 	sym->used = 0;
197346e6c55bSreyk 	sym->persist = persist;
197446e6c55bSreyk 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
197546e6c55bSreyk 	return (0);
197646e6c55bSreyk }
197746e6c55bSreyk 
197846e6c55bSreyk int
cmdline_symset(char * s)197946e6c55bSreyk cmdline_symset(char *s)
198046e6c55bSreyk {
198146e6c55bSreyk 	char	*sym, *val;
198246e6c55bSreyk 	int	ret;
198346e6c55bSreyk 
198446e6c55bSreyk 	if ((val = strrchr(s, '=')) == NULL)
198546e6c55bSreyk 		return (-1);
1986ed1b9eb8Smiko 	sym = strndup(s, val - s);
1987ed1b9eb8Smiko 	if (sym == NULL)
1988ed1b9eb8Smiko 		errx(1, "%s: strndup", __func__);
198946e6c55bSreyk 	ret = symset(sym, val + 1, 1);
199046e6c55bSreyk 	free(sym);
199146e6c55bSreyk 
199246e6c55bSreyk 	return (ret);
199346e6c55bSreyk }
199446e6c55bSreyk 
199546e6c55bSreyk char *
symget(const char * nam)199646e6c55bSreyk symget(const char *nam)
199746e6c55bSreyk {
199846e6c55bSreyk 	struct sym	*sym;
199946e6c55bSreyk 
200054c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
200146e6c55bSreyk 		if (strcmp(nam, sym->nam) == 0) {
200246e6c55bSreyk 			sym->used = 1;
200346e6c55bSreyk 			return (sym->val);
200446e6c55bSreyk 		}
200554c95b7aSkrw 	}
200646e6c55bSreyk 	return (NULL);
200746e6c55bSreyk }
200846e6c55bSreyk 
200946e6c55bSreyk int
host(const char * s,const char * port,int family,int type,struct sockaddr_storage * ss,int max)201070787abdSmartijn host(const char *s, const char *port, int family, int type,
201170787abdSmartijn     struct sockaddr_storage *ss, int max)
201246e6c55bSreyk {
201346e6c55bSreyk 	struct addrinfo		 hints, *res0, *res;
2014967754d5Smartijn 	int			 error, i;
201546e6c55bSreyk 
201646e6c55bSreyk 	bzero(&hints, sizeof(hints));
201770787abdSmartijn 	hints.ai_family = family;
2018967754d5Smartijn 	hints.ai_socktype = type;
2019a7a73940Smartijn 	/*
2020a7a73940Smartijn 	 * Without AI_NUMERICHOST getaddrinfo might not resolve ip addresses
2021a7a73940Smartijn 	 * for families not specified in the "family" statement in resolv.conf.
2022a7a73940Smartijn 	 */
2023a7a73940Smartijn 	hints.ai_flags = AI_NUMERICHOST;
2024967754d5Smartijn 	error = getaddrinfo(s, port, &hints, &res0);
2025a7a73940Smartijn 	if (error == EAI_NONAME) {
2026a7a73940Smartijn 		hints.ai_flags = 0;
2027a7a73940Smartijn 		error = getaddrinfo(s, port, &hints, &res0);
2028a7a73940Smartijn 	}
202946e6c55bSreyk 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
2030967754d5Smartijn 		return 0;
203146e6c55bSreyk 	if (error) {
2032967754d5Smartijn 		log_warnx("Could not parse \"%s\": %s", s, gai_strerror(error));
2033967754d5Smartijn 		return -1;
203446e6c55bSreyk 	}
203546e6c55bSreyk 
2036967754d5Smartijn 	for (i = 0, res = res0; res; res = res->ai_next, i++) {
203746e6c55bSreyk 		if (res->ai_family != AF_INET &&
203846e6c55bSreyk 		    res->ai_family != AF_INET6)
203946e6c55bSreyk 			continue;
2040967754d5Smartijn 		if (i >= max)
2041f005ecdcSjca 			continue;
204246e6c55bSreyk 
2043967754d5Smartijn 		bcopy(res->ai_addr, &(ss[i]), res->ai_addrlen);
204446e6c55bSreyk 	}
204546e6c55bSreyk 	freeaddrinfo(res0);
2046967754d5Smartijn 
2047967754d5Smartijn 	return i;
204846e6c55bSreyk }
204946e6c55bSreyk 
205046e6c55bSreyk int
listen_add(struct sockaddr_storage * ss,int type,int flags)205120f2292fSmartijn listen_add(struct sockaddr_storage *ss, int type, int flags)
205246e6c55bSreyk {
2053967754d5Smartijn 	struct sockaddr_in *sin;
2054967754d5Smartijn 	struct sockaddr_in6 *sin6;
2055967754d5Smartijn 	struct address *h;
2056f005ecdcSjca 
2057967754d5Smartijn 	if ((h = calloc(1, sizeof(*h))) == NULL)
2058967754d5Smartijn 		return -1;
2059967754d5Smartijn 	bcopy(ss, &(h->ss), sizeof(*ss));
2060967754d5Smartijn 	if (ss->ss_family == AF_INET) {
2061967754d5Smartijn 		sin = (struct sockaddr_in *)ss;
2062967754d5Smartijn 		h->port = ntohs(sin->sin_port);
2063967754d5Smartijn 	} else {
2064967754d5Smartijn 		sin6 = (struct sockaddr_in6*)ss;
2065967754d5Smartijn 		h->port = ntohs(sin6->sin6_port);
2066f005ecdcSjca 	}
2067967754d5Smartijn 	h->type = type;
2068c92471afSmartijn 	if (((h->flags = flags) & ADDRESS_FLAG_PERM) == 0) {
206920f2292fSmartijn 		if (h->port == 162)
2070c92471afSmartijn 			h->flags |= ADDRESS_FLAG_NOTIFY;
207120f2292fSmartijn 		else
2072c92471afSmartijn 			h->flags |= ADDRESS_FLAG_READ | ADDRESS_FLAG_WRITE;
207320f2292fSmartijn 	}
2074c92471afSmartijn 	if ((h->flags & ADDRESS_FLAG_MPS) == 0)
2075c92471afSmartijn 		h->flags |= ADDRESS_FLAG_SNMPV3;
2076967754d5Smartijn 	TAILQ_INSERT_TAIL(&(conf->sc_addresses), h, entry);
207746e6c55bSreyk 
2078967754d5Smartijn 	return 0;
207946e6c55bSreyk }
2080