1 /*- 2 * Copyright (c) 2006 The FreeBSD Project 3 * All rights reserved. 4 * 5 * Author: Shteryana Shopova <syrinx@FreeBSD.org> 6 * 7 * Redistribution of this software and documentation and use in source and 8 * binary forms, with or without modification, are permitted provided that 9 * the following conditions are met: 10 * 11 * 1. Redistributions of source code or documentation must retain the above 12 * copyright notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * Textual conventions for OctetStrings 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/queue.h> 36 #include <sys/socket.h> 37 #include <sys/uio.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <syslog.h> 47 #include <unistd.h> 48 49 #include <arpa/inet.h> 50 #include <netinet/in.h> 51 52 #include <bsnmp/asn1.h> 53 #include <bsnmp/snmp.h> 54 #include "bsnmptc.h" 55 #include "bsnmptools.h" 56 57 /* OctetString, DisplayString */ 58 static char *snmp_oct2str(uint32_t, char *, char *); 59 static char *snmp_str2asn_oid(char *, struct asn_oid *); 60 static int parse_octetstring(struct snmp_value *, char *); 61 62 /* DateAndTime */ 63 static char *snmp_octstr2date(uint32_t, char *, char *); 64 static char *snmp_date2asn_oid(char * , struct asn_oid *); 65 static int parse_dateandtime(struct snmp_value *, char *); 66 67 /* PhysAddress */ 68 static char *snmp_oct2physAddr(uint32_t, char *, char *); 69 static char *snmp_addr2asn_oid(char *, struct asn_oid *); 70 static int parse_physaddress(struct snmp_value *, char *); 71 72 /* NTPTimeStamp */ 73 static char *snmp_oct2ntp_ts(uint32_t, char *, char *); 74 static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *); 75 static int parse_ntp_ts(struct snmp_value *, char *); 76 77 /* BridgeId */ 78 static char *snmp_oct2bridgeid(uint32_t, char *, char *); 79 static char *snmp_bridgeid2oct(char *, struct asn_oid *); 80 static int parse_bridge_id(struct snmp_value *, char *); 81 82 /* BridgePortId */ 83 static char *snmp_oct2bport_id(uint32_t, char *, char *); 84 static char *snmp_bport_id2oct(char *, struct asn_oid *); 85 static int parse_bport_id(struct snmp_value *, char *); 86 87 /* InetAddress */ 88 static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf); 89 static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid); 90 static int32_t parse_inetaddr(struct snmp_value *value, char *string); 91 92 static char *snmp_oct2bits(uint32_t len, char *octets, char *buf); 93 static char *snmp_bits2oct(char *str, struct asn_oid *oid); 94 static int32_t parse_bits(struct snmp_value *value, char *string); 95 96 static struct snmp_text_conv { 97 enum snmp_tc tc; 98 const char *tc_str; 99 int32_t len; 100 snmp_oct2tc_f oct2tc; 101 snmp_tc2oid_f tc2oid; 102 snmp_tc2oct_f tc2oct; 103 } text_convs[] = { 104 { SNMP_STRING, "OctetString", SNMP_VAR_STRSZ, 105 snmp_oct2str, snmp_str2asn_oid, parse_octetstring }, 106 107 { SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ, 108 snmp_oct2str, snmp_str2asn_oid, parse_octetstring }, 109 110 { SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ, 111 snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime }, 112 113 { SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ, 114 snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress }, 115 116 { SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ, 117 snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress }, 118 119 { SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ, 120 snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts }, 121 122 { SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ, 123 snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress }, 124 125 { SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ, 126 snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id }, 127 128 { SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ, 129 snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id }, 130 131 { SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ, 132 snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr }, 133 134 { SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ, 135 snmp_oct2bits, snmp_bits2oct, parse_bits }, 136 137 { SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str, 138 snmp_str2asn_oid, parse_octetstring } /* keep last */ 139 }; 140 141 /* Common API */ 142 enum snmp_tc 143 snmp_get_tc(char *str) 144 { 145 int i; 146 for (i = 0; i < SNMP_UNKNOWN; i++) { 147 if (!strncmp(text_convs[i].tc_str, str, 148 strlen(text_convs[i].tc_str))) 149 return (text_convs[i].tc); 150 } 151 152 return (SNMP_STRING); 153 } 154 155 char * 156 snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets) 157 { 158 uint32_t tc_len; 159 char * buf; 160 161 if (tc > SNMP_UNKNOWN) 162 tc = SNMP_UNKNOWN; 163 164 if (text_convs[tc].len > 0) 165 tc_len = text_convs[tc].len; 166 else 167 tc_len = 2 * len + 3; 168 169 if ((buf = malloc(tc_len)) == NULL ) { 170 syslog(LOG_ERR, "malloc failed - %s", strerror(errno)); 171 return (NULL); 172 } 173 174 memset(buf, 0, tc_len); 175 if (text_convs[tc].oct2tc(len, octets, buf) == NULL) { 176 free(buf); 177 return (NULL); 178 } 179 180 return (buf); 181 } 182 183 char * 184 snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid) 185 { 186 if (tc > SNMP_UNKNOWN) 187 tc = SNMP_UNKNOWN; 188 189 return (text_convs[tc].tc2oid(str, oid)); 190 } 191 192 int32_t 193 snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string) 194 { 195 if (tc > SNMP_UNKNOWN) 196 tc = SNMP_UNKNOWN; 197 198 return (text_convs[tc].tc2oct(value, string)); 199 } 200 201 /***************************************************** 202 * Basic OctetString type. 203 */ 204 static char * 205 snmp_oct2str(uint32_t len, char *octets, char *buf) 206 { 207 uint8_t binary = 0; 208 uint32_t i; 209 char *ptr; 210 211 if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL) 212 return (NULL); 213 214 for (ptr = buf, i = 0; i < len; i++) 215 if (!isprint(octets[i])) { 216 binary = 1; 217 buf += sprintf(buf, "0x"); 218 break; 219 } 220 221 for (ptr = buf, i = 0; i < len; i++) 222 if (!binary) 223 ptr += sprintf(ptr, "%c", octets[i]); 224 else 225 ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]); 226 227 return (buf); 228 } 229 230 static char * 231 snmp_str2asn_oid(char *str, struct asn_oid *oid) 232 { 233 uint32_t i, len = 0; 234 235 /* 236 * OctetStrings are allowed max length of ASN_MAXOCTETSTRING, 237 * but trying to index an entry with such a long OctetString 238 * will fail anyway. 239 */ 240 for (len = 0; len < ASN_MAXOIDLEN; len++) { 241 if (strchr(",]", *(str + len)) != NULL) 242 break; 243 } 244 245 if (len >= ASN_MAXOIDLEN) 246 return (NULL); 247 248 if (snmp_suboid_append(oid, (asn_subid_t) len) < 0) 249 return (NULL); 250 251 for (i = 0; i < len; i++) 252 if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0) 253 return (NULL); 254 255 return (str + len); 256 } 257 258 static int32_t 259 parse_octetstring(struct snmp_value *value, char *val) 260 { 261 size_t len; 262 263 if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) { 264 warnx("Octetstring too long - %d is max allowed", 265 MAX_OCTSTRING_LEN - 1); 266 return (-1); 267 } 268 269 if ((value->v.octetstring.octets = malloc(len)) == NULL) { 270 value->v.octetstring.len = 0; 271 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 272 return (-1); 273 } 274 275 value->v.octetstring.len = len; 276 memcpy(value->v.octetstring.octets, val, len); 277 value->syntax = SNMP_SYNTAX_OCTETSTRING; 278 279 return (0); 280 } 281 282 /************************************************************* 283 * DateAndTime 284 ************************************************************* 285 * rfc 2579 specification: 286 * DateAndTime ::= TEXTUAL-CONVENTION 287 * DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d" 288 * STATUS current 289 * DESCRIPTION 290 * "A date-time specification. 291 * 292 * field octets contents range 293 * ----- ------ -------- ----- 294 * 1 1-2 year* 0..65536 295 * 2 3 month 1..12 296 * 3 4 day 1..31 297 * 4 5 hour 0..23 298 * 5 6 minutes 0..59 299 * 6 7 seconds 0..60 300 * (use 60 for leap-second) 301 * 7 8 deci-seconds 0..9 302 * 8 9 direction from UTC '+' / '-' 303 * 9 10 hours from UTC* 0..13 304 * 10 11 minutes from UTC 0..59 305 * 306 * * Notes: 307 * - the value of year is in network-byte order 308 * - daylight saving time in New Zealand is +13 309 * 310 * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be 311 * displayed as: 312 * 313 * 1992-5-26,13:30:15.0,-4:0 314 */ 315 static char * 316 snmp_octstr2date(uint32_t len, char *octets, char *buf) 317 { 318 int year; 319 char *ptr; 320 321 if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL) 322 return (NULL); 323 324 buf[0]= '\0'; 325 year = (octets[0] << 8); 326 year += (octets[1]); 327 328 ptr = buf; 329 ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]); 330 ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5], 331 octets[6],octets[7]); 332 ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]); 333 334 return (buf); 335 } 336 337 static char * 338 snmp_date2asn_oid(char *str, struct asn_oid *oid) 339 { 340 char *endptr, *ptr; 341 static const char UTC[3] = "UTC"; 342 int32_t saved_errno; 343 uint32_t v; 344 345 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0) 346 return (NULL); 347 348 /* Read 'YYYY-' and write it in two subs. */ 349 ptr = str; 350 saved_errno = errno; 351 errno = 0; 352 v = strtoul(ptr, &endptr, 10); 353 if (v > 0xffff) 354 goto error; 355 else 356 errno = saved_errno; 357 if (*endptr != '-') 358 goto error1; 359 if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0) 360 return (NULL); 361 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0) 362 return (NULL); 363 364 /* 'MM-' */ 365 ptr = endptr + 1; 366 saved_errno = errno; 367 errno = 0; 368 v = strtoul(ptr, &endptr, 10); 369 if (errno != 0) 370 goto error; 371 else 372 errno = saved_errno; 373 if (*endptr != '-') 374 goto error1; 375 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 376 return (NULL); 377 378 /* 'DD,' */ 379 ptr = endptr + 1; 380 saved_errno = errno; 381 errno = 0; 382 v = strtoul(ptr, &endptr, 10); 383 if (errno != 0) 384 goto error; 385 else 386 errno = saved_errno; 387 if (*endptr != '-') 388 goto error1; 389 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 390 return (NULL); 391 392 /* 'HH:' */ 393 ptr = endptr + 1; 394 saved_errno = errno; 395 errno = 0; 396 v = strtoul(ptr, &endptr, 10); 397 if (errno != 0) 398 goto error; 399 else 400 errno = saved_errno; 401 if (*endptr != ':') 402 goto error1; 403 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 404 return (NULL); 405 406 /* 'MM:' */ 407 ptr = endptr + 1; 408 saved_errno = errno; 409 errno = 0; 410 v = strtoul(ptr, &endptr, 10); 411 if (errno != 0) 412 goto error; 413 else 414 errno = saved_errno; 415 if (*endptr != ':') 416 goto error1; 417 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 418 return (NULL); 419 420 /* 'SS.' */ 421 ptr = endptr + 1; 422 saved_errno = errno; 423 errno = 0; 424 v = strtoul(ptr, &endptr, 10); 425 if (errno != 0) 426 goto error; 427 else 428 errno = saved_errno; 429 if (*endptr != '.') 430 goto error1; 431 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 432 return (NULL); 433 434 /* 'M(mseconds),' */ 435 ptr = endptr + 1; 436 saved_errno = errno; 437 errno = 0; 438 v = strtoul(ptr, &endptr, 10); 439 if (errno != 0) 440 goto error; 441 else 442 errno = saved_errno; 443 if (*endptr != ',') 444 goto error1; 445 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 446 return (NULL); 447 448 /* 'UTC' - optional */ 449 ptr = endptr + 1; 450 if (strncmp(ptr, UTC, sizeof(UTC)) == 0) 451 ptr += sizeof(UTC); 452 453 /* '+/-' */ 454 if (*ptr == '-' || *ptr == '+') { 455 if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0) 456 return (NULL); 457 } else 458 goto error1; 459 460 /* 'HH:' */ 461 ptr = endptr + 1; 462 saved_errno = errno; 463 errno = 0; 464 v = strtoul(ptr, &endptr, 10); 465 if (errno != 0) 466 goto error; 467 else 468 errno = saved_errno; 469 if (*endptr != ':') 470 goto error1; 471 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 472 return (NULL); 473 474 /* 'MM' - last one - ignore endptr here. */ 475 ptr = endptr + 1; 476 saved_errno = errno; 477 errno = 0; 478 v = strtoul(ptr, &endptr, 10); 479 if (errno != 0) 480 goto error; 481 else 482 errno = saved_errno; 483 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 484 return (NULL); 485 486 return (endptr); 487 488 error: 489 errno = saved_errno; 490 error1: 491 warnx("Date value %s not supported", str); 492 return (NULL); 493 } 494 495 /* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */ 496 static int32_t 497 parse_dateandtime(struct snmp_value *sv, char *val) 498 { 499 char *endptr; 500 uint32_t v; 501 uint8_t date[SNMP_DATETIME_OCTETS]; 502 503 /* 'YYYY-' */ 504 v = strtoul(val, &endptr, 10); 505 if (v > 0xffff || *endptr != '-') 506 goto error; 507 date[0] = ((v & 0xff00) >> 8); 508 date[1] = (v & 0xff); 509 val = endptr + 1; 510 511 /* 'MM-' */ 512 v = strtoul(val, &endptr, 10); 513 if (v == 0 || v > 12 || *endptr != '-') 514 goto error; 515 date[2] = v; 516 val = endptr + 1; 517 518 /* 'DD,' */ 519 v = strtoul(val, &endptr, 10); 520 if (v == 0 || v > 31 || *endptr != ',') 521 goto error; 522 date[3] = v; 523 val = endptr + 1; 524 525 /* 'HH:' */ 526 v = strtoul(val, &endptr, 10); 527 if (v > 23 || *endptr != ':') 528 goto error; 529 date[4] = v; 530 val = endptr + 1; 531 532 /* 'MM:' */ 533 v = strtoul(val, &endptr, 10); 534 if (v > 59 || *endptr != ':') 535 goto error; 536 date[5] = v; 537 val = endptr + 1; 538 539 /* 'SS.' */ 540 v = strtoul(val, &endptr, 10); 541 if (v > 60 || *endptr != '.') 542 goto error; 543 date[6] = v; 544 val = endptr + 1; 545 546 /* '(deci-)s,' */ 547 v = strtoul(val, &endptr, 10); 548 if (v > 9 || *endptr != ',') 549 goto error; 550 date[7] = v; 551 val = endptr + 1; 552 553 /* offset - '+/-' */ 554 if (*val != '-' && *val != '+') 555 goto error; 556 date[8] = (uint8_t) *val; 557 val = endptr + 1; 558 559 /* 'HH:' - offset from UTC */ 560 v = strtoul(val, &endptr, 10); 561 if (v > 13 || *endptr != ':') 562 goto error; 563 date[9] = v; 564 val = endptr + 1; 565 566 /* 'MM'\0'' offset from UTC */ 567 v = strtoul(val, &endptr, 10); 568 if (v > 59 || *endptr != '\0') 569 goto error; 570 date[10] = v; 571 572 if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) { 573 warn("malloc() failed"); 574 return (-1); 575 } 576 577 sv->v.octetstring.len = SNMP_DATETIME_OCTETS; 578 memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS); 579 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 580 return (1); 581 582 error: 583 warnx("Date value %s not supported", val); 584 return (-1); 585 } 586 587 /************************************************************** 588 * PhysAddress 589 */ 590 static char * 591 snmp_oct2physAddr(uint32_t len, char *octets, char *buf) 592 { 593 char *ptr; 594 uint32_t i; 595 596 if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL) 597 return (NULL); 598 599 buf[0]= '\0'; 600 601 ptr = buf; 602 ptr += sprintf(ptr, "%2.2x", octets[0]); 603 for (i = 1; i < 6; i++) 604 ptr += sprintf(ptr, ":%2.2x", octets[i]); 605 606 return (buf); 607 } 608 609 static char * 610 snmp_addr2asn_oid(char *str, struct asn_oid *oid) 611 { 612 char *endptr, *ptr; 613 uint32_t v, i; 614 int saved_errno; 615 616 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0) 617 return (NULL); 618 619 ptr = str; 620 for (i = 0; i < 5; i++) { 621 saved_errno = errno; 622 v = strtoul(ptr, &endptr, 16); 623 errno = saved_errno; 624 if (v > 0xff) { 625 warnx("Integer value %s not supported", str); 626 return (NULL); 627 } 628 if (*endptr != ':') { 629 warnx("Failed adding oid - %s", str); 630 return (NULL); 631 } 632 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 633 return (NULL); 634 ptr = endptr + 1; 635 } 636 637 /* The last one - don't check the ending char here. */ 638 saved_errno = errno; 639 v = strtoul(ptr, &endptr, 16); 640 errno = saved_errno; 641 if (v > 0xff) { 642 warnx("Integer value %s not supported", str); 643 return (NULL); 644 } 645 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 646 return (NULL); 647 648 return (endptr); 649 } 650 651 static int32_t 652 parse_physaddress(struct snmp_value *sv, char *val) 653 { 654 char *endptr; 655 int32_t i; 656 uint32_t v; 657 uint8_t phys_addr[SNMP_PHYSADDR_OCTETS]; 658 659 for (i = 0; i < 5; i++) { 660 v = strtoul(val, &endptr, 16); 661 if (v > 0xff) { 662 warnx("Integer value %s not supported", val); 663 return (-1); 664 } 665 if(*endptr != ':') { 666 warnx("Failed reading octet - %s", val); 667 return (-1); 668 } 669 phys_addr[i] = v; 670 val = endptr + 1; 671 } 672 673 /* The last one - don't check the ending char here. */ 674 v = strtoul(val, &endptr, 16); 675 if (v > 0xff) { 676 warnx("Integer value %s not supported", val); 677 return (-1); 678 } 679 phys_addr[5] = v; 680 681 if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) { 682 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 683 return (-1); 684 } 685 686 sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS; 687 memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS); 688 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 689 return (1); 690 } 691 692 /************************************************************** 693 * NTPTimeStamp 694 ************************************************************** 695 * NTP MIB, Revision 0.2, 7/25/97: 696 * NTPTimeStamp ::= TEXTUAL-CONVENTION 697 * DISPLAY-HINT "4x.4x" 698 * STATUS current 699 * DESCRIPTION 700 * "" 701 * SYNTAX OCTET STRING (SIZE(8)) 702 */ 703 static char * 704 snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf) 705 { 706 char *ptr; 707 uint32_t i; 708 709 if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL) 710 return (NULL); 711 712 buf[0]= '\0'; 713 714 ptr = buf; 715 i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3]; 716 ptr += sprintf(ptr, "%4.4d", i); 717 i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7]; 718 ptr += sprintf(ptr, ".%4.4d", i); 719 720 return (buf); 721 } 722 723 static char * 724 snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid) 725 { 726 char *endptr, *ptr; 727 uint32_t v, i, d; 728 struct asn_oid suboid; 729 int saved_errno; 730 731 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0) 732 return (NULL); 733 734 ptr = str; 735 saved_errno = errno; 736 errno = 0; 737 v = strtoul(ptr, &endptr, 10); 738 if (errno != 0 || (v / 1000) > 9) { 739 warnx("Integer value %s not supported", str); 740 errno = saved_errno; 741 return (NULL); 742 } else 743 errno = saved_errno; 744 745 if (*endptr != '.') { 746 warnx("Failed adding oid - %s", str); 747 return (NULL); 748 } 749 750 memset(&suboid, 0, sizeof(struct asn_oid)); 751 suboid.len = SNMP_NTP_TS_OCTETS; 752 753 for (i = 0, d = 1000; i < 4; i++) { 754 suboid.subs[i] = v / d; 755 v = v % d; 756 d = d / 10; 757 } 758 759 ptr = endptr + 1; 760 saved_errno = errno; 761 errno = 0; 762 v = strtoul(ptr, &endptr, 10); 763 if (errno != 0 || (v / 1000) > 9) { 764 warnx("Integer value %s not supported", str); 765 errno = saved_errno; 766 return (NULL); 767 } else 768 errno = saved_errno; 769 770 for (i = 0, d = 1000; i < 4; i++) { 771 suboid.subs[i + 4] = v / d; 772 v = v % d; 773 d = d / 10; 774 } 775 776 asn_append_oid(oid, &suboid); 777 return (endptr); 778 } 779 780 static int32_t 781 parse_ntp_ts(struct snmp_value *sv, char *val) 782 { 783 char *endptr; 784 int32_t i, d, saved_errno; 785 uint32_t v; 786 uint8_t ntp_ts[SNMP_NTP_TS_OCTETS]; 787 788 saved_errno = errno; 789 errno = 0; 790 v = strtoul(val, &endptr, 10); 791 if (errno != 0 || (v / 1000) > 9) { 792 errno = saved_errno; 793 warnx("Integer value %s not supported", val); 794 return (-1); 795 } else 796 errno = saved_errno; 797 798 if (*endptr != '.') { 799 warnx("Failed reading octet - %s", val); 800 return (-1); 801 } 802 803 for (i = 0, d = 1000; i < 4; i++) { 804 ntp_ts[i] = v / d; 805 v = v % d; 806 d = d / 10; 807 } 808 val = endptr + 1; 809 810 saved_errno = errno; 811 errno = 0; 812 v = strtoul(val, &endptr, 10); 813 if (errno != 0 || (v / 1000) > 9) { 814 errno = saved_errno; 815 warnx("Integer value %s not supported", val); 816 return (-1); 817 } else 818 errno = saved_errno; 819 820 for (i = 0, d = 1000; i < 4; i++) { 821 ntp_ts[i + 4] = v / d; 822 v = v % d; 823 d = d / 10; 824 } 825 826 if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) { 827 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 828 return (-1); 829 } 830 831 sv->v.octetstring.len = SNMP_NTP_TS_OCTETS; 832 memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS); 833 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 834 return (1); 835 } 836 837 /************************************************************** 838 * BridgeId 839 ************************************************************** 840 * BRIDGE-MIB, REVISION "200509190000Z" 841 * BridgeId ::= TEXTUAL-CONVENTION 842 * STATUS current 843 * DESCRIPTION 844 * "The Bridge-Identifier, as used in the Spanning Tree 845 * Protocol, to uniquely identify a bridge. Its first two 846 * octets (in network byte order) contain a priority value, 847 * and its last 6 octets contain the MAC address used to 848 * refer to a bridge in a unique fashion (typically, the 849 * numerically smallest MAC address of all ports on the 850 * bridge)." 851 * SYNTAX OCTET STRING (SIZE (8)) 852 */ 853 static char * 854 snmp_oct2bridgeid(uint32_t len, char *octets, char *buf) 855 { 856 char *ptr; 857 uint32_t i, priority; 858 859 if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL) 860 return (NULL); 861 862 buf[0]= '\0'; 863 ptr = buf; 864 865 priority = octets[0] << 8; 866 priority += octets[1]; 867 if (priority > SNMP_MAX_BRIDGE_PRIORITY) { 868 warnx("Invalid bridge priority %d", priority); 869 return (NULL); 870 } else 871 ptr += sprintf(ptr, "%d.", octets[0]); 872 873 ptr += sprintf(ptr, "%2.2x", octets[2]); 874 875 for (i = 1; i < 6; i++) 876 ptr += sprintf(ptr, ":%2.2x", octets[i + 2]); 877 878 return (buf); 879 } 880 881 static char * 882 snmp_bridgeid2oct(char *str, struct asn_oid *oid) 883 { 884 char *endptr, *ptr; 885 uint32_t v, i; 886 int32_t saved_errno; 887 888 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0) 889 return (NULL); 890 891 ptr = str; 892 /* Read the priority. */ 893 saved_errno = errno; 894 errno = 0; 895 v = strtoul(ptr, &endptr, 10); 896 897 if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') { 898 errno = saved_errno; 899 warnx("Bad bridge priority value %d", v); 900 return (NULL); 901 } 902 903 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0) 904 return (NULL); 905 906 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0) 907 return (NULL); 908 909 ptr = endptr + 1; 910 for (i = 0; i < 5; i++) { 911 saved_errno = errno; 912 errno = 0; 913 v = strtoul(ptr, &endptr, 16); 914 errno = saved_errno; 915 if (v > 0xff) { 916 warnx("Integer value %s not supported", str); 917 return (NULL); 918 } 919 if (*endptr != ':') { 920 warnx("Failed adding oid - %s",str); 921 return (NULL); 922 } 923 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 924 return (NULL); 925 ptr = endptr + 1; 926 } 927 928 /* The last one - don't check the ending char here. */ 929 saved_errno = errno; 930 errno = 0; 931 v = strtoul(ptr, &endptr, 16); 932 errno = saved_errno; 933 if (v > 0xff) { 934 warnx("Integer value %s not supported", str); 935 return (NULL); 936 } 937 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 938 return (NULL); 939 940 return (endptr); 941 } 942 943 static int32_t 944 parse_bridge_id(struct snmp_value *sv, char *string) 945 { 946 char *endptr; 947 int32_t i, saved_errno; 948 uint32_t v; 949 uint8_t bridge_id[SNMP_BRIDGEID_OCTETS]; 950 951 /* Read the priority. */ 952 saved_errno = errno; 953 errno = 0; 954 v = strtoul(string, &endptr, 10); 955 956 if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') { 957 errno = saved_errno; 958 warnx("Bad bridge priority value %d", v); 959 return (-1); 960 } 961 962 bridge_id[0] = (v & 0xff00); 963 bridge_id[1] = (v & 0xff); 964 965 string = endptr + 1; 966 967 for (i = 0; i < 5; i++) { 968 v = strtoul(string, &endptr, 16); 969 if (v > 0xff) { 970 warnx("Integer value %s not supported", string); 971 return (-1); 972 } 973 if(*endptr != ':') { 974 warnx("Failed reading octet - %s", string); 975 return (-1); 976 } 977 bridge_id[i + 2] = v; 978 string = endptr + 1; 979 } 980 981 /* The last one - don't check the ending char here. */ 982 v = strtoul(string, &endptr, 16); 983 if (v > 0xff) { 984 warnx("Integer value %s not supported", string); 985 return (-1); 986 } 987 bridge_id[7] = v; 988 989 if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) { 990 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 991 return (-1); 992 } 993 994 sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS; 995 memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS); 996 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 997 return (1); 998 } 999 1000 /************************************************************** 1001 * BridgePortId 1002 ************************************************************** 1003 * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z" 1004 * BridgePortId ::= TEXTUAL-CONVENTION 1005 * DISPLAY-HINT "1x.1x" 1006 * STATUS current 1007 * DESCRIPTION 1008 * "A port identifier that contains a bridge port's STP priority 1009 * in the first octet and the port number in the second octet." 1010 * SYNTAX OCTET STRING (SIZE(2)) 1011 */ 1012 static char * 1013 snmp_oct2bport_id(uint32_t len, char *octets, char *buf) 1014 { 1015 char *ptr; 1016 1017 if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL) 1018 return (NULL); 1019 1020 buf[0]= '\0'; 1021 ptr = buf; 1022 1023 ptr += sprintf(ptr, "%d.", octets[0]); 1024 ptr += sprintf(ptr, "%d", octets[1]); 1025 1026 return (buf); 1027 } 1028 1029 static char * 1030 snmp_bport_id2oct(char *str, struct asn_oid *oid) 1031 { 1032 char *endptr, *ptr; 1033 uint32_t v; 1034 int saved_errno; 1035 1036 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0) 1037 return (NULL); 1038 1039 ptr = str; 1040 /* Read the priority. */ 1041 saved_errno = errno; 1042 errno = 0; 1043 v = strtoul(ptr, &endptr, 10); 1044 1045 if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') { 1046 errno = saved_errno; 1047 warnx("Bad bridge port priority value %d", v); 1048 return (NULL); 1049 } 1050 1051 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1052 return (NULL); 1053 1054 saved_errno = errno; 1055 errno = 0; 1056 v = strtoul(ptr, &endptr, 16); 1057 errno = saved_errno; 1058 1059 if (v > 0xff) { 1060 warnx("Bad port number - %d", v); 1061 return (NULL); 1062 } 1063 1064 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1065 return (NULL); 1066 1067 return (endptr); 1068 } 1069 1070 static int32_t 1071 parse_bport_id(struct snmp_value *value, char *string) 1072 { 1073 char *endptr; 1074 int saved_errno; 1075 uint32_t v; 1076 uint8_t bport_id[SNMP_BPORT_OCTETS]; 1077 1078 /* Read the priority. */ 1079 saved_errno = errno; 1080 errno = 0; 1081 v = strtoul(string, &endptr, 10); 1082 1083 if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') { 1084 errno = saved_errno; 1085 warnx("Bad bridge port priority value %d", v); 1086 return (-1); 1087 } 1088 1089 bport_id[0] = v; 1090 1091 string = endptr + 1; 1092 v = strtoul(string, &endptr, 16); 1093 if (v > 0xff) { 1094 warnx("Bad port number - %d", v); 1095 return (-1); 1096 } 1097 1098 bport_id[1] = v; 1099 1100 if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) { 1101 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 1102 return (-1); 1103 } 1104 1105 value->v.octetstring.len = SNMP_BPORT_OCTETS; 1106 memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS); 1107 value->syntax = SNMP_SYNTAX_OCTETSTRING; 1108 return (1); 1109 } 1110 /************************************************************** 1111 * InetAddress 1112 ************************************************************** 1113 * INET-ADDRESS-MIB, REVISION "200502040000Z" 1114 * InetAddress ::= TEXTUAL-CONVENTION 1115 * STATUS current 1116 * DESCRIPTION 1117 * "Denotes a generic Internet address. 1118 * 1119 * An InetAddress value is always interpreted within the context 1120 * of an InetAddressType value. Every usage of the InetAddress 1121 * textual convention is required to specify the InetAddressType 1122 * object that provides the context. It is suggested that the 1123 * InetAddressType object be logically registered before the 1124 * object(s) that use the InetAddress textual convention, if 1125 * they appear in the same logical row. 1126 * 1127 * The value of an InetAddress object must always be 1128 * consistent with the value of the associated InetAddressType 1129 * object. Attempts to set an InetAddress object to a value 1130 * inconsistent with the associated InetAddressType 1131 * must fail with an inconsistentValue error. 1132 * 1133 * When this textual convention is used as the syntax of an 1134 * index object, there may be issues with the limit of 128 1135 * sub-identifiers specified in SMIv2, STD 58. In this case, 1136 * the object definition MUST include a 'SIZE' clause to 1137 * limit the number of potential instance sub-identifiers; 1138 * otherwise the applicable constraints MUST be stated in 1139 * the appropriate conceptual row DESCRIPTION clauses, or 1140 * in the surrounding documentation if there is no single 1141 * DESCRIPTION clause that is appropriate." 1142 * SYNTAX OCTET STRING (SIZE (0..255)) 1143 ************************************************************** 1144 * TODO: FIXME!!! syrinx: Since we do not support checking the 1145 * consistency of a varbinding based on the value of a previous 1146 * one, try to guess the type of address based on the 1147 * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently 1148 * not supported. 1149 */ 1150 static char * 1151 snmp_oct2inetaddr(uint32_t len, char *octets, char *buf) 1152 { 1153 int af; 1154 void *ip; 1155 struct in_addr ipv4; 1156 struct in6_addr ipv6; 1157 1158 if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL) 1159 return (NULL); 1160 1161 switch (len) { 1162 /* XXX: FIXME - IPv4*/ 1163 case 4: 1164 memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr)); 1165 af = AF_INET; 1166 ip = &ipv4; 1167 break; 1168 1169 /* XXX: FIXME - IPv4*/ 1170 case 16: 1171 memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr)); 1172 af = AF_INET6; 1173 ip = &ipv6; 1174 break; 1175 1176 default: 1177 return (NULL); 1178 } 1179 1180 if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) { 1181 warn("inet_ntop failed"); 1182 return (NULL); 1183 } 1184 1185 return (buf); 1186 } 1187 1188 static char * 1189 snmp_inetaddr2oct(char *str __unused, struct asn_oid *oid __unused) 1190 { 1191 return (NULL); 1192 } 1193 1194 static int32_t 1195 parse_inetaddr(struct snmp_value *value __unused, char *string __unused) 1196 { 1197 return (-1); 1198 } 1199 1200 /************************************************************** 1201 * SNMP BITS type - XXX: FIXME 1202 **************************************************************/ 1203 static char * 1204 snmp_oct2bits(uint32_t len, char *octets, char *buf) 1205 { 1206 int i, bits; 1207 uint64_t value; 1208 1209 if (len > sizeof(value) || octets == NULL || buf == NULL) 1210 return (NULL); 1211 1212 for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8) 1213 value += octets[i] << bits; 1214 1215 buf[0]= '\0'; 1216 sprintf(buf, "0x%llx.",(long long unsigned) value); 1217 1218 return (buf); 1219 } 1220 1221 static char * 1222 snmp_bits2oct(char *str, struct asn_oid *oid) 1223 { 1224 char *endptr; 1225 int i, size, bits, saved_errno; 1226 uint64_t v, mask = 0xFF00000000000000; 1227 1228 saved_errno = errno; 1229 errno = 0; 1230 1231 v = strtoull(str, &endptr, 16); 1232 if (errno != 0) { 1233 warn("Bad BITS value %s", str); 1234 errno = saved_errno; 1235 return (NULL); 1236 } 1237 1238 bits = 8; 1239 /* Determine length - up to 8 octets supported so far. */ 1240 for (size = sizeof(v); size > 0; size--) { 1241 if ((v & mask) != 0) 1242 break; 1243 mask = mask >> bits; 1244 } 1245 1246 if (size == 0) 1247 size = 1; 1248 1249 if (snmp_suboid_append(oid, (asn_subid_t) size) < 0) 1250 return (NULL); 1251 1252 for (i = 0, bits = 0; i < size; i++, bits += 8) 1253 if (snmp_suboid_append(oid, 1254 (asn_subid_t)((v & mask) >> bits)) < 0) 1255 return (NULL); 1256 1257 return (endptr); 1258 } 1259 1260 static int32_t 1261 parse_bits(struct snmp_value *value, char *string) 1262 { 1263 char *endptr; 1264 int i, size, bits, saved_errno; 1265 uint64_t v, mask = 0xFF00000000000000; 1266 1267 saved_errno = errno; 1268 errno = 0; 1269 1270 v = strtoull(string, &endptr, 16); 1271 1272 if (errno != 0) { 1273 warn("Bad BITS value %s", string); 1274 errno = saved_errno; 1275 return (-1); 1276 } 1277 1278 bits = 8; 1279 /* Determine length - up to 8 octets supported so far. */ 1280 for (size = sizeof(v); size > 0; size--) { 1281 if ((v & mask) != 0) 1282 break; 1283 mask = mask >> bits; 1284 } 1285 1286 if (size == 0) 1287 size = 1; 1288 1289 if ((value->v.octetstring.octets = malloc(size)) == NULL) { 1290 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 1291 return (-1); 1292 } 1293 1294 value->v.octetstring.len = size; 1295 for (i = 0, bits = 0; i < size; i++, bits += 8) 1296 value->v.octetstring.octets[i] = (v & mask) >> bits; 1297 value->syntax = SNMP_SYNTAX_OCTETSTRING; 1298 return (1); 1299 } 1300