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