1124758Semax/*- 2124758Semax * Copyright (c) 2006 The FreeBSD Project 3124758Semax * All rights reserved. 4124758Semax * 5124758Semax * Author: Shteryana Shopova <syrinx@FreeBSD.org> 6124758Semax * 7124758Semax * Redistribution of this software and documentation and use in source and 8124758Semax * binary forms, with or without modification, are permitted provided that 9124758Semax * the following conditions are met: 10124758Semax * 11124758Semax * 1. Redistributions of source code or documentation must retain the above 12124758Semax * copyright notice, this list of conditions and the following disclaimer. 13124758Semax * 2. Redistributions in binary form must reproduce the above copyright 14124758Semax * notice, this list of conditions and the following disclaimer in the 15124758Semax * documentation and/or other materials provided with the distribution. 16124758Semax * 17124758Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20124758Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27124758Semax * SUCH DAMAGE. 28124758Semax * 29124758Semax * $FreeBSD: releng/10.3/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c 216295 2010-12-08 14:30:25Z syrinx $ 30124758Semax */ 31124758Semax 32124758Semax/* 33124758Semax * Read file containing table description - reuse magic from gensnmptree.c. 34124758Semax * Hopefully one day most of the code here will be part of libbsnmp and 35124758Semax * this duplication won't be necessary. 36124758Semax * 37124758Semax * Syntax is: 38124758Semax * --------- 39124758Semax * file := top | top file 40124758Semax * 41124758Semax * top := tree | typedef | include 42124758Semax * 43124758Semax * tree := head elements ')' 44124758Semax * 45124758Semax * entry := head ':' index STRING elements ')' 46124758Semax * 47124758Semax * leaf := head type STRING ACCESS ')' 48124758Semax * 49124758Semax * column := head type ACCESS ')' 50124758Semax * 51124758Semax * type := BASETYPE | BASETYPE '|' subtype | enum | bits 52124758Semax * 53124758Semax * subtype := STRING 54124758Semax * 55124758Semax * enum := ENUM '(' value ')' 56124758Semax * 57124758Semax * bits := BITS '(' value ')' 58124758Semax * 59124758Semax * value := INT STRING | INT STRING value 60124758Semax * 61124758Semax * head := '(' INT STRING 62124758Semax * 63124758Semax * elements := EMPTY | elements element 64124758Semax * 65124758Semax * element := tree | leaf | column 66124758Semax * 67124758Semax * index := type | index type 68124758Semax * 69124758Semax * typedef := 'typedef' STRING type 70124758Semax * 71124758Semax * include := 'include' filespec 72124758Semax * 73124758Semax * filespec := '"' STRING '"' | '<' STRING '>' 74124758Semax */ 75124758Semax 76124758Semax#include <sys/param.h> 77124758Semax#include <sys/queue.h> 78124758Semax#include <sys/uio.h> 79124758Semax 80124758Semax#include <ctype.h> 81124758Semax#include <err.h> 82124758Semax#include <errno.h> 83124758Semax#include <fcntl.h> 84124758Semax#include <stdio.h> 85124758Semax#include <stdlib.h> 86124758Semax#include <string.h> 87124758Semax#include <syslog.h> 88124758Semax#include <unistd.h> 89124758Semax 90124758Semax#include <bsnmp/asn1.h> 91124758Semax#include <bsnmp/snmp.h> 92124758Semax#include <bsnmp/snmpagent.h> /* SNMP_INDEXES_MAX */ 93124758Semax#include "bsnmptc.h" 94124758Semax#include "bsnmptools.h" 95124758Semax 96124758Semaxenum snmp_tbl_entry { 97124758Semax ENTRY_NONE = 0, 98124758Semax ENTRY_INDEX, 99124758Semax ENTRY_DATA 100124758Semax}; 101124758Semax 102124758Semaxenum { 103124758Semax FL_GET = 0x01, 104124758Semax FL_SET = 0x02, 105124758Semax}; 106124758Semax 107124758Semax/************************************************************ 108124758Semax * 109124758Semax * Allocate memory and panic just in the case... 110124758Semax */ 111124758Semaxstatic void * 112124758Semaxxalloc(size_t size) 113124758Semax{ 114124758Semax void *ptr; 115124758Semax 116124758Semax if ((ptr = malloc(size)) == NULL) 117124758Semax err(1, "allocing %zu bytes", size); 118124758Semax 119124758Semax return (ptr); 120124758Semax} 121124758Semax 122124758Semaxstatic char * 123124758Semaxsavestr(const char *s) 124124758Semax{ 125124758Semax if (s == NULL) 126124758Semax return (NULL); 127124758Semax 128124758Semax return (strcpy(xalloc(strlen(s) + 1), s)); 129124758Semax} 130124758Semax 131124758Semax/************************************************************ 132124758Semax * 133124758Semax * Input stack 134124758Semax */ 135124758Semaxstruct input { 136124758Semax FILE *fp; 137124758Semax uint32_t lno; 138124758Semax char *fname; 139124758Semax char *path; 140124758Semax LIST_ENTRY(input) link; 141124758Semax}; 142124758Semax 143124758SemaxLIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); 144124758Semaxstruct input *input = NULL; 145124758Semaxint32_t pbchar = -1; 146124758Semax 147124758Semax#define MAX_PATHS 100 148124758Semax 149124758Semaxstatic const char *paths[MAX_PATHS + 1] = { 150124758Semax "/usr/share/snmp/defs", 151124758Semax "/usr/local/share/snmp/defs", 152124758Semax NULL 153124758Semax}; 154124758Semax 155124758Semaxstatic void 156124758Semaxinput_new(FILE *fp, const char *path, const char *fname) 157124758Semax{ 158124758Semax struct input *ip; 159124758Semax 160124758Semax ip = xalloc(sizeof(*ip)); 161124758Semax ip->fp = fp; 162124758Semax ip->lno = 1; 163124758Semax ip->fname = savestr(fname); 164124758Semax ip->path = savestr(path); 165124758Semax LIST_INSERT_HEAD(&inputs, ip, link); 166124758Semax 167124758Semax input = ip; 168124758Semax} 169124758Semax 170124758Semaxstatic void 171124758Semaxinput_close(void) 172124758Semax{ 173124758Semax if (input == NULL) 174124758Semax return; 175124758Semax 176124758Semax fclose(input->fp); 177124758Semax free(input->fname); 178124758Semax free(input->path); 179124758Semax LIST_REMOVE(input, link); 180124758Semax free(input); 181124758Semax 182124758Semax input = LIST_FIRST(&inputs); 183124758Semax} 184124758Semax 185124758Semaxstatic FILE * 186124758Semaxtryopen(const char *path, const char *fname) 187124758Semax{ 188124758Semax char *fn; 189124758Semax FILE *fp; 190124758Semax 191124758Semax if (path == NULL) 192124758Semax fn = savestr(fname); 193124758Semax else { 194124758Semax fn = xalloc(strlen(path) + strlen(fname) + 2); 195124758Semax sprintf(fn, "%s/%s", path, fname); 196124758Semax } 197124758Semax fp = fopen(fn, "r"); 198124758Semax free(fn); 199124758Semax return (fp); 200124758Semax} 201124758Semax 202124758Semaxstatic int32_t 203124758Semaxinput_fopen(const char *fname) 204124758Semax{ 205124758Semax FILE *fp; 206124758Semax u_int p; 207124758Semax 208124758Semax if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') { 209124758Semax if ((fp = tryopen(NULL, fname)) != NULL) { 210124758Semax input_new(fp, NULL, fname); 211124758Semax return (0); 212124758Semax } 213124758Semax 214124758Semax } else { 215124758Semax 216124758Semax for (p = 0; paths[p] != NULL; p++) 217124758Semax if ((fp = tryopen(paths[p], fname)) != NULL) { 218124758Semax input_new(fp, paths[p], fname); 219124758Semax return (0); 220124758Semax } 221124758Semax } 222124758Semax 223124758Semax warnx("cannot open '%s'", fname); 224124758Semax return (-1); 225124758Semax} 226124758Semax 227124758Semaxstatic int32_t 228124758Semaxtgetc(void) 229124758Semax{ 230124758Semax int c; 231124758Semax 232124758Semax if (pbchar != -1) { 233124758Semax c = pbchar; 234124758Semax pbchar = -1; 235124758Semax return (c); 236 } 237 238 for (;;) { 239 if (input == NULL) 240 return (EOF); 241 242 if ((c = getc(input->fp)) != EOF) 243 return (c); 244 245 input_close(); 246 } 247} 248 249static int32_t 250tungetc(int c) 251{ 252 253 if (pbchar != -1) 254 return (-1); 255 256 pbchar = c; 257 return (1); 258} 259 260/************************************************************ 261 * 262 * Parsing input 263 */ 264enum tok { 265 TOK_EOF = 0200, /* end-of-file seen */ 266 TOK_NUM, /* number */ 267 TOK_STR, /* string */ 268 TOK_ACCESS, /* access operator */ 269 TOK_TYPE, /* type operator */ 270 TOK_ENUM, /* enum token (kind of a type) */ 271 TOK_TYPEDEF, /* typedef directive */ 272 TOK_DEFTYPE, /* defined type */ 273 TOK_INCLUDE, /* include directive */ 274 TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */ 275 TOK_BITS, /* bits token (kind of a type) */ 276 TOK_ERR /* unexpected char - exit */ 277}; 278 279static const struct { 280 const char *str; 281 enum tok tok; 282 uint32_t val; 283} keywords[] = { 284 { "GET", TOK_ACCESS, FL_GET }, 285 { "SET", TOK_ACCESS, FL_SET }, 286 { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, 287 { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 288 { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 289 { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 290 { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, 291 { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, 292 { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, 293 { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, 294 { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, 295 { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 296 { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, 297 { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, 298 { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, 299 { "typedef", TOK_TYPEDEF, 0 }, 300 { "include", TOK_INCLUDE, 0 }, 301 { NULL, 0, 0 } 302}; 303 304struct { 305 /* Current OID type, regarding table membership. */ 306 enum snmp_tbl_entry tbl_type; 307 /* A pointer to a structure in table list to add to its members. */ 308 struct snmp_index_entry *table_idx; 309} table_data; 310 311struct asn_oid current_oid; 312char nexttok[MAXSTR]; 313u_long val; /* integer values */ 314int32_t all_cond; /* all conditions are true */ 315int32_t saved_token = -1; 316 317/* Prepare the global data before parsing a new file. */ 318static void 319snmp_import_init(struct asn_oid *append) 320{ 321 memset(&table_data, 0, sizeof(table_data)); 322 memset(¤t_oid, 0, sizeof(struct asn_oid)); 323 memset(nexttok, 0, MAXSTR); 324 325 if (append != NULL) 326 asn_append_oid(¤t_oid, append); 327 328 all_cond = 0; 329 val = 0; 330 saved_token = -1; 331} 332 333static int32_t 334gettoken(struct snmp_toolinfo *snmptoolctx) 335{ 336 int c; 337 struct enum_type *t; 338 339 if (saved_token != -1) { 340 c = saved_token; 341 saved_token = -1; 342 return (c); 343 } 344 345 again: 346 /* 347 * Skip any whitespace before the next token. 348 */ 349 while ((c = tgetc()) != EOF) { 350 if (c == '\n') 351 input->lno++; 352 if (!isspace(c)) 353 break; 354 } 355 if (c == EOF) 356 return (TOK_EOF); 357 358 if (!isascii(c)) { 359 warnx("unexpected character %#2x", (u_int) c); 360 return (TOK_ERR); 361 } 362 363 /* 364 * Skip comments. 365 */ 366 if (c == '#') { 367 while ((c = tgetc()) != EOF) { 368 if (c == '\n') { 369 input->lno++; 370 goto again; 371 } 372 } 373 warnx("unexpected EOF in comment"); 374 return (TOK_ERR); 375 } 376 377 /* 378 * Single character tokens. 379 */ 380 if (strchr("():|", c) != NULL) 381 return (c); 382 383 if (c == '"' || c == '<') { 384 int32_t end = c; 385 size_t n = 0; 386 387 val = 1; 388 if (c == '<') { 389 val = 0; 390 end = '>'; 391 } 392 393 while ((c = tgetc()) != EOF) { 394 if (c == end) 395 break; 396 if (n == sizeof(nexttok) - 1) { 397 nexttok[n++] = '\0'; 398 warnx("filename too long '%s...'", nexttok); 399 return (TOK_ERR); 400 } 401 nexttok[n++] = c; 402 } 403 nexttok[n++] = '\0'; 404 return (TOK_FILENAME); 405 } 406 407 /* 408 * Sort out numbers. 409 */ 410 if (isdigit(c)) { 411 size_t n = 0; 412 nexttok[n++] = c; 413 while ((c = tgetc()) != EOF) { 414 if (!isdigit(c)) { 415 if (tungetc(c) < 0) 416 return (TOK_ERR); 417 break; 418 } 419 if (n == sizeof(nexttok) - 1) { 420 nexttok[n++] = '\0'; 421 warnx("number too long '%s...'", nexttok); 422 return (TOK_ERR); 423 } 424 nexttok[n++] = c; 425 } 426 nexttok[n++] = '\0'; 427 sscanf(nexttok, "%lu", &val); 428 return (TOK_NUM); 429 } 430 431 /* 432 * So that has to be a string. 433 */ 434 if (isalpha(c) || c == '_' || c == '-') { 435 size_t n = 0; 436 nexttok[n++] = c; 437 while ((c = tgetc()) != EOF) { 438 if (!isalnum(c) && c != '_' && c != '-') { 439 if (tungetc (c) < 0) 440 return (TOK_ERR); 441 break; 442 } 443 if (n == sizeof(nexttok) - 1) { 444 nexttok[n++] = '\0'; 445 warnx("string too long '%s...'", nexttok); 446 return (TOK_ERR); 447 } 448 nexttok[n++] = c; 449 } 450 nexttok[n++] = '\0'; 451 452 /* 453 * Keywords. 454 */ 455 for (c = 0; keywords[c].str != NULL; c++) 456 if (strcmp(keywords[c].str, nexttok) == 0) { 457 val = keywords[c].val; 458 return (keywords[c].tok); 459 } 460 461 if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) { 462 val = t->syntax; 463 return (TOK_DEFTYPE); 464 } 465 466 return (TOK_STR); 467 } 468 469 if (isprint(c)) 470 warnx("%u: unexpected character '%c'", input->lno, c); 471 else 472 warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c); 473 474 return (TOK_ERR); 475} 476 477/* 478 * Update table information. 479 */ 480static struct snmp_index_entry * 481snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl) 482{ 483 switch (te) { 484 case ENTRY_NONE: 485 if (table_data.tbl_type == ENTRY_NONE) 486 return (NULL); 487 if (table_data.tbl_type == ENTRY_INDEX) 488 table_data.table_idx = NULL; 489 table_data.tbl_type--; 490 return (NULL); 491 492 case ENTRY_INDEX: 493 if (tbl == NULL) 494 warnx("No table_index to add!!!"); 495 table_data.table_idx = tbl; 496 table_data.tbl_type = ENTRY_INDEX; 497 return (tbl); 498 499 case ENTRY_DATA: 500 if (table_data.tbl_type == ENTRY_INDEX) { 501 table_data.tbl_type = ENTRY_DATA; 502 return (table_data.table_idx); 503 } 504 return (NULL); 505 506 default: 507 /* NOTREACHED */ 508 warnx("Unknown table entry type!!!"); 509 break; 510 } 511 512 return (NULL); 513} 514 515static int32_t 516parse_enum(struct snmp_toolinfo *snmptoolctx, enum tok *tok, 517 struct enum_pairs *enums) 518{ 519 while ((*tok = gettoken(snmptoolctx)) == TOK_STR) { 520 if (enum_pair_insert(enums, val, nexttok) < 0) 521 return (-1); 522 if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) 523 break; 524 } 525 526 if (*tok != ')') { 527 warnx("')' at end of enums"); 528 return (-1); 529 } 530 531 return (1); 532} 533 534static int32_t 535parse_subtype(struct snmp_toolinfo *snmptoolctx, enum tok *tok, 536 enum snmp_tc *tc) 537{ 538 if ((*tok = gettoken(snmptoolctx)) != TOK_STR) { 539 warnx("subtype expected after '|'"); 540 return (-1); 541 } 542 543 *tc = snmp_get_tc(nexttok); 544 *tok = gettoken(snmptoolctx); 545 546 return (1); 547} 548 549static int32_t 550parse_type(struct snmp_toolinfo *snmptoolctx, enum tok *tok, 551 enum snmp_tc *tc, struct enum_pairs **snmp_enum) 552{ 553 int32_t syntax, mem; 554 555 syntax = val; 556 *tc = 0; 557 558 if (*tok == TOK_ENUM || *tok == TOK_BITS) { 559 if (*snmp_enum == NULL) { 560 if ((*snmp_enum = enum_pairs_init()) == NULL) 561 return (-1); 562 mem = 1; 563 *tc = SNMP_TC_OWN; 564 } else 565 mem = 0; 566 567 if (gettoken(snmptoolctx) != '(') { 568 warnx("'(' expected after ENUM/BITS"); 569 return (-1); 570 } 571 572 if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) { 573 warnx("need value for ENUM//BITS"); 574 if (mem == 1) { 575 free(*snmp_enum); 576 *snmp_enum = NULL; 577 } 578 return (-1); 579 } 580 581 if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) { 582 enum_pairs_free(*snmp_enum); 583 *snmp_enum = NULL; 584 return (-1); 585 } 586 587 *tok = gettoken(snmptoolctx); 588 589 } else if (*tok == TOK_DEFTYPE) { 590 struct enum_type *t; 591 592 *tc = 0; 593 t = snmp_enumtc_lookup(snmptoolctx, nexttok); 594 if (t != NULL) 595 *snmp_enum = t->snmp_enum; 596 597 *tok = gettoken(snmptoolctx); 598 599 } else { 600 if ((*tok = gettoken(snmptoolctx)) == '|') { 601 if (parse_subtype(snmptoolctx, tok, tc) < 0) 602 return (-1); 603 } 604 } 605 606 return (syntax); 607} 608 609static int32_t 610snmp_import_head(struct snmp_toolinfo *snmptoolctx) 611{ 612 enum tok tok; 613 614 if ((tok = gettoken(snmptoolctx)) == '(') 615 tok = gettoken(snmptoolctx); 616 617 if (tok != TOK_NUM || val > ASN_MAXID ) { 618 warnx("Suboid expected - line %d", input->lno); 619 return (-1); 620 } 621 622 if (gettoken(snmptoolctx) != TOK_STR) { 623 warnx("Node name expected at line %d", input->lno); 624 return (-1); 625 } 626 627 return (1); 628} 629 630static int32_t 631snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj) 632{ 633 int32_t i; 634 enum snmp_tc tc; 635 enum tok tok; 636 struct snmp_index_entry *entry; 637 638 if ((entry = malloc(sizeof(struct snmp_index_entry))) == NULL) { 639 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); 640 return (-1); 641 } 642 643 memset(entry, 0, sizeof(struct snmp_index_entry)); 644 STAILQ_INIT(&(entry->index_list)); 645 646 for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) { 647 int32_t syntax; 648 struct enum_pairs *enums = NULL; 649 650 if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM && 651 tok != TOK_BITS) 652 break; 653 654 if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) { 655 enum_pairs_free(enums); 656 snmp_index_listfree(&(entry->index_list)); 657 free(entry); 658 return (-1); 659 } 660 661 if (snmp_syntax_insert(&(entry->index_list), enums, syntax, 662 tc) < 0) { 663 snmp_index_listfree(&(entry->index_list)); 664 enum_pairs_free(enums); 665 free(entry); 666 return (-1); 667 } 668 } 669 670 if (i == 0 || i > SNMP_INDEXES_MAX) { 671 warnx("Bad number of indexes at line %d", input->lno); 672 snmp_index_listfree(&(entry->index_list)); 673 free(entry); 674 return (-1); 675 } 676 677 if (tok != TOK_STR) { 678 warnx("String expected after indexes at line %d", input->lno); 679 snmp_index_listfree(&(entry->index_list)); 680 free(entry); 681 return (-1); 682 } 683 684 entry->string = obj->string; 685 entry->strlen = obj->strlen; 686 asn_append_oid(&(entry->var), &(obj->var)); 687 688 if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) { 689 snmp_index_listfree(&(entry->index_list)); 690 free(entry); 691 return (-1); 692 } else if (i == 0) { 693 /* Same entry already present in lists. */ 694 free(entry->string); 695 free(entry); 696 } 697 698 (void) snmp_import_update_table(ENTRY_INDEX, entry); 699 700 return (1); 701} 702 703/* 704 * Read everything after the syntax type that is certainly a leaf OID info. 705 */ 706static int32_t 707snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, enum tok *tok, 708 struct snmp_oid2str *oid2str) 709{ 710 int32_t i, syntax; 711 712 if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum))) 713 < 0) 714 return(-1); 715 716 oid2str->syntax = syntax; 717 /* 718 * That is the name of the function, corresponding to the entry. 719 * It is used by bsnmpd, but is not interesting for us. 720 */ 721 if (*tok == TOK_STR) 722 *tok = gettoken(snmptoolctx); 723 724 for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) { 725 oid2str->access |= (uint32_t) val; 726 *tok = gettoken(snmptoolctx); 727 } 728 729 if (*tok != ')') { 730 warnx("')' expected at end of line %d", input->lno); 731 return (-1); 732 } 733 734 oid2str->table_idx = snmp_import_update_table(ENTRY_DATA, NULL); 735 736 if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) { 737 warnx("Error adding leaf %s to list", oid2str->string); 738 return (-1); 739 } 740 741 /* 742 * Same entry is already present in the mapping lists and 743 * the new one was not inserted. 744 */ 745 if (i == 0) { 746 free(oid2str->string); 747 free(oid2str); 748 } 749 750 (void) snmp_import_update_table(ENTRY_NONE, NULL); 751 752 return (1); 753} 754 755static int32_t 756snmp_import_object(struct snmp_toolinfo *snmptoolctx) 757{ 758 char *string; 759 int i; 760 enum tok tok; 761 struct snmp_oid2str *oid2str; 762 763 if (snmp_import_head(snmptoolctx) < 0) 764 return (-1); 765 766 if ((oid2str = malloc(sizeof(struct snmp_oid2str))) == NULL) { 767 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); 768 return (-1); 769 } 770 771 if ((string = malloc(strlen(nexttok) + 1)) == NULL) { 772 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); 773 free(oid2str); 774 return (-1); 775 } 776 777 memset(oid2str, 0, sizeof(struct snmp_oid2str)); 778 strlcpy(string, nexttok, strlen(nexttok) + 1); 779 oid2str->string = string; 780 oid2str->strlen = strlen(nexttok); 781 782 asn_append_oid(&(oid2str->var), &(current_oid)); 783 if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0) 784 goto error; 785 786 /* 787 * Prepared the entry - now figure out where to insert it. 788 * After the object we have following options: 789 * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist; 790 * 2) new line , ( - nonleaf oid -> snmp_nodelist; 791 * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more) 792 * may follow and second string must end line -> snmp_tablelist; 793 * 3) OID , string ) - this is a trap entry or a leaf -> snmp_oidlist; 794 * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last 795 * and )- this is definitely a leaf. 796 */ 797 798 switch (tok = gettoken(snmptoolctx)) { 799 case ')': 800 if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0) 801 goto error; 802 if (i == 0) { 803 free(oid2str->string); 804 free(oid2str); 805 } 806 return (1); 807 808 case '(': 809 if (snmp_suboid_append(¤t_oid, (asn_subid_t) val) < 0) 810 goto error; 811 812 /* 813 * Ignore the error for nodes since the .def files currently 814 * contain different strings for 1.3.6.1.2.1 - mibII. Only make 815 * sure the memory is freed and don't complain. 816 */ 817 if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) { 818 free(string); 819 free(oid2str); 820 } 821 return (snmp_import_object(snmptoolctx)); 822 823 case ':': 824 if (snmp_suboid_append(¤t_oid, (asn_subid_t) val) < 0) 825 goto error; 826 if (snmp_import_table(snmptoolctx, oid2str) < 0) 827 goto error; 828 /* 829 * A different table entry type was malloced and the data is 830 * contained there. 831 */ 832 free(oid2str); 833 return (1); 834 835 case TOK_TYPE: 836 /* FALLTHROUGH */ 837 case TOK_DEFTYPE: 838 /* FALLTHROUGH */ 839 case TOK_ENUM: 840 /* FALLTHROUGH */ 841 case TOK_BITS: 842 if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0) 843 goto error; 844 return (1); 845 846 default: 847 warnx("Unexpected token at line %d - %s", input->lno, 848 input->fname); 849 break; 850 } 851 852error: 853 snmp_mapping_entryfree(oid2str); 854 855 return (-1); 856} 857 858static int32_t 859snmp_import_tree(struct snmp_toolinfo *snmptoolctx, enum tok *tok) 860{ 861 while (*tok != TOK_EOF) { 862 switch (*tok) { 863 case TOK_ERR: 864 return (-1); 865 case '(': 866 if (snmp_import_object(snmptoolctx) < 0) 867 return (-1); 868 break; 869 case ')': 870 if (snmp_suboid_pop(¤t_oid) < 0) 871 return (-1); 872 (void) snmp_import_update_table(ENTRY_NONE, NULL); 873 break; 874 default: 875 /* Anything else here would be illegal. */ 876 return (-1); 877 } 878 *tok = gettoken(snmptoolctx); 879 } 880 881 return (0); 882} 883 884static int32_t 885snmp_import_top(struct snmp_toolinfo *snmptoolctx, enum tok *tok) 886{ 887 enum snmp_tc tc; 888 struct enum_type *t; 889 890 if (*tok == '(') 891 return (snmp_import_tree(snmptoolctx, tok)); 892 893 if (*tok == TOK_TYPEDEF) { 894 if ((*tok = gettoken(snmptoolctx)) != TOK_STR) { 895 warnx("type name expected after typedef - %s", 896 input->fname); 897 return (-1); 898 } 899 900 t = snmp_enumtc_init(nexttok); 901 902 *tok = gettoken(snmptoolctx); 903 t->is_enum = (*tok == TOK_ENUM); 904 t->is_bits = (*tok == TOK_BITS); 905 t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum)); 906 snmp_enumtc_insert(snmptoolctx, t); 907 908 return (1); 909 } 910 911 if (*tok == TOK_INCLUDE) { 912 int i; 913 914 *tok = gettoken(snmptoolctx); 915 if (*tok != TOK_FILENAME) { 916 warnx("filename expected in include directive - %s", 917 nexttok); 918 return (-1); 919 } 920 921 if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) { 922 *tok = gettoken(snmptoolctx); 923 return (1); 924 } 925 926 if (i == -1) 927 return (-1); 928 929 input_fopen(nexttok); 930 *tok = gettoken(snmptoolctx); 931 return (1); 932 } 933 934 warnx("'(' or 'typedef' expected - %s", nexttok); 935 return (-1); 936} 937 938static int32_t 939snmp_import(struct snmp_toolinfo *snmptoolctx) 940{ 941 int i; 942 enum tok tok; 943 944 tok = gettoken(snmptoolctx); 945 946 do 947 i = snmp_import_top(snmptoolctx, &tok); 948 while (i > 0); 949 950 return (i); 951} 952 953/* 954 * Read a .def file and import oid<->string mapping. 955 * Mappings are inserted into a global structure containing list for each OID 956 * syntax type. 957 */ 958int32_t 959snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file) 960{ 961 int idx; 962 963 snmp_import_init(&(file->cut)); 964 input_fopen(file->name); 965 if ((idx = snmp_import(snmptoolctx)) < 0) 966 warnx("Failed to read mappings from file %s", file->name); 967 968 input_close(); 969 970 return (idx); 971} 972