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 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 < 0 || 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 < 0 || 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 < 0 || 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 value->v.octetstring.len = len; 270 271 if((value->v.octetstring.octets = malloc(len)) == NULL) { 272 syslog(LOG_ERR,"malloc failed: %s", strerror(errno)); 273 return (-1); 274 } 275 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 uint32_t v; 342 int32_t saved_errno; 343 344 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0) 345 return (NULL); 346 347 /* Read 'YYYY-' and write it in two subs. */ 348 ptr = str; 349 saved_errno = errno; 350 errno = 0; 351 v = strtoul(ptr, &endptr, 10); 352 if (v > 0xffff) 353 goto error; 354 else 355 errno = saved_errno; 356 if (*endptr != '-') 357 goto error1; 358 if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0) 359 return (NULL); 360 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0) 361 return (NULL); 362 363 /* 'MM-' */ 364 ptr = endptr + 1; 365 saved_errno = errno; 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 v = strtoul(ptr, &endptr, 10); 380 if (errno != 0) 381 goto error; 382 else 383 errno = saved_errno; 384 if (*endptr != '-') 385 goto error1; 386 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 387 return (NULL); 388 389 /* 'HH:' */ 390 ptr = endptr + 1; 391 saved_errno = errno; 392 v = strtoul(ptr, &endptr, 10); 393 if (errno != 0) 394 goto error; 395 else 396 errno = saved_errno; 397 if (*endptr != ':') 398 goto error1; 399 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 400 return (NULL); 401 402 /* 'MM:' */ 403 ptr = endptr + 1; 404 saved_errno = errno; 405 v = strtoul(ptr, &endptr, 10); 406 if (errno != 0) 407 goto error; 408 else 409 errno = saved_errno; 410 if (*endptr != ':') 411 goto error1; 412 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 413 return (NULL); 414 415 /* 'SS.' */ 416 ptr = endptr + 1; 417 saved_errno = errno; 418 v = strtoul(ptr, &endptr, 10); 419 if (errno != 0) 420 goto error; 421 else 422 errno = saved_errno; 423 if (*endptr != '.') 424 goto error1; 425 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 426 return (NULL); 427 428 /* 'M(mseconds),' */ 429 ptr = endptr + 1; 430 saved_errno = errno; 431 v = strtoul(ptr, &endptr, 10); 432 if (errno != 0) 433 goto error; 434 else 435 errno = saved_errno; 436 if (*endptr != ',') 437 goto error1; 438 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 439 return (NULL); 440 441 /* 'UTC' - optional */ 442 ptr = endptr + 1; 443 if (*ptr == 'U' && *(ptr + 1) == 'T' && *(ptr + 1) == 'C') 444 ptr += 3; 445 446 /* '+/-' */ 447 if (*ptr == '-' || *ptr == '+') { 448 if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0) 449 return (NULL); 450 } else 451 goto error1; 452 453 /* 'HH:' */ 454 ptr = endptr + 1; 455 saved_errno = errno; 456 v = strtoul(ptr, &endptr, 10); 457 if (errno != 0) 458 goto error; 459 else 460 errno = saved_errno; 461 if (*endptr != ':') 462 goto error1; 463 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 464 return (NULL); 465 466 /* 'MM' - last one - ignore endptr here. */ 467 ptr = endptr + 1; 468 saved_errno = errno; 469 v = strtoul(ptr, &endptr, 10); 470 if (errno != 0) 471 goto error; 472 else 473 errno = saved_errno; 474 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 475 return (NULL); 476 477 return (endptr); 478 479 error: 480 errno = saved_errno; 481 error1: 482 warnx("Date value %s not supported", str); 483 return (NULL); 484 } 485 486 /* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */ 487 static int32_t 488 parse_dateandtime(struct snmp_value *sv, char *val) 489 { 490 char *endptr; 491 uint32_t v; 492 uint8_t date[SNMP_DATETIME_OCTETS]; 493 494 /* 'YYYY-' */ 495 v = strtoul(val, &endptr, 10); 496 if (v > 0xffff || *endptr != '-') 497 goto error; 498 date[0] = ((v & 0xff00) >> 8); 499 date[1] = (v & 0xff); 500 val = endptr + 1; 501 502 /* 'MM-' */ 503 v = strtoul(val, &endptr, 10); 504 if (v == 0 || v > 12 || *endptr != '-') 505 goto error; 506 date[2] = v; 507 val = endptr + 1; 508 509 /* 'DD,' */ 510 v = strtoul(val, &endptr, 10); 511 if (v == 0 || v > 31 || *endptr != ',') 512 goto error; 513 date[3] = v; 514 val = endptr + 1; 515 516 /* 'HH:' */ 517 v = strtoul(val, &endptr, 10); 518 if (v > 23 || *endptr != ':') 519 goto error; 520 date[4] = v; 521 val = endptr + 1; 522 523 /* 'MM:' */ 524 v = strtoul(val, &endptr, 10); 525 if (v > 59 || *endptr != ':') 526 goto error; 527 date[5] = v; 528 val = endptr + 1; 529 530 /* 'SS.' */ 531 v = strtoul(val, &endptr, 10); 532 if (v > 60 || *endptr != '.') 533 goto error; 534 date[6] = v; 535 val = endptr + 1; 536 537 /* '(deci-)s,' */ 538 v = strtoul(val, &endptr, 10); 539 if (v > 9 || *endptr != ',') 540 goto error; 541 date[7] = v; 542 val = endptr + 1; 543 544 /* offset - '+/-' */ 545 if (*val != '-' && *val != '+') 546 goto error; 547 date[8] = (uint8_t) *val; 548 val = endptr + 1; 549 550 /* 'HH:' - offset from UTC */ 551 v = strtoul(val, &endptr, 10); 552 if (v > 13 || *endptr != ':') 553 goto error; 554 date[9] = v; 555 val = endptr + 1; 556 557 /* 'MM'\0'' offset from UTC */ 558 v = strtoul(val, &endptr, 10); 559 if (v > 59 || *endptr != '\0') 560 goto error; 561 date[10] = v; 562 563 if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) { 564 warnx("malloc() failed - %s", strerror(errno)); 565 return (-1); 566 } 567 568 sv->v.octetstring.len = SNMP_DATETIME_OCTETS; 569 memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS); 570 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 571 return (1); 572 573 error: 574 warnx("Date value %s not supported", val); 575 return (-1); 576 } 577 578 /************************************************************** 579 * PhysAddress 580 */ 581 static char * 582 snmp_oct2physAddr(uint32_t len, char *octets, char *buf) 583 { 584 char *ptr; 585 uint32_t i; 586 587 if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL) 588 return (NULL); 589 590 buf[0]= '\0'; 591 592 ptr = buf; 593 ptr += sprintf(ptr, "%2.2x", octets[0]); 594 for (i = 1; i < 6; i++) 595 ptr += sprintf(ptr, ":%2.2x", octets[i]); 596 597 return (buf); 598 } 599 600 static char * 601 snmp_addr2asn_oid(char *str, struct asn_oid *oid) 602 { 603 char *endptr, *ptr; 604 uint32_t v, i; 605 int saved_errno; 606 607 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0) 608 return (NULL); 609 610 ptr = str; 611 for (i = 0; i < 5; i++) { 612 saved_errno = errno; 613 v = strtoul(ptr, &endptr, 16); 614 errno = saved_errno; 615 if (v > 0xff) { 616 warnx("Integer value %s not supported", str); 617 return (NULL); 618 } 619 if (*endptr != ':') { 620 warnx("Failed adding oid - %s",str); 621 return (NULL); 622 } 623 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 624 return (NULL); 625 ptr = endptr + 1; 626 } 627 628 /* The last one - don't check the ending char here. */ 629 saved_errno = errno; 630 v = strtoul(ptr, &endptr, 16); 631 errno = saved_errno; 632 if (v > 0xff) { 633 warnx("Integer value %s not supported", str); 634 return (NULL); 635 } 636 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 637 return (NULL); 638 639 return (endptr); 640 } 641 642 static int32_t 643 parse_physaddress(struct snmp_value *sv, char *val) 644 { 645 char *endptr; 646 int32_t i; 647 uint32_t v; 648 uint8_t phys_addr[SNMP_PHYSADDR_OCTETS]; 649 650 for (i = 0; i < 5; i++) { 651 v = strtoul(val, &endptr, 16); 652 if (v > 0xff) { 653 warnx("Integer value %s not supported", val); 654 return (-1); 655 } 656 if(*endptr != ':') { 657 warnx("Failed reading octet - %s", val); 658 return (-1); 659 } 660 phys_addr[i] = v; 661 val = endptr + 1; 662 } 663 664 /* The last one - don't check the ending char here. */ 665 v = strtoul(val, &endptr, 16); 666 if (v > 0xff) { 667 warnx("Integer value %s not supported", val); 668 return (-1); 669 } 670 phys_addr[5] = v; 671 672 if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) { 673 syslog(LOG_ERR,"malloc failed: %s", strerror(errno)); 674 return (-1); 675 } 676 677 sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS; 678 memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS); 679 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 680 return (1); 681 } 682 683 /************************************************************** 684 * NTPTimeStamp 685 ************************************************************** 686 * NTP MIB, Revision 0.2, 7/25/97: 687 * NTPTimeStamp ::= TEXTUAL-CONVENTION 688 * DISPLAY-HINT "4x.4x" 689 * STATUS current 690 * DESCRIPTION 691 * "" 692 * SYNTAX OCTET STRING (SIZE(8)) 693 */ 694 static char * 695 snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf) 696 { 697 char *ptr; 698 uint32_t i; 699 700 if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL) 701 return (NULL); 702 703 buf[0]= '\0'; 704 705 ptr = buf; 706 i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3]; 707 ptr += sprintf(ptr, "%4.4d", i); 708 i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7]; 709 ptr += sprintf(ptr, ".%4.4d", i); 710 711 return (buf); 712 } 713 714 static char * 715 snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid) 716 { 717 char *endptr, *ptr; 718 uint32_t v, i, d; 719 struct asn_oid suboid; 720 int saved_errno; 721 722 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0) 723 return (NULL); 724 725 ptr = str; 726 saved_errno = errno; 727 v = strtoul(ptr, &endptr, 10); 728 if (errno != 0 || (v / 1000) > 9) { 729 warnx("Integer value %s not supported", str); 730 errno = saved_errno; 731 return (NULL); 732 } else 733 errno = saved_errno; 734 735 if (*endptr != '.') { 736 warnx("Failed adding oid - %s",str); 737 return (NULL); 738 } 739 740 memset(&suboid, 0, sizeof(struct asn_oid)); 741 suboid.len = SNMP_NTP_TS_OCTETS; 742 743 for (i = 0, d = 1000; i < 4; i++) { 744 suboid.subs[i] = v / d; 745 v = v % d; 746 d = d / 10; 747 } 748 749 ptr = endptr + 1; 750 saved_errno = errno; 751 v = strtoul(ptr, &endptr, 10); 752 if (errno != 0 || (v / 1000) > 9) { 753 warnx("Integer value %s not supported", str); 754 errno = saved_errno; 755 return (NULL); 756 } else 757 errno = saved_errno; 758 759 for (i = 0, d = 1000; i < 4; i++) { 760 suboid.subs[i + 4] = v / d; 761 v = v % d; 762 d = d / 10; 763 } 764 765 asn_append_oid(oid, &suboid); 766 return (endptr); 767 } 768 769 static int32_t 770 parse_ntp_ts(struct snmp_value *sv, char *val) 771 { 772 char *endptr; 773 int32_t i, d, saved_errno; 774 uint32_t v; 775 uint8_t ntp_ts[SNMP_NTP_TS_OCTETS]; 776 777 saved_errno = errno; 778 v = strtoul(val, &endptr, 10); 779 if (errno != 0 || (v / 1000) > 9) { 780 saved_errno = errno; 781 warnx("Integer value %s not supported", val); 782 return (-1); 783 } else 784 saved_errno = errno; 785 786 if (*endptr != '.') { 787 warnx("Failed reading octet - %s", val); 788 return (-1); 789 } 790 791 for (i = 0, d = 1000; i < 4; i++) { 792 ntp_ts[i] = v / d; 793 v = v % d; 794 d = d / 10; 795 } 796 val = endptr + 1; 797 798 saved_errno = errno; 799 v = strtoul(val, &endptr, 10); 800 if (errno != 0 || (v / 1000) > 9) { 801 saved_errno = errno; 802 warnx("Integer value %s not supported", val); 803 return (-1); 804 } else 805 saved_errno = errno; 806 807 for (i = 0, d = 1000; i < 4; i++) { 808 ntp_ts[i + 4] = v / d; 809 v = v % d; 810 d = d / 10; 811 } 812 813 if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) { 814 syslog(LOG_ERR,"malloc failed: %s", strerror(errno)); 815 return (-1); 816 } 817 818 sv->v.octetstring.len = SNMP_NTP_TS_OCTETS; 819 memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS); 820 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 821 return (1); 822 } 823 824 /************************************************************** 825 * BridgeId 826 ************************************************************** 827 * BRIDGE-MIB, REVISION "200509190000Z" 828 * BridgeId ::= TEXTUAL-CONVENTION 829 * STATUS current 830 * DESCRIPTION 831 * "The Bridge-Identifier, as used in the Spanning Tree 832 * Protocol, to uniquely identify a bridge. Its first two 833 * octets (in network byte order) contain a priority value, 834 * and its last 6 octets contain the MAC address used to 835 * refer to a bridge in a unique fashion (typically, the 836 * numerically smallest MAC address of all ports on the 837 * bridge)." 838 * SYNTAX OCTET STRING (SIZE (8)) 839 */ 840 static char * 841 snmp_oct2bridgeid(uint32_t len, char *octets, char *buf) 842 { 843 char *ptr; 844 uint32_t i, priority; 845 846 if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL) 847 return (NULL); 848 849 buf[0]= '\0'; 850 ptr = buf; 851 852 priority = octets[0] << 8; 853 priority += octets[1]; 854 if (priority > SNMP_MAX_BRIDGE_PRIORITY) { 855 warnx("Invalid bridge priority %d", priority); 856 return (NULL); 857 } else 858 ptr += sprintf(ptr, "%d.", octets[0]); 859 860 ptr += sprintf(ptr, "%2.2x", octets[2]); 861 862 for (i = 1; i < 6; i++) 863 ptr += sprintf(ptr, ":%2.2x", octets[i + 2]); 864 865 return (buf); 866 } 867 868 static char * 869 snmp_bridgeid2oct(char *str, struct asn_oid *oid) 870 { 871 char *endptr, *ptr; 872 uint32_t v, i; 873 int32_t saved_errno; 874 875 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0) 876 return (NULL); 877 878 ptr = str; 879 /* Read the priority. */ 880 saved_errno = errno; 881 v = strtoul(ptr, &endptr, 10); 882 errno = 0; 883 884 if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') { 885 errno = saved_errno; 886 warnx("Bad bridge priority value %d", v); 887 return (NULL); 888 } 889 890 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0) 891 return (NULL); 892 893 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0) 894 return (NULL); 895 896 ptr = endptr + 1; 897 for (i = 0; i < 5; i++) { 898 saved_errno = errno; 899 v = strtoul(ptr, &endptr, 16); 900 errno = saved_errno; 901 if (v > 0xff) { 902 warnx("Integer value %s not supported", str); 903 return (NULL); 904 } 905 if (*endptr != ':') { 906 warnx("Failed adding oid - %s",str); 907 return (NULL); 908 } 909 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 910 return (NULL); 911 ptr = endptr + 1; 912 } 913 914 /* The last one - don't check the ending char here. */ 915 saved_errno = errno; 916 v = strtoul(ptr, &endptr, 16); 917 errno = saved_errno; 918 if (v > 0xff) { 919 warnx("Integer value %s not supported", str); 920 return (NULL); 921 } 922 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 923 return (NULL); 924 925 return (endptr); 926 } 927 928 static int32_t 929 parse_bridge_id(struct snmp_value *sv, char *string) 930 { 931 char *ptr, *endptr; 932 int32_t i, saved_errno; 933 uint32_t v; 934 uint8_t bridge_id[SNMP_BRIDGEID_OCTETS]; 935 936 ptr = string; 937 /* Read the priority. */ 938 saved_errno = errno; 939 errno = 0; 940 v = strtoul(string, &endptr, 10); 941 errno = saved_errno; 942 943 if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') { 944 errno = saved_errno; 945 warnx("Bad bridge priority value %d", v); 946 return (-1); 947 } 948 949 bridge_id[0] = (v & 0xff00); 950 bridge_id[1] = (v & 0xff); 951 952 string = endptr + 1; 953 954 for (i = 0; i < 5; i++) { 955 v = strtoul(string, &endptr, 16); 956 if (v > 0xff) { 957 warnx("Integer value %s not supported", string); 958 return (-1); 959 } 960 if(*endptr != ':') { 961 warnx("Failed reading octet - %s", string); 962 return (-1); 963 } 964 bridge_id[i + 2] = v; 965 string = endptr + 1; 966 } 967 968 /* The last one - don't check the ending char here. */ 969 v = strtoul(string, &endptr, 16); 970 if (v > 0xff) { 971 warnx("Integer value %s not supported", string); 972 return (-1); 973 } 974 bridge_id[7] = v; 975 976 if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) { 977 syslog(LOG_ERR,"malloc failed: %s", strerror(errno)); 978 return (-1); 979 } 980 981 sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS; 982 memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS); 983 sv->syntax = SNMP_SYNTAX_OCTETSTRING; 984 return (1); 985 } 986 987 /************************************************************** 988 * BridgePortId 989 ************************************************************** 990 * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z" 991 * BridgePortId ::= TEXTUAL-CONVENTION 992 * DISPLAY-HINT "1x.1x" 993 * STATUS current 994 * DESCRIPTION 995 * "A port identifier that contains a bridge port's STP priority 996 * in the first octet and the port number in the second octet." 997 * SYNTAX OCTET STRING (SIZE(2)) 998 */ 999 static char * 1000 snmp_oct2bport_id(uint32_t len, char *octets, char *buf) 1001 { 1002 char *ptr; 1003 1004 if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL) 1005 return (NULL); 1006 1007 buf[0]= '\0'; 1008 ptr = buf; 1009 1010 ptr += sprintf(ptr, "%d.", octets[0]); 1011 ptr += sprintf(ptr, "%d", octets[1]); 1012 1013 return (buf); 1014 } 1015 1016 static char * 1017 snmp_bport_id2oct(char *str, struct asn_oid *oid) 1018 { 1019 char *endptr, *ptr; 1020 uint32_t v; 1021 int saved_errno; 1022 1023 if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0) 1024 return (NULL); 1025 1026 ptr = str; 1027 /* Read the priority. */ 1028 saved_errno = errno; 1029 v = strtoul(ptr, &endptr, 10); 1030 errno = 0; 1031 1032 if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') { 1033 errno = saved_errno; 1034 warnx("Bad bridge port priority value %d", v); 1035 return (NULL); 1036 } 1037 1038 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1039 return (NULL); 1040 1041 saved_errno = errno; 1042 v = strtoul(ptr, &endptr, 16); 1043 errno = saved_errno; 1044 1045 if (v > 0xff) { 1046 warnx("Bad port number - %d", v); 1047 return (NULL); 1048 } 1049 1050 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1051 return (NULL); 1052 1053 return (endptr); 1054 } 1055 1056 static int32_t 1057 parse_bport_id(struct snmp_value *value, char *string) 1058 { 1059 char *ptr, *endptr; 1060 int saved_errno; 1061 uint32_t v; 1062 uint8_t bport_id[SNMP_BPORT_OCTETS]; 1063 1064 ptr = string; 1065 /* Read the priority. */ 1066 saved_errno = errno; 1067 errno = 0; 1068 v = strtoul(string, &endptr, 10); 1069 errno = saved_errno; 1070 1071 if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') { 1072 errno = saved_errno; 1073 warnx("Bad bridge port priority value %d", v); 1074 return (-1); 1075 } 1076 1077 bport_id[0] = v; 1078 1079 string = endptr + 1; 1080 v = strtoul(string, &endptr, 16); 1081 if (v > 0xff) { 1082 warnx("Bad port number - %d", v); 1083 return (-1); 1084 } 1085 1086 bport_id[1] = v; 1087 1088 if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) { 1089 syslog(LOG_ERR,"malloc failed: %s", strerror(errno)); 1090 return (-1); 1091 } 1092 1093 value->v.octetstring.len = SNMP_BPORT_OCTETS; 1094 memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS); 1095 value->syntax = SNMP_SYNTAX_OCTETSTRING; 1096 return (1); 1097 } 1098 /************************************************************** 1099 * InetAddress 1100 ************************************************************** 1101 * INET-ADDRESS-MIB, REVISION "200502040000Z" 1102 * InetAddress ::= TEXTUAL-CONVENTION 1103 * STATUS current 1104 * DESCRIPTION 1105 * "Denotes a generic Internet address. 1106 * 1107 * An InetAddress value is always interpreted within the context 1108 * of an InetAddressType value. Every usage of the InetAddress 1109 * textual convention is required to specify the InetAddressType 1110 * object that provides the context. It is suggested that the 1111 * InetAddressType object be logically registered before the 1112 * object(s) that use the InetAddress textual convention, if 1113 * they appear in the same logical row. 1114 * 1115 * The value of an InetAddress object must always be 1116 * consistent with the value of the associated InetAddressType 1117 * object. Attempts to set an InetAddress object to a value 1118 * inconsistent with the associated InetAddressType 1119 * must fail with an inconsistentValue error. 1120 * 1121 * When this textual convention is used as the syntax of an 1122 * index object, there may be issues with the limit of 128 1123 * sub-identifiers specified in SMIv2, STD 58. In this case, 1124 * the object definition MUST include a 'SIZE' clause to 1125 * limit the number of potential instance sub-identifiers; 1126 * otherwise the applicable constraints MUST be stated in 1127 * the appropriate conceptual row DESCRIPTION clauses, or 1128 * in the surrounding documentation if there is no single 1129 * DESCRIPTION clause that is appropriate." 1130 * SYNTAX OCTET STRING (SIZE (0..255)) 1131 ************************************************************** 1132 * TODO: FIXME!!! syrinx: Since we do not support checking the 1133 * consistency of a varbinding based on the value of a previous 1134 * one, try to guess the type of address based on the 1135 * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently 1136 * not supported. 1137 */ 1138 static char * 1139 snmp_oct2inetaddr(uint32_t len, char *octets, char *buf) 1140 { 1141 int af; 1142 void *ip; 1143 struct in_addr ipv4; 1144 struct in6_addr ipv6; 1145 1146 if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL) 1147 return (NULL); 1148 1149 switch (len) { 1150 /* XXX: FIXME - IPv4*/ 1151 case 4: 1152 memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr)); 1153 af = AF_INET; 1154 ip = &ipv4; 1155 break; 1156 1157 /* XXX: FIXME - IPv4*/ 1158 case 16: 1159 memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr)); 1160 af = AF_INET6; 1161 ip = &ipv6; 1162 break; 1163 1164 default: 1165 return (NULL); 1166 } 1167 1168 if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) { 1169 warnx("inet_ntop failed - %s", strerror(errno)); 1170 return (NULL); 1171 } 1172 1173 return (buf); 1174 } 1175 1176 static char * 1177 snmp_inetaddr2oct(char *str, struct asn_oid *oid) 1178 { 1179 return (NULL); 1180 } 1181 1182 static int32_t 1183 parse_inetaddr(struct snmp_value *value, char *string) 1184 { 1185 return (-1); 1186 } 1187 1188 /************************************************************** 1189 * SNMP BITS type - XXX: FIXME 1190 **************************************************************/ 1191 static char * 1192 snmp_oct2bits(uint32_t len, char *octets, char *buf) 1193 { 1194 int i, bits; 1195 uint64_t value; 1196 1197 if (len > sizeof(value) || octets == NULL || buf == NULL) 1198 return (NULL); 1199 1200 for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8) 1201 value += octets[i] << bits; 1202 1203 buf[0]= '\0'; 1204 sprintf(buf, "0x%llx.",(long long unsigned) value); 1205 1206 return (buf); 1207 } 1208 1209 static char * 1210 snmp_bits2oct(char *str, struct asn_oid *oid) 1211 { 1212 char *endptr; 1213 int i, size, bits, saved_errno; 1214 uint64_t v, mask = 0xFF00000000000000; 1215 1216 saved_errno = errno; 1217 errno = 0; 1218 1219 v = strtoull(str, &endptr, 16); 1220 if (errno != 0) { 1221 warnx("Bad BITS value %s - %s", str, strerror(errno)); 1222 errno = saved_errno; 1223 return (NULL); 1224 } 1225 1226 bits = 8; 1227 /* Determine length - up to 8 octets supported so far. */ 1228 for (size = sizeof(v); size > 0; size--) { 1229 if ((v & mask) != 0) 1230 break; 1231 mask = mask >> bits; 1232 } 1233 1234 if (size == 0) 1235 size = 1; 1236 1237 if (snmp_suboid_append(oid, (asn_subid_t) size) < 0) 1238 return (NULL); 1239 1240 for (i = 0, bits = 0; i < size; i++, bits += 8) 1241 if (snmp_suboid_append(oid, 1242 (asn_subid_t)((v & mask) >> bits)) < 0) 1243 return (NULL); 1244 1245 return (endptr); 1246 } 1247 1248 static int32_t 1249 parse_bits(struct snmp_value *value, char *string) 1250 { 1251 char *endptr; 1252 int i, size, bits, saved_errno; 1253 uint64_t v, mask = 0xFF00000000000000; 1254 1255 saved_errno = errno; 1256 errno = 0; 1257 1258 v = strtoull(string, &endptr, 16); 1259 1260 if (errno != 0) { 1261 warnx("Bad BITS value %s - %s", string, strerror(errno)); 1262 errno = saved_errno; 1263 return (-1); 1264 } 1265 1266 bits = 8; 1267 /* Determine length - up to 8 octets supported so far. */ 1268 for (size = sizeof(v); size > 0; size--) { 1269 if ((v & mask) != 0) 1270 break; 1271 mask = mask >> bits; 1272 } 1273 1274 if (size == 0) 1275 size = 1; 1276 1277 if ((value->v.octetstring.octets = malloc(size)) == NULL) { 1278 syslog(LOG_ERR, "malloc failed: %s", strerror(errno)); 1279 return (-1); 1280 } 1281 1282 value->v.octetstring.len = size; 1283 for (i = 0, bits = 0; i < size; i++, bits += 8) 1284 value->v.octetstring.octets[i] = (v & mask) >> bits; 1285 value->syntax = SNMP_SYNTAX_OCTETSTRING; 1286 return (1); 1287 } 1288