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