1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7133211Sharti * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 14122394Sharti * notice, this list of conditions and the following disclaimer in the 15122394Sharti * documentation and/or other materials provided with the distribution. 16133211Sharti * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28122394Sharti * 29156066Sharti * $Begemot: bsnmp/snmpd/config.c,v 1.25 2006/02/14 09:04:20 brandt_h Exp $ 30122394Sharti * 31122394Sharti * Parse configuration file. 32122394Sharti */ 33122394Sharti#include <sys/types.h> 34216294Ssyrinx#include <sys/queue.h> 35122394Sharti#include <sys/socket.h> 36122394Sharti#include <sys/un.h> 37122394Sharti#include <stdio.h> 38122394Sharti#include <stdlib.h> 39122394Sharti#include <string.h> 40122394Sharti#include <stdarg.h> 41122394Sharti#include <ctype.h> 42122394Sharti#include <errno.h> 43122394Sharti#include <syslog.h> 44122394Sharti#include <unistd.h> 45122394Sharti#include <limits.h> 46122394Sharti#include <netdb.h> 47122394Sharti#include <setjmp.h> 48122394Sharti#include <inttypes.h> 49122394Sharti 50122394Sharti#include "snmpmod.h" 51122394Sharti#include "snmpd.h" 52122394Sharti#include "tree.h" 53122394Sharti 54122394Sharti/* 55122394Sharti#define DEBUGGING 56122394Sharti*/ 57122394Sharti 58122394Sharti/* 59122394Sharti * config_file: EMPTY | config_file line 60122394Sharti * 61122394Sharti * line: oid '=' value 62122394Sharti * | '%' STRING 63122394Sharti * | STRING := REST_OF_LINE 64122394Sharti * | STRING ?= REST_OF_LINE 65122394Sharti * | . INCLUDE STRING 66122394Sharti * 67122394Sharti * oid: STRING suboid 68122394Sharti * 69122394Sharti * suboid: EMPTY | suboid '.' subid 70122394Sharti * 71122394Sharti * subid: NUM | STRING | '[' STRING ']' 72122394Sharti * 73122394Sharti * value: EMPTY | STRING | NUM 74122394Sharti */ 75122394Sharti 76122394Sharti/* 77122394Sharti * Input context for macros and includes 78122394Sharti */ 79122394Shartienum input_type { 80122394Sharti INPUT_FILE = 1, 81122394Sharti INPUT_STRING 82122394Sharti}; 83122394Shartistruct input { 84122394Sharti enum input_type type; 85122394Sharti union { 86122394Sharti struct { 87122394Sharti FILE *fp; 88122394Sharti char *filename; 89122394Sharti u_int lno; 90122394Sharti } file; 91122394Sharti struct { 92122394Sharti char *macro; 93122394Sharti char *str; 94122394Sharti char *ptr; 95122394Sharti size_t left; 96122394Sharti } str; 97122394Sharti } u; 98122394Sharti LIST_ENTRY(input) link; 99122394Sharti}; 100122394Shartistatic LIST_HEAD(, input) inputs; 101122394Sharti 102122394Sharti#define input_fp u.file.fp 103122394Sharti#define input_filename u.file.filename 104122394Sharti#define input_lno u.file.lno 105122394Sharti#define input_macro u.str.macro 106122394Sharti#define input_str u.str.str 107122394Sharti#define input_ptr u.str.ptr 108122394Sharti#define input_left u.str.left 109122394Sharti 110122394Shartistatic int input_push; 111122394Shartistatic int input_buf[2]; 112122394Sharti 113122394Sharti/* 114122394Sharti * Configuration data. The configuration file is handled as one single 115122394Sharti * SNMP transaction. So we need to keep the assignment data for the 116122394Sharti * commit or rollback pass. Note, that dependencies and finish functions 117122394Sharti * are NOT allowed here. 118122394Sharti */ 119122394Shartistruct assign { 120122394Sharti struct snmp_value value; 121122394Sharti struct snmp_scratch scratch; 122122394Sharti const char *node_name; 123122394Sharti 124122394Sharti TAILQ_ENTRY(assign) link; 125122394Sharti}; 126122394Shartistatic TAILQ_HEAD(assigns, assign) assigns = TAILQ_HEAD_INITIALIZER(assigns); 127122394Sharti 128122394Sharti 129122394Shartistatic struct snmp_context *snmp_ctx; 130122394Sharti 131122394Shartistruct macro { 132122394Sharti char *name; 133122394Sharti char *value; 134122394Sharti size_t length; 135122394Sharti LIST_ENTRY(macro) link; 136122394Sharti int perm; 137122394Sharti}; 138205729Santoinestatic LIST_HEAD(, macro) macros = LIST_HEAD_INITIALIZER(macros); 139122394Sharti 140122394Shartienum { 141122394Sharti TOK_EOF = 0200, 142122394Sharti TOK_EOL, 143122394Sharti TOK_NUM, 144122394Sharti TOK_STR, 145122394Sharti TOK_HOST, 146122394Sharti TOK_ASSIGN, 147122394Sharti TOK_QASSIGN, 148122394Sharti}; 149122394Sharti 150122394Sharti/* lexer values and last token */ 151122394Shartistatic uint64_t numval; 152122394Shartistatic char strval[_POSIX2_LINE_MAX]; 153122394Shartistatic size_t strvallen; 154122394Shartistatic int token; 155122394Sharti 156122394Sharti/* error return */ 157122394Shartistatic jmp_buf errjmp[4]; 158122394Shartistatic volatile int errstk; 159122394Sharti 160122394Sharti# define ERRPUSH() (setjmp(errjmp[errstk++])) 161122394Sharti# define ERRPOP() ((void)(errstk--)) 162122394Sharti# define ERRNEXT() (longjmp(errjmp[--errstk], 1)) 163122394Sharti# define ERR() (longjmp(errjmp[--errstk], 1)) 164122394Sharti 165122394Sharti/* section context */ 166122394Shartistatic int ignore; 167122394Sharti 168122394Sharti/* 169122394Sharti * Report an error and jump to the error label 170122394Sharti */ 171122394Shartistatic void report(const char *fmt, ...) __dead2 __printflike(1, 2); 172122394Sharti 173122394Shartistatic void 174122394Shartireport(const char *fmt, ...) 175122394Sharti{ 176122394Sharti va_list ap; 177122394Sharti const struct input *input; 178122394Sharti 179122394Sharti va_start(ap, fmt); 180122394Sharti vsyslog(LOG_ERR, fmt, ap); 181122394Sharti va_end(ap); 182122394Sharti 183122394Sharti LIST_FOREACH(input, &inputs, link) { 184122394Sharti switch (input->type) { 185122394Sharti 186122394Sharti case INPUT_FILE: 187122394Sharti syslog(LOG_ERR, " in file %s line %u", 188122394Sharti input->input_filename, input->input_lno); 189122394Sharti break; 190122394Sharti 191122394Sharti case INPUT_STRING: 192122394Sharti syslog(LOG_ERR, " in macro %s pos %td", 193122394Sharti input->input_macro, 194122394Sharti input->input_ptr - input->input_str); 195122394Sharti break; 196122394Sharti } 197122394Sharti } 198122394Sharti ERR(); 199122394Sharti} 200122394Sharti 201122394Sharti/* 202122394Sharti * Open a file for input 203122394Sharti */ 204122394Shartistatic int 205122394Shartiinput_open_file(const char *fname, int sysdir) 206122394Sharti{ 207122394Sharti struct input *input; 208122394Sharti FILE *fp; 209122394Sharti char path[PATH_MAX + 1]; 210154178Sharti const char *col; 211122394Sharti const char *ptr; 212122394Sharti 213122394Sharti if (sysdir) { 214122394Sharti ptr = syspath; 215122394Sharti fp = NULL; 216122394Sharti while (*ptr != '\0') { 217154178Sharti if ((col = strchr(ptr, ':')) == NULL) { 218122394Sharti snprintf(path, sizeof(path), "%s/%s", 219122394Sharti ptr, fname); 220154178Sharti col = ptr + strlen(ptr) - 1; 221154178Sharti } else if (col == ptr) 222122394Sharti snprintf(path, sizeof(path), "./%s", fname); 223122394Sharti else 224122394Sharti snprintf(path, sizeof(path), "%.*s/%s", 225122394Sharti (int)(col - ptr), ptr, fname); 226122394Sharti if ((fp = fopen(path, "r")) != NULL) 227122394Sharti break; 228122394Sharti ptr = col + 1; 229122394Sharti } 230122394Sharti } else 231122394Sharti fp = fopen(fname, "r"); 232122394Sharti 233122394Sharti if (fp == NULL) 234122394Sharti report("%s: %m", fname); 235122394Sharti 236122394Sharti if ((input = malloc(sizeof(*input))) == NULL) { 237122394Sharti fclose(fp); 238122394Sharti return (-1); 239122394Sharti } 240122394Sharti if ((input->input_filename = malloc(strlen(fname) + 1)) == NULL) { 241122394Sharti fclose(fp); 242122394Sharti free(input); 243122394Sharti return (-1); 244122394Sharti } 245122394Sharti strcpy(input->input_filename, fname); 246122394Sharti input->input_fp = fp; 247122394Sharti input->input_lno = 1; 248122394Sharti input->type = INPUT_FILE; 249122394Sharti LIST_INSERT_HEAD(&inputs, input, link); 250122394Sharti return (0); 251122394Sharti} 252122394Sharti 253122394Sharti/* 254122394Sharti * Make a macro the next input 255122394Sharti */ 256122394Shartistatic void 257122394Shartiinput_open_macro(struct macro *m) 258122394Sharti{ 259122394Sharti struct input *input; 260122394Sharti 261122394Sharti if ((input = malloc(sizeof(*input))) == NULL) 262122394Sharti report("%m"); 263122394Sharti input->type = INPUT_STRING; 264122394Sharti input->input_macro = m->name; 265122394Sharti if ((input->input_str = malloc(m->length)) == NULL) { 266122394Sharti free(input); 267122394Sharti report("%m"); 268122394Sharti } 269122394Sharti memcpy(input->input_str, m->value, m->length); 270122394Sharti input->input_ptr = input->input_str; 271122394Sharti input->input_left = m->length; 272122394Sharti LIST_INSERT_HEAD(&inputs, input, link); 273122394Sharti} 274122394Sharti 275122394Sharti/* 276122394Sharti * Close top input source 277122394Sharti */ 278122394Shartistatic void 279122394Shartiinput_close(void) 280122394Sharti{ 281122394Sharti struct input *input; 282122394Sharti 283122394Sharti if ((input = LIST_FIRST(&inputs)) == NULL) 284122394Sharti abort(); 285122394Sharti switch (input->type) { 286122394Sharti 287122394Sharti case INPUT_FILE: 288122394Sharti fclose(input->input_fp); 289122394Sharti free(input->input_filename); 290122394Sharti break; 291122394Sharti 292122394Sharti case INPUT_STRING: 293122394Sharti free(input->input_str); 294122394Sharti break; 295122394Sharti } 296122394Sharti LIST_REMOVE(input, link); 297122394Sharti free(input); 298122394Sharti} 299122394Sharti 300122394Sharti/* 301122394Sharti * Close all inputs 302122394Sharti */ 303122394Shartistatic void 304122394Shartiinput_close_all(void) 305122394Sharti{ 306122394Sharti while (!LIST_EMPTY(&inputs)) 307122394Sharti input_close(); 308122394Sharti} 309122394Sharti 310122394Sharti/* 311122394Sharti * Push back one character 312122394Sharti */ 313122394Shartistatic void 314122394Shartiinput_ungetc(int c) 315122394Sharti{ 316122394Sharti if (c == EOF) 317122394Sharti report("pushing EOF"); 318122394Sharti if (input_push == 2) 319122394Sharti report("pushing third char"); 320122394Sharti input_buf[input_push++] = c; 321122394Sharti} 322122394Sharti 323122394Sharti 324122394Sharti/* 325122394Sharti * Return next character from the input without preprocessing. 326122394Sharti */ 327122394Shartistatic int 328122394Shartiinput_getc_raw(void) 329122394Sharti{ 330122394Sharti int c; 331122394Sharti struct input *input; 332122394Sharti 333122394Sharti if (input_push != 0) { 334122394Sharti c = input_buf[--input_push]; 335122394Sharti goto ok; 336122394Sharti } 337122394Sharti while ((input = LIST_FIRST(&inputs)) != NULL) { 338122394Sharti switch (input->type) { 339122394Sharti 340122394Sharti case INPUT_FILE: 341122394Sharti if ((c = getc(input->input_fp)) == EOF) { 342122394Sharti if (ferror(input->input_fp)) 343122394Sharti report("read error: %m"); 344122394Sharti input_close(); 345122394Sharti break; 346122394Sharti } 347122394Sharti if (c == '\n') 348122394Sharti input->input_lno++; 349122394Sharti goto ok; 350122394Sharti 351122394Sharti case INPUT_STRING: 352122394Sharti if (input->input_left-- == 0) { 353122394Sharti input_close(); 354122394Sharti break; 355122394Sharti } 356122394Sharti c = *input->input_ptr++; 357122394Sharti goto ok; 358122394Sharti } 359122394Sharti } 360122394Sharti# ifdef DEBUGGING 361122394Sharti fprintf(stderr, "EOF"); 362122394Sharti# endif 363122394Sharti return (EOF); 364122394Sharti 365122394Sharti ok: 366122394Sharti# ifdef DEBUGGING 367122394Sharti if (!isascii(c) || !isprint(c)) 368122394Sharti fprintf(stderr, "'%#2x'", c); 369122394Sharti else 370122394Sharti fprintf(stderr, "'%c'", c); 371122394Sharti# endif 372122394Sharti return (c); 373122394Sharti} 374122394Sharti 375122394Sharti/* 376122394Sharti * Get character with and \\n -> processing. 377122394Sharti */ 378122394Shartistatic int 379122394Shartiinput_getc_plain(void) 380122394Sharti{ 381122394Sharti int c; 382122394Sharti 383122394Sharti again: 384122394Sharti if ((c = input_getc_raw()) == '\\') { 385122394Sharti if ((c = input_getc_raw()) == '\n') 386122394Sharti goto again; 387122394Sharti if (c != EOF) 388122394Sharti input_ungetc(c); 389122394Sharti return ('\\'); 390122394Sharti } 391122394Sharti return (c); 392122394Sharti} 393122394Sharti 394122394Sharti/* 395122394Sharti * Get next character with substitution of macros 396122394Sharti */ 397122394Shartistatic int 398122394Shartiinput_getc(void) 399122394Sharti{ 400122394Sharti int c; 401122394Sharti struct macro *m; 402122394Sharti char name[_POSIX2_LINE_MAX]; 403122394Sharti size_t namelen; 404122394Sharti 405122394Sharti again: 406122394Sharti if ((c = input_getc_plain()) != '$') 407122394Sharti return (c); 408122394Sharti 409122394Sharti if ((c = input_getc()) == EOF) 410122394Sharti report("unexpected EOF"); 411122394Sharti if (c != '(') 412122394Sharti report("expecting '(' after '$'"); 413122394Sharti 414122394Sharti namelen = 0; 415122394Sharti while ((c = input_getc()) != EOF && c != ')') { 416122394Sharti if (isalpha(c) || c == '_' || (namelen != 0 && isdigit(c))) 417122394Sharti name[namelen++] = c; 418122394Sharti else 419122394Sharti goto badchar; 420122394Sharti } 421122394Sharti if (c == EOF) 422122394Sharti report("unexpected EOF"); 423122394Sharti name[namelen++] = '\0'; 424122394Sharti 425122394Sharti LIST_FOREACH(m, ¯os, link) 426122394Sharti if (strcmp(m->name, name) == 0) 427122394Sharti break; 428122394Sharti if (m == NULL) 429122394Sharti report("undefined macro '%s'", name); 430122394Sharti 431122394Sharti input_open_macro(m); 432122394Sharti goto again; 433122394Sharti 434122394Sharti badchar: 435122394Sharti if (!isascii(c) || !isprint(c)) 436122394Sharti report("unexpected character %#2x", (u_int)c); 437122394Sharti else 438122394Sharti report("bad character '%c'", c); 439122394Sharti} 440122394Sharti 441122394Sharti 442122394Shartistatic void 443122394Shartiinput_getnum(u_int base, u_int flen) 444122394Sharti{ 445122394Sharti int c; 446122394Sharti u_int cnt; 447122394Sharti 448122394Sharti cnt = 0; 449122394Sharti numval = 0; 450122394Sharti while (flen == 0 || cnt < flen) { 451122394Sharti if ((c = input_getc()) == EOF) { 452122394Sharti if (cnt == 0) 453122394Sharti report("bad number"); 454122394Sharti return; 455122394Sharti } 456122394Sharti if (isdigit(c)) { 457122394Sharti if (base == 8 && (c == '8' || c == '9')) { 458122394Sharti input_ungetc(c); 459122394Sharti if (cnt == 0) 460122394Sharti report("bad number"); 461122394Sharti return; 462122394Sharti } 463122394Sharti numval = numval * base + (c - '0'); 464122394Sharti } else if (base == 16 && isxdigit(c)) { 465122394Sharti if (islower(c)) 466122394Sharti numval = numval * base + (c - 'a' + 10); 467122394Sharti else 468122394Sharti numval = numval * base + (c - 'A' + 10); 469122394Sharti } else { 470122394Sharti input_ungetc(c); 471122394Sharti if (cnt == 0) 472122394Sharti report("bad number"); 473122394Sharti return; 474122394Sharti } 475122394Sharti cnt++; 476122394Sharti } 477122394Sharti} 478122394Sharti 479122394Shartistatic int 480122394Sharti# ifdef DEBUGGING 481122394Sharti_gettoken(void) 482122394Sharti# else 483122394Shartigettoken(void) 484122394Sharti# endif 485122394Sharti{ 486122394Sharti int c; 487122394Sharti char *end; 488122394Sharti static const char esc[] = "abfnrtv"; 489122394Sharti static const char chr[] = "\a\b\f\n\r\t\v"; 490122394Sharti 491122394Sharti /* 492122394Sharti * Skip any whitespace before the next token 493122394Sharti */ 494122394Sharti while ((c = input_getc()) != EOF) { 495122394Sharti if (!isspace(c) || c == '\n') 496122394Sharti break; 497122394Sharti } 498122394Sharti if (c == EOF) 499122394Sharti return (token = TOK_EOF); 500122394Sharti if (!isascii(c)) 501122394Sharti goto badchar; 502122394Sharti 503122394Sharti /* 504122394Sharti * Skip comments 505122394Sharti */ 506122394Sharti if (c == '#') { 507122394Sharti while ((c = input_getc_plain()) != EOF) { 508122394Sharti if (c == '\n') 509122394Sharti return (token = TOK_EOL); 510122394Sharti } 511122394Sharti goto badeof; 512122394Sharti } 513122394Sharti 514122394Sharti /* 515122394Sharti * Single character tokens 516122394Sharti */ 517122394Sharti if (c == '\n') 518122394Sharti return (token = TOK_EOL); 519122394Sharti if (c == '.' || c == '%' || c == '=' || c == '<' || c == '>') 520122394Sharti return (token = c); 521122394Sharti if (c == ':') { 522122394Sharti if ((c = input_getc()) == '=') 523122394Sharti return (token = TOK_ASSIGN); 524122394Sharti input_ungetc(c); 525122394Sharti return (token = ':'); 526122394Sharti } 527122394Sharti if (c == '?') { 528122394Sharti if ((c = input_getc()) == '=') 529122394Sharti return (token = TOK_QASSIGN); 530122394Sharti input_ungetc(c); 531122394Sharti goto badchar; 532122394Sharti } 533122394Sharti 534122394Sharti /* 535122394Sharti * Sort out numbers 536122394Sharti */ 537122394Sharti if (isdigit(c)) { 538122394Sharti if (c == '0') { 539122394Sharti if ((c = input_getc()) == 'x' || c == 'X') { 540122394Sharti input_getnum(16, 0); 541122394Sharti } else if (isdigit(c)) { 542122394Sharti input_ungetc(c); 543122394Sharti input_getnum(8, 0); 544122394Sharti } else { 545122394Sharti if (c != EOF) 546122394Sharti input_ungetc(c); 547122394Sharti numval = 0; 548122394Sharti c = 1; 549122394Sharti } 550122394Sharti } else { 551122394Sharti input_ungetc(c); 552122394Sharti input_getnum(10, 0); 553122394Sharti } 554122394Sharti return (token = TOK_NUM); 555122394Sharti } 556122394Sharti 557122394Sharti /* 558122394Sharti * Must be a string then 559122394Sharti */ 560122394Sharti strvallen = 0; 561122394Sharti 562122394Sharti# define GETC(C) do { \ 563122394Sharti if ((c = input_getc()) == EOF) \ 564122394Sharti goto badeof; \ 565122394Sharti if (!isascii(c) || (!isprint(c) && c != '\t')) \ 566122394Sharti goto badchar; \ 567122394Sharti} while(0) 568122394Sharti 569122394Sharti if (c == '"') { 570122394Sharti for(;;) { 571122394Sharti GETC(c); 572122394Sharti if (c == '"') { 573122394Sharti strval[strvallen] = '\0'; 574122394Sharti break; 575122394Sharti } 576122394Sharti if (c != '\\') { 577122394Sharti strval[strvallen++] = c; 578122394Sharti continue; 579122394Sharti } 580122394Sharti GETC(c); 581122394Sharti if ((end = strchr(esc, c)) != NULL) { 582122394Sharti strval[strvallen++] = chr[end - esc]; 583122394Sharti continue; 584122394Sharti } 585122394Sharti if (c == 'x') { 586122394Sharti input_getnum(16, 2); 587122394Sharti c = numval; 588122394Sharti } else if (c >= '0' && c <= '7') { 589122394Sharti input_ungetc(c); 590122394Sharti input_getnum(8, 3); 591122394Sharti c = numval; 592122394Sharti } 593122394Sharti strval[strvallen++] = c; 594122394Sharti } 595122394Sharti# undef GETC 596122394Sharti 597122394Sharti } else if (c == '[') { 598122394Sharti /* 599122394Sharti * Skip leading space 600122394Sharti */ 601122394Sharti while ((c = input_getc()) != EOF && isspace(c)) 602122394Sharti ; 603122394Sharti if (c == EOF) 604122394Sharti goto badeof; 605122394Sharti while (c != ']' && !isspace(c)) { 606122394Sharti if (!isalnum(c) && c != '.' && c != '-') 607122394Sharti goto badchar; 608122394Sharti strval[strvallen++] = c; 609122394Sharti if ((c = input_getc()) == EOF) 610122394Sharti goto badeof; 611122394Sharti } 612122394Sharti while (c != ']' && isspace(c)) { 613122394Sharti if ((c = input_getc()) == EOF) 614122394Sharti goto badeof; 615122394Sharti } 616122394Sharti if (c != ']') 617122394Sharti goto badchar; 618122394Sharti strval[strvallen] = '\0'; 619122394Sharti return (token = TOK_HOST); 620122394Sharti 621122394Sharti } else if (!isalpha(c) && c != '_') { 622122394Sharti goto badchar; 623122394Sharti 624122394Sharti } else { 625122394Sharti for (;;) { 626122394Sharti strval[strvallen++] = c; 627122394Sharti if ((c = input_getc()) == EOF) 628122394Sharti goto badeof; 629122394Sharti if (!isalnum(c) && c != '_' && c != '-') { 630122394Sharti input_ungetc(c); 631122394Sharti strval[strvallen] = '\0'; 632122394Sharti break; 633122394Sharti } 634122394Sharti } 635122394Sharti } 636122394Sharti 637122394Sharti return (token = TOK_STR); 638122394Sharti 639122394Sharti badeof: 640122394Sharti report("unexpected EOF"); 641122394Sharti 642122394Sharti badchar: 643122394Sharti if (!isascii(c) || !isprint(c)) 644122394Sharti report("unexpected character %#2x", (u_int)c); 645122394Sharti else 646122394Sharti report("bad character '%c'", c); 647122394Sharti} 648122394Sharti 649122394Sharti# ifdef DEBUGGING 650122394Shartistatic int 651122394Shartigettoken() 652122394Sharti{ 653122394Sharti _gettoken(); 654122394Sharti if (isascii(token) && isprint(token)) 655122394Sharti printf("(%c)", token); 656122394Sharti else { 657122394Sharti switch (token) { 658122394Sharti 659122394Sharti case TOK_EOF: 660122394Sharti printf("(EOF)"); 661122394Sharti break; 662122394Sharti case TOK_EOL: 663122394Sharti printf("(EOL)"); 664122394Sharti break; 665122394Sharti case TOK_NUM: 666122394Sharti printf("(NUM %llu)", numval); 667122394Sharti break; 668122394Sharti case TOK_STR: 669122394Sharti printf("(STR %.*s)", (int)strvallen, strval); 670122394Sharti break; 671122394Sharti case TOK_HOST: 672122394Sharti printf("(HOST %s)", strval); 673122394Sharti break; 674122394Sharti default: 675122394Sharti printf("(%#2x)", token); 676122394Sharti break; 677122394Sharti } 678122394Sharti } 679122394Sharti return (token); 680122394Sharti} 681122394Sharti#endif 682122394Sharti 683122394Sharti 684122394Sharti/* 685122394Sharti * Try to execute the assignment. 686122394Sharti */ 687122394Shartistatic void 688122394Shartihandle_assignment(const struct snmp_node *node, struct asn_oid *vindex, 689122394Sharti const struct snmp_value *value) 690122394Sharti{ 691122394Sharti u_int i; 692122394Sharti int err; 693122394Sharti struct assign *tp; 694122394Sharti char nodename[100]; 695122394Sharti 696122394Sharti if (node->type == SNMP_NODE_LEAF) { 697122394Sharti /* index must be one single zero or no index at all */ 698122394Sharti if (vindex->len > 1 || (vindex->len == 1 && 699122394Sharti vindex->subs[0] != 0)) 700122394Sharti report("bad index on leaf node"); 701122394Sharti vindex->len = 1; 702122394Sharti vindex->subs[0] = 0; 703122394Sharti } else { 704122394Sharti /* resulting oid must not be too long */ 705122394Sharti if (node->oid.len + vindex->len > ASN_MAXOIDLEN) 706122394Sharti report("resulting OID too long"); 707122394Sharti } 708122394Sharti 709122394Sharti /* 710122394Sharti * Get the next assignment entry for the transaction. 711122394Sharti */ 712122394Sharti if ((tp = malloc(sizeof(*tp))) == NULL) 713122394Sharti report("%m"); 714122394Sharti 715122394Sharti tp->value = *value; 716122394Sharti tp->node_name = node->name; 717122394Sharti 718122394Sharti /* 719122394Sharti * Build the OID 720122394Sharti */ 721122394Sharti tp->value.var = node->oid; 722122394Sharti for (i = 0; i < vindex->len; i++) 723122394Sharti tp->value.var.subs[tp->value.var.len++] = vindex->subs[i]; 724122394Sharti 725122394Sharti /* 726122394Sharti * Puzzle together the variables for the call and call the 727122394Sharti * set routine. The set routine may make our node pointer 728122394Sharti * invalid (if we happend to call the module loader) so 729122394Sharti * get a copy of the node name beforehands. 730122394Sharti */ 731122394Sharti snprintf(nodename, sizeof(nodename), "%s", node->name); 732122394Sharti snmp_ctx->scratch = &tp->scratch; 733122394Sharti snmp_ctx->var_index = 0; 734122394Sharti err = (*node->op)(snmp_ctx, &tp->value, node->oid.len, node->index, 735122394Sharti SNMP_OP_SET); 736122394Sharti if (err != 0) { 737122394Sharti free(tp); 738122394Sharti report("assignment to %s.%s returns %d", nodename, 739122394Sharti asn_oid2str(vindex), err); 740122394Sharti } 741122394Sharti 742122394Sharti TAILQ_INSERT_TAIL(&assigns, tp, link); 743122394Sharti} 744122394Sharti 745122394Sharti 746122394Sharti/* 747122394Sharti * Parse the section statement 748122394Sharti */ 749122394Shartistatic void 750122394Shartiparse_section(const struct lmodule *mod) 751122394Sharti{ 752122394Sharti if (token != TOK_STR) 753122394Sharti report("expecting section name"); 754122394Sharti 755122394Sharti if (strcmp(strval, "snmpd") == 0) { 756122394Sharti if (mod != NULL) 757122394Sharti /* loading a module - ignore common stuff */ 758122394Sharti ignore = 1; 759122394Sharti else 760122394Sharti /* global configuration - don't ignore */ 761122394Sharti ignore = 0; 762122394Sharti } else { 763122394Sharti if (mod == NULL) { 764122394Sharti /* global configuration - ignore module stuff */ 765122394Sharti ignore = 1; 766122394Sharti } else { 767122394Sharti /* loading module - check if it's our section */ 768122394Sharti ignore = (strcmp(strval, mod->section) != 0); 769122394Sharti } 770122394Sharti } 771122394Sharti gettoken(); 772122394Sharti} 773122394Sharti 774122394Sharti/* 775122394Sharti * Convert a hostname to four u_chars 776122394Sharti */ 777122394Shartistatic void 778122394Shartigethost(const char *host, u_char *ip) 779122394Sharti{ 780122394Sharti struct addrinfo hints, *res; 781122394Sharti int error; 782122394Sharti struct sockaddr_in *sain; 783122394Sharti 784122394Sharti memset(&hints, 0, sizeof(hints)); 785122394Sharti hints.ai_family = AF_INET; 786122394Sharti hints.ai_socktype = SOCK_DGRAM; 787122394Sharti hints.ai_protocol = IPPROTO_UDP; 788122394Sharti hints.ai_flags = AI_PASSIVE; 789122394Sharti error = getaddrinfo(host, NULL, &hints, &res); 790122394Sharti if (error != 0) 791122394Sharti report("%s: %s", host, gai_strerror(error)); 792122394Sharti if (res == NULL) 793122394Sharti report("%s: unknown hostname", host); 794122394Sharti 795122394Sharti sain = (struct sockaddr_in *)(void *)res->ai_addr; 796122394Sharti sain->sin_addr.s_addr = ntohl(sain->sin_addr.s_addr); 797122394Sharti ip[0] = sain->sin_addr.s_addr >> 24; 798122394Sharti ip[1] = sain->sin_addr.s_addr >> 16; 799122394Sharti ip[2] = sain->sin_addr.s_addr >> 8; 800122394Sharti ip[3] = sain->sin_addr.s_addr >> 0; 801122394Sharti 802122394Sharti freeaddrinfo(res); 803122394Sharti} 804122394Sharti 805122394Sharti/* 806122394Sharti * Parse the left hand side of a config line. 807122394Sharti */ 808122394Shartistatic const struct snmp_node * 809122394Shartiparse_oid(const char *varname, struct asn_oid *oid) 810122394Sharti{ 811122394Sharti struct snmp_node *node; 812122394Sharti u_int i; 813122394Sharti u_char ip[4]; 814216294Ssyrinx struct asn_oid str_oid; 815122394Sharti 816122394Sharti for (node = tree; node < &tree[tree_size]; node++) 817122394Sharti if (strcmp(varname, node->name) == 0) 818122394Sharti break; 819122394Sharti if (node == &tree[tree_size]) 820122394Sharti node = NULL; 821122394Sharti 822122394Sharti oid->len = 0; 823122394Sharti while (token == '.') { 824122394Sharti if (gettoken() == TOK_NUM) { 825122394Sharti if (numval > ASN_MAXID) 826150920Sharti report("subid too large %#"QUADXFMT, numval); 827122394Sharti if (oid->len == ASN_MAXOIDLEN) 828122394Sharti report("index too long"); 829216294Ssyrinx if (gettoken() != ':') 830216294Ssyrinx oid->subs[oid->len++] = numval; 831216294Ssyrinx else { 832216294Ssyrinx str_oid.len = 0; 833216294Ssyrinx str_oid.subs[str_oid.len++] = numval; 834216294Ssyrinx while (gettoken() == TOK_NUM) { 835216294Ssyrinx str_oid.subs[str_oid.len++] = numval; 836216294Ssyrinx if (gettoken() != ':') 837216294Ssyrinx break; 838216294Ssyrinx } 839216294Ssyrinx oid->subs[oid->len++] = str_oid.len; 840216294Ssyrinx asn_append_oid(oid, &str_oid); 841216294Ssyrinx } 842122394Sharti 843122394Sharti } else if (token == TOK_STR) { 844122394Sharti if (strvallen + oid->len + 1 > ASN_MAXOIDLEN) 845122394Sharti report("oid too long"); 846122394Sharti oid->subs[oid->len++] = strvallen; 847122394Sharti for (i = 0; i < strvallen; i++) 848122394Sharti oid->subs[oid->len++] = strval[i]; 849216294Ssyrinx gettoken(); 850122394Sharti 851122394Sharti } else if (token == TOK_HOST) { 852122394Sharti gethost(strval, ip); 853122394Sharti if (oid->len + 4 > ASN_MAXOIDLEN) 854122394Sharti report("index too long"); 855122394Sharti for (i = 0; i < 4; i++) 856122394Sharti oid->subs[oid->len++] = ip[i]; 857216294Ssyrinx gettoken(); 858122394Sharti } else 859122394Sharti report("bad token in index"); 860122394Sharti } 861122394Sharti 862122394Sharti return (node); 863122394Sharti} 864122394Sharti 865122394Sharti/* 866122394Sharti * Parse the value for an assignment. 867122394Sharti */ 868122394Shartistatic void 869122394Shartiparse_syntax_null(struct snmp_value *value __unused) 870122394Sharti{ 871122394Sharti if (token != TOK_EOL) 872122394Sharti report("bad NULL syntax"); 873122394Sharti} 874122394Sharti 875122394Shartistatic void 876122394Shartiparse_syntax_integer(struct snmp_value *value) 877122394Sharti{ 878122394Sharti if (token != TOK_NUM) 879122394Sharti report("bad INTEGER syntax"); 880122394Sharti if (numval > 0x7fffffff) 881150920Sharti report("INTEGER too large %"QUADFMT, numval); 882122394Sharti 883122394Sharti value->v.integer = numval; 884122394Sharti gettoken(); 885122394Sharti} 886122394Sharti 887122394Shartistatic void 888122394Shartiparse_syntax_counter64(struct snmp_value *value) 889122394Sharti{ 890122394Sharti if (token != TOK_NUM) 891122394Sharti report("bad COUNTER64 syntax"); 892122394Sharti 893122394Sharti value->v.counter64 = numval; 894122394Sharti gettoken(); 895122394Sharti} 896122394Sharti 897122394Shartistatic void 898122394Shartiparse_syntax_octetstring(struct snmp_value *value) 899122394Sharti{ 900122394Sharti u_long alloc; 901122394Sharti u_char *noct; 902122394Sharti 903122394Sharti if (token == TOK_STR) { 904122394Sharti value->v.octetstring.len = strvallen; 905122394Sharti value->v.octetstring.octets = malloc(strvallen); 906122394Sharti (void)memcpy(value->v.octetstring.octets, strval, strvallen); 907122394Sharti gettoken(); 908122394Sharti return; 909122394Sharti } 910122394Sharti 911122394Sharti /* XX:XX:XX syntax */ 912122394Sharti value->v.octetstring.octets = NULL; 913122394Sharti value->v.octetstring.len = 0; 914122394Sharti 915122394Sharti if (token != TOK_NUM) 916122394Sharti /* empty string is allowed */ 917122394Sharti return; 918122394Sharti 919122394Sharti if (ERRPUSH()) { 920122394Sharti free(value->v.octetstring.octets); 921122394Sharti ERRNEXT(); 922122394Sharti } 923122394Sharti 924122394Sharti alloc = 0; 925122394Sharti for (;;) { 926122394Sharti if (token != TOK_NUM) 927122394Sharti report("bad OCTETSTRING syntax"); 928122394Sharti if (numval > 0xff) 929122394Sharti report("byte value too large"); 930122394Sharti if (alloc == value->v.octetstring.len) { 931122394Sharti alloc += 100; 932122394Sharti noct = realloc(value->v.octetstring.octets, alloc); 933122394Sharti if (noct == NULL) 934122394Sharti report("%m"); 935122394Sharti value->v.octetstring.octets = noct; 936122394Sharti } 937122394Sharti value->v.octetstring.octets[value->v.octetstring.len++] 938122394Sharti = numval; 939122394Sharti if (gettoken() != ':') 940122394Sharti break; 941122394Sharti gettoken(); 942122394Sharti } 943122394Sharti ERRPOP(); 944122394Sharti} 945122394Sharti 946122394Shartistatic void 947122394Shartiparse_syntax_oid(struct snmp_value *value) 948122394Sharti{ 949122394Sharti value->v.oid.len = 0; 950122394Sharti 951122394Sharti if (token != TOK_NUM) 952122394Sharti return; 953122394Sharti 954122394Sharti for (;;) { 955122394Sharti if (token != TOK_NUM) 956122394Sharti report("bad OID syntax"); 957122394Sharti if (numval > ASN_MAXID) 958122394Sharti report("subid too large"); 959122394Sharti if (value->v.oid.len == ASN_MAXOIDLEN) 960122394Sharti report("OID too long"); 961122394Sharti value->v.oid.subs[value->v.oid.len++] = numval; 962122394Sharti if (gettoken() != '.') 963122394Sharti break; 964122394Sharti gettoken(); 965122394Sharti } 966122394Sharti} 967122394Sharti 968122394Shartistatic void 969122394Shartiparse_syntax_ipaddress(struct snmp_value *value) 970122394Sharti{ 971122394Sharti int i; 972122394Sharti u_char ip[4]; 973122394Sharti 974122394Sharti if (token == TOK_NUM) { 975122394Sharti /* numerical address */ 976122394Sharti i = 0; 977122394Sharti for (;;) { 978122394Sharti if (numval >= 256) 979122394Sharti report("ip address part too large"); 980122394Sharti value->v.ipaddress[i++] = numval; 981122394Sharti if (i == 4) 982122394Sharti break; 983122394Sharti if (gettoken() != '.') 984122394Sharti report("expecting '.' in ip address"); 985122394Sharti } 986122394Sharti gettoken(); 987122394Sharti 988122394Sharti } else if (token == TOK_HOST) { 989122394Sharti /* host name */ 990122394Sharti gethost(strval, ip); 991122394Sharti for (i = 0; i < 4; i++) 992122394Sharti value->v.ipaddress[i] = ip[i]; 993122394Sharti gettoken(); 994122394Sharti 995122394Sharti } else 996122394Sharti report("bad ip address syntax"); 997122394Sharti} 998122394Sharti 999122394Shartistatic void 1000122394Shartiparse_syntax_uint32(struct snmp_value *value) 1001122394Sharti{ 1002122394Sharti 1003122394Sharti if (token != TOK_NUM) 1004122394Sharti report("bad number syntax"); 1005122394Sharti if (numval > 0xffffffff) 1006122394Sharti report("number too large"); 1007122394Sharti value->v.uint32 = numval; 1008122394Sharti gettoken(); 1009122394Sharti} 1010122394Sharti 1011122394Sharti/* 1012122394Sharti * Parse an assignement line 1013122394Sharti */ 1014122394Shartistatic void 1015122394Shartiparse_assign(const char *varname) 1016122394Sharti{ 1017122394Sharti struct snmp_value value; 1018122394Sharti struct asn_oid vindex; 1019122394Sharti const struct snmp_node *node; 1020122394Sharti 1021122394Sharti node = parse_oid(varname, &vindex); 1022122394Sharti if (token != '=') 1023216294Ssyrinx report("'=' expected, got '%c'", token); 1024122394Sharti gettoken(); 1025122394Sharti 1026122394Sharti if (ignore) { 1027122394Sharti /* skip rest of line */ 1028122394Sharti while (token != TOK_EOL && token != TOK_EOF) 1029122394Sharti gettoken(); 1030122394Sharti return; 1031122394Sharti } 1032122394Sharti if (node == NULL) 1033122394Sharti report("unknown variable"); 1034122394Sharti 1035122394Sharti switch (value.syntax = node->syntax) { 1036122394Sharti 1037122394Sharti case SNMP_SYNTAX_NULL: 1038122394Sharti parse_syntax_null(&value); 1039122394Sharti break; 1040122394Sharti 1041122394Sharti case SNMP_SYNTAX_INTEGER: 1042122394Sharti parse_syntax_integer(&value); 1043122394Sharti break; 1044122394Sharti 1045122394Sharti case SNMP_SYNTAX_COUNTER64: 1046122394Sharti parse_syntax_counter64(&value); 1047122394Sharti break; 1048122394Sharti 1049122394Sharti case SNMP_SYNTAX_OCTETSTRING: 1050122394Sharti parse_syntax_octetstring(&value); 1051122394Sharti break; 1052122394Sharti 1053122394Sharti case SNMP_SYNTAX_OID: 1054122394Sharti parse_syntax_oid(&value); 1055122394Sharti break; 1056122394Sharti 1057122394Sharti case SNMP_SYNTAX_IPADDRESS: 1058122394Sharti parse_syntax_ipaddress(&value); 1059122394Sharti break; 1060122394Sharti 1061122394Sharti case SNMP_SYNTAX_COUNTER: 1062122394Sharti case SNMP_SYNTAX_GAUGE: 1063122394Sharti case SNMP_SYNTAX_TIMETICKS: 1064122394Sharti parse_syntax_uint32(&value); 1065122394Sharti break; 1066122394Sharti 1067122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 1068122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 1069122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 1070122394Sharti abort(); 1071122394Sharti } 1072122394Sharti 1073122394Sharti if (ERRPUSH()) { 1074122394Sharti snmp_value_free(&value); 1075122394Sharti ERRNEXT(); 1076122394Sharti } 1077122394Sharti 1078122394Sharti handle_assignment(node, &vindex, &value); 1079122394Sharti 1080122394Sharti ERRPOP(); 1081122394Sharti} 1082122394Sharti 1083122394Sharti/* 1084122394Sharti * Handle macro definition line 1085122394Sharti * We have already seen the := and the input now stands at the character 1086122394Sharti * after the =. Skip whitespace and then call the input routine directly to 1087122394Sharti * eat up characters. 1088122394Sharti */ 1089122394Shartistatic void 1090122394Shartiparse_define(const char *varname) 1091122394Sharti{ 1092122394Sharti char *volatile string; 1093122394Sharti char *new; 1094122394Sharti volatile size_t alloc, length; 1095122394Sharti int c; 1096122394Sharti struct macro *m; 1097122394Sharti int t = token; 1098122394Sharti 1099122394Sharti alloc = 100; 1100122394Sharti length = 0; 1101122394Sharti if ((string = malloc(alloc)) == NULL) 1102122394Sharti report("%m"); 1103122394Sharti 1104122394Sharti if (ERRPUSH()) { 1105122394Sharti free(string); 1106122394Sharti ERRNEXT(); 1107122394Sharti } 1108122394Sharti 1109122394Sharti while ((c = input_getc_plain()) != EOF) { 1110122394Sharti if (c == '\n' || !isspace(c)) 1111122394Sharti break; 1112122394Sharti } 1113122394Sharti 1114122394Sharti while (c != EOF && c != '#' && c != '\n') { 1115122394Sharti if (alloc == length) { 1116122394Sharti alloc *= 2; 1117122394Sharti if ((new = realloc(string, alloc)) == NULL) 1118122394Sharti report("%m"); 1119122394Sharti string = new; 1120122394Sharti } 1121122394Sharti string[length++] = c; 1122122394Sharti c = input_getc_plain(); 1123122394Sharti } 1124122394Sharti if (c == '#') { 1125122394Sharti while ((c = input_getc_plain()) != EOF && c != '\n') 1126122394Sharti ; 1127122394Sharti } 1128122394Sharti if (c == EOF) 1129122394Sharti report("EOF in macro definition"); 1130122394Sharti 1131122394Sharti LIST_FOREACH(m, ¯os, link) 1132122394Sharti if (strcmp(m->name, varname) == 0) 1133122394Sharti break; 1134122394Sharti 1135122394Sharti if (m == NULL) { 1136122394Sharti if ((m = malloc(sizeof(*m))) == NULL) 1137122394Sharti report("%m"); 1138122394Sharti if ((m->name = malloc(strlen(varname) + 1)) == NULL) { 1139122394Sharti free(m); 1140122394Sharti report("%m"); 1141122394Sharti } 1142122394Sharti strcpy(m->name, varname); 1143122394Sharti m->perm = 0; 1144122394Sharti LIST_INSERT_HEAD(¯os, m, link); 1145122394Sharti 1146122394Sharti m->value = string; 1147122394Sharti m->length = length; 1148122394Sharti } else { 1149150920Sharti if (t == TOK_ASSIGN) { 1150122394Sharti free(m->value); 1151122394Sharti m->value = string; 1152122394Sharti m->length = length; 1153122394Sharti } 1154122394Sharti } 1155122394Sharti 1156122394Sharti token = TOK_EOL; 1157122394Sharti 1158122394Sharti ERRPOP(); 1159122394Sharti} 1160122394Sharti 1161122394Sharti/* 1162122394Sharti * Free all macros 1163122394Sharti */ 1164122394Shartistatic void 1165122394Shartimacro_free_all(void) 1166122394Sharti{ 1167122394Sharti static struct macro *m, *m1; 1168122394Sharti 1169122394Sharti m = LIST_FIRST(¯os); 1170122394Sharti while (m != NULL) { 1171122394Sharti m1 = LIST_NEXT(m, link); 1172122394Sharti if (!m->perm) { 1173122394Sharti free(m->name); 1174122394Sharti free(m->value); 1175122394Sharti LIST_REMOVE(m, link); 1176122394Sharti free(m); 1177122394Sharti } 1178122394Sharti m = m1; 1179122394Sharti } 1180122394Sharti} 1181122394Sharti 1182122394Sharti/* 1183122394Sharti * Parse an include directive and switch to the new file 1184122394Sharti */ 1185122394Shartistatic void 1186122394Shartiparse_include(void) 1187122394Sharti{ 1188122394Sharti int sysdir = 0; 1189122394Sharti char fname[_POSIX2_LINE_MAX]; 1190122394Sharti 1191122394Sharti if (gettoken() == '<') { 1192122394Sharti sysdir = 1; 1193122394Sharti if (gettoken() != TOK_STR) 1194122394Sharti report("expecting filename after in .include"); 1195122394Sharti } else if (token != TOK_STR) 1196122394Sharti report("expecting filename after in .include"); 1197122394Sharti 1198122394Sharti strcpy(fname, strval); 1199122394Sharti if (sysdir && gettoken() != '>') 1200122394Sharti report("expecting '>'"); 1201122394Sharti gettoken(); 1202122394Sharti if (input_open_file(fname, sysdir) == -1) 1203122394Sharti report("%s: %m", fname); 1204122394Sharti} 1205122394Sharti 1206122394Sharti/* 1207122394Sharti * Parse the configuration file 1208122394Sharti */ 1209122394Shartistatic void 1210122394Shartiparse_file(const struct lmodule *mod) 1211122394Sharti{ 1212122394Sharti char varname[_POSIX2_LINE_MAX]; 1213122394Sharti 1214122394Sharti while (gettoken() != TOK_EOF) { 1215122394Sharti if (token == TOK_EOL) 1216122394Sharti /* empty line */ 1217122394Sharti continue; 1218122394Sharti if (token == '%') { 1219122394Sharti gettoken(); 1220122394Sharti parse_section(mod); 1221122394Sharti } else if (token == '.') { 1222122394Sharti if (gettoken() != TOK_STR) 1223122394Sharti report("keyword expected after '.'"); 1224122394Sharti if (strcmp(strval, "include") == 0) 1225122394Sharti parse_include(); 1226122394Sharti else 1227122394Sharti report("unknown keyword '%s'", strval); 1228122394Sharti } else if (token == TOK_STR) { 1229122394Sharti strcpy(varname, strval); 1230122394Sharti if (gettoken() == TOK_ASSIGN || token == TOK_QASSIGN) 1231122394Sharti parse_define(varname); 1232122394Sharti else 1233122394Sharti parse_assign(varname); 1234122394Sharti } 1235122394Sharti if (token != TOK_EOL) 1236122394Sharti report("eol expected"); 1237122394Sharti } 1238122394Sharti} 1239122394Sharti 1240122394Sharti/* 1241122394Sharti * Do rollback on errors 1242122394Sharti */ 1243122394Shartistatic void 1244122394Shartido_rollback(void) 1245122394Sharti{ 1246122394Sharti struct assign *tp; 1247122394Sharti struct snmp_node *node; 1248122394Sharti 1249122394Sharti while ((tp = TAILQ_LAST(&assigns, assigns)) != NULL) { 1250122394Sharti TAILQ_REMOVE(&assigns, tp, link); 1251122394Sharti for (node = tree; node < &tree[tree_size]; node++) 1252122394Sharti if (node->name == tp->node_name) { 1253122394Sharti snmp_ctx->scratch = &tp->scratch; 1254122394Sharti (void)(*node->op)(snmp_ctx, &tp->value, 1255122394Sharti node->oid.len, node->index, 1256122394Sharti SNMP_OP_ROLLBACK); 1257122394Sharti break; 1258122394Sharti } 1259122394Sharti if (node == &tree[tree_size]) 1260122394Sharti syslog(LOG_ERR, "failed to find node for " 1261122394Sharti "rollback"); 1262122394Sharti snmp_value_free(&tp->value); 1263122394Sharti free(tp); 1264122394Sharti } 1265122394Sharti} 1266122394Sharti 1267122394Sharti/* 1268122394Sharti * Do commit 1269122394Sharti */ 1270122394Shartistatic void 1271122394Shartido_commit(void) 1272122394Sharti{ 1273122394Sharti struct assign *tp; 1274122394Sharti struct snmp_node *node; 1275122394Sharti 1276122394Sharti while ((tp = TAILQ_FIRST(&assigns)) != NULL) { 1277122394Sharti TAILQ_REMOVE(&assigns, tp, link); 1278122394Sharti for (node = tree; node < &tree[tree_size]; node++) 1279122394Sharti if (node->name == tp->node_name) { 1280122394Sharti snmp_ctx->scratch = &tp->scratch; 1281122394Sharti (void)(*node->op)(snmp_ctx, &tp->value, 1282122394Sharti node->oid.len, node->index, SNMP_OP_COMMIT); 1283122394Sharti break; 1284122394Sharti } 1285122394Sharti if (node == &tree[tree_size]) 1286122394Sharti syslog(LOG_ERR, "failed to find node for commit"); 1287122394Sharti snmp_value_free(&tp->value); 1288122394Sharti free(tp); 1289122394Sharti } 1290122394Sharti} 1291122394Sharti 1292122394Sharti/* 1293122394Sharti * Read the configuration file. Handle the entire file as one transaction. 1294122394Sharti * 1295122394Sharti * If lodmod is NULL, the sections for 'snmpd' and all loaded modules are 1296122394Sharti * executed. If it is not NULL, only the sections for that module are handled. 1297122394Sharti */ 1298122394Shartiint 1299122394Shartiread_config(const char *fname, struct lmodule *lodmod) 1300122394Sharti{ 1301122394Sharti int err; 1302122394Sharti char objbuf[ASN_OIDSTRLEN]; 1303122394Sharti char idxbuf[ASN_OIDSTRLEN]; 1304122394Sharti 1305122394Sharti ignore = 0; 1306122394Sharti 1307122394Sharti input_push = 0; 1308133594Sharti 1309133594Sharti if (ERRPUSH()) 1310133594Sharti return (-1); 1311122394Sharti if (input_open_file(fname, 0) == -1) { 1312122394Sharti syslog(LOG_ERR, "%s: %m", fname); 1313122394Sharti return (-1); 1314122394Sharti } 1315133594Sharti ERRPOP(); 1316122394Sharti community = COMM_INITIALIZE; 1317122394Sharti 1318122394Sharti if ((snmp_ctx = snmp_init_context()) == NULL) { 1319133594Sharti input_close_all(); 1320122394Sharti syslog(LOG_ERR, "%m"); 1321122394Sharti return (-1); 1322122394Sharti } 1323122394Sharti 1324122394Sharti if (ERRPUSH()) { 1325122394Sharti do_rollback(); 1326122394Sharti input_close_all(); 1327122394Sharti macro_free_all(); 1328122394Sharti free(snmp_ctx); 1329122394Sharti return (-1); 1330122394Sharti } 1331122394Sharti parse_file(lodmod); 1332122394Sharti ERRPOP(); 1333122394Sharti 1334122394Sharti if ((err = snmp_dep_commit(snmp_ctx)) != SNMP_ERR_NOERROR) { 1335122394Sharti syslog(LOG_ERR, "init dep failed: %u %s %s", err, 1336122394Sharti asn_oid2str_r(&snmp_ctx->dep->obj, objbuf), 1337122394Sharti asn_oid2str_r(&snmp_ctx->dep->idx, idxbuf)); 1338122394Sharti snmp_dep_rollback(snmp_ctx); 1339122394Sharti do_rollback(); 1340122394Sharti input_close_all(); 1341122394Sharti macro_free_all(); 1342122394Sharti free(snmp_ctx); 1343122394Sharti return (-1); 1344122394Sharti } 1345122394Sharti 1346122394Sharti do_commit(); 1347128237Sharti snmp_dep_finish(snmp_ctx); 1348128237Sharti 1349122394Sharti macro_free_all(); 1350122394Sharti 1351122394Sharti free(snmp_ctx); 1352122394Sharti 1353122394Sharti return (0); 1354122394Sharti} 1355122394Sharti 1356122394Sharti/* 1357122394Sharti * Define a permanent macro 1358122394Sharti */ 1359122394Shartiint 1360122394Shartidefine_macro(const char *name, const char *value) 1361122394Sharti{ 1362122394Sharti struct macro *m; 1363122394Sharti 1364122394Sharti if ((m = malloc(sizeof(*m))) == NULL) 1365122394Sharti return (-1); 1366122394Sharti if ((m->name = malloc(strlen(name) + 1)) == NULL) { 1367122394Sharti free(m); 1368122394Sharti return (-1); 1369122394Sharti } 1370122394Sharti strcpy(m->name, name); 1371122394Sharti if ((m->value = malloc(strlen(value) + 1)) == NULL) { 1372122394Sharti free(m->name); 1373122394Sharti free(m); 1374122394Sharti return (-1); 1375122394Sharti } 1376122394Sharti strcpy(m->value, value); 1377122394Sharti m->length = strlen(value); 1378150920Sharti m->perm = 1; 1379150920Sharti LIST_INSERT_HEAD(¯os, m, link); 1380122394Sharti return (0); 1381122394Sharti} 1382