1 /* 2 * SNMP functions for CUPS. 3 * 4 * Copyright 2007-2014 by Apple Inc. 5 * Copyright 2006-2007 by Easy Software Products, all rights reserved. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * "LICENSE" which should have been included with this file. If this 11 * file is missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers. 18 */ 19 20 #include "cups-private.h" 21 #include "snmp-private.h" 22 #ifdef HAVE_POLL 23 # include <poll.h> 24 #endif /* HAVE_POLL */ 25 26 27 /* 28 * Local functions... 29 */ 30 31 static void asn1_debug(const char *prefix, unsigned char *buffer, 32 size_t len, int indent); 33 static int asn1_decode_snmp(unsigned char *buffer, size_t len, 34 cups_snmp_t *packet); 35 static int asn1_encode_snmp(unsigned char *buffer, size_t len, 36 cups_snmp_t *packet); 37 static int asn1_get_integer(unsigned char **buffer, 38 unsigned char *bufend, 39 unsigned length); 40 static int asn1_get_oid(unsigned char **buffer, 41 unsigned char *bufend, 42 unsigned length, int *oid, int oidsize); 43 static int asn1_get_packed(unsigned char **buffer, 44 unsigned char *bufend); 45 static char *asn1_get_string(unsigned char **buffer, 46 unsigned char *bufend, 47 unsigned length, char *string, 48 size_t strsize); 49 static unsigned asn1_get_length(unsigned char **buffer, 50 unsigned char *bufend); 51 static int asn1_get_type(unsigned char **buffer, 52 unsigned char *bufend); 53 static void asn1_set_integer(unsigned char **buffer, 54 int integer); 55 static void asn1_set_length(unsigned char **buffer, 56 unsigned length); 57 static void asn1_set_oid(unsigned char **buffer, 58 const int *oid); 59 static void asn1_set_packed(unsigned char **buffer, 60 int integer); 61 static unsigned asn1_size_integer(int integer); 62 static unsigned asn1_size_length(unsigned length); 63 static unsigned asn1_size_oid(const int *oid); 64 static unsigned asn1_size_packed(int integer); 65 static void snmp_set_error(cups_snmp_t *packet, 66 const char *message); 67 68 69 /* 70 * '_cupsSNMPClose()' - Close a SNMP socket. 71 */ 72 73 void 74 _cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */ 75 { 76 DEBUG_printf(("4_cupsSNMPClose(fd=%d)", fd)); 77 78 httpAddrClose(NULL, fd); 79 } 80 81 82 /* 83 * '_cupsSNMPCopyOID()' - Copy an OID. 84 * 85 * The array pointed to by "src" is terminated by the value -1. 86 */ 87 88 int * /* O - New OID */ 89 _cupsSNMPCopyOID(int *dst, /* I - Destination OID */ 90 const int *src, /* I - Source OID */ 91 int dstsize) /* I - Number of integers in dst */ 92 { 93 int i; /* Looping var */ 94 95 96 DEBUG_printf(("4_cupsSNMPCopyOID(dst=%p, src=%p, dstsize=%d)", dst, src, 97 dstsize)); 98 99 for (i = 0, dstsize --; src[i] >= 0 && i < dstsize; i ++) 100 dst[i] = src[i]; 101 102 dst[i] = -1; 103 104 return (dst); 105 } 106 107 108 /* 109 * '_cupsSNMPDefaultCommunity()' - Get the default SNMP community name. 110 * 111 * The default community name is the first community name found in the 112 * snmp.conf file. If no community name is defined there, "public" is used. 113 */ 114 115 const char * /* O - Default community name */ 116 _cupsSNMPDefaultCommunity(void) 117 { 118 cups_file_t *fp; /* snmp.conf file */ 119 char line[1024], /* Line from file */ 120 *value; /* Value from file */ 121 int linenum; /* Line number in file */ 122 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 123 124 125 DEBUG_puts("4_cupsSNMPDefaultCommunity()"); 126 127 if (!cg->snmp_community[0]) 128 { 129 strlcpy(cg->snmp_community, "public", sizeof(cg->snmp_community)); 130 131 snprintf(line, sizeof(line), "%s/snmp.conf", cg->cups_serverroot); 132 if ((fp = cupsFileOpen(line, "r")) != NULL) 133 { 134 linenum = 0; 135 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) 136 if (!_cups_strcasecmp(line, "Community") && value) 137 { 138 strlcpy(cg->snmp_community, value, sizeof(cg->snmp_community)); 139 break; 140 } 141 142 cupsFileClose(fp); 143 } 144 } 145 146 DEBUG_printf(("5_cupsSNMPDefaultCommunity: Returning \"%s\"", 147 cg->snmp_community)); 148 149 return (cg->snmp_community); 150 } 151 152 153 /* 154 * '_cupsSNMPIsOID()' - Test whether a SNMP response contains the specified OID. 155 * 156 * The array pointed to by "oid" is terminated by the value -1. 157 */ 158 159 int /* O - 1 if equal, 0 if not equal */ 160 _cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */ 161 const int *oid) /* I - OID */ 162 { 163 int i; /* Looping var */ 164 165 166 /* 167 * Range check input... 168 */ 169 170 DEBUG_printf(("4_cupsSNMPIsOID(packet=%p, oid=%p)", packet, oid)); 171 172 if (!packet || !oid) 173 { 174 DEBUG_puts("5_cupsSNMPIsOID: Returning 0"); 175 176 return (0); 177 } 178 179 /* 180 * Compare OIDs... 181 */ 182 183 for (i = 0; 184 i < CUPS_SNMP_MAX_OID && oid[i] >= 0 && packet->object_name[i] >= 0; 185 i ++) 186 if (oid[i] != packet->object_name[i]) 187 { 188 DEBUG_puts("5_cupsSNMPIsOID: Returning 0"); 189 190 return (0); 191 } 192 193 DEBUG_printf(("5_cupsSNMPIsOID: Returning %d", 194 i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i])); 195 196 return (i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i]); 197 } 198 199 200 /* 201 * '_cupsSNMPIsOIDPrefixed()' - Test whether a SNMP response uses the specified 202 * OID prefix. 203 * 204 * The array pointed to by "prefix" is terminated by the value -1. 205 */ 206 207 int /* O - 1 if prefixed, 0 if not prefixed */ 208 _cupsSNMPIsOIDPrefixed( 209 cups_snmp_t *packet, /* I - Response packet */ 210 const int *prefix) /* I - OID prefix */ 211 { 212 int i; /* Looping var */ 213 214 215 /* 216 * Range check input... 217 */ 218 219 DEBUG_printf(("4_cupsSNMPIsOIDPrefixed(packet=%p, prefix=%p)", packet, 220 prefix)); 221 222 if (!packet || !prefix) 223 { 224 DEBUG_puts("5_cupsSNMPIsOIDPrefixed: Returning 0"); 225 226 return (0); 227 } 228 229 /* 230 * Compare OIDs... 231 */ 232 233 for (i = 0; 234 i < CUPS_SNMP_MAX_OID && prefix[i] >= 0 && packet->object_name[i] >= 0; 235 i ++) 236 if (prefix[i] != packet->object_name[i]) 237 { 238 DEBUG_puts("5_cupsSNMPIsOIDPrefixed: Returning 0"); 239 240 return (0); 241 } 242 243 DEBUG_printf(("5_cupsSNMPIsOIDPrefixed: Returning %d", 244 i < CUPS_SNMP_MAX_OID)); 245 246 return (i < CUPS_SNMP_MAX_OID); 247 } 248 249 250 /* 251 * '_cupsSNMPOIDToString()' - Convert an OID to a string. 252 */ 253 254 255 char * /* O - New string or @code NULL@ on error */ 256 _cupsSNMPOIDToString(const int *src, /* I - OID */ 257 char *dst, /* I - String buffer */ 258 size_t dstsize) /* I - Size of string buffer */ 259 { 260 char *dstptr, /* Pointer into string buffer */ 261 *dstend; /* End of string buffer */ 262 263 264 DEBUG_printf(("4_cupsSNMPOIDToString(src=%p, dst=%p, dstsize=" CUPS_LLFMT ")", 265 src, dst, CUPS_LLCAST dstsize)); 266 267 /* 268 * Range check input... 269 */ 270 271 if (!src || !dst || dstsize < 4) 272 return (NULL); 273 274 /* 275 * Loop through the OID array and build a string... 276 */ 277 278 for (dstptr = dst, dstend = dstptr + dstsize - 1; 279 *src >= 0 && dstptr < dstend; 280 src ++, dstptr += strlen(dstptr)) 281 snprintf(dstptr, (size_t)(dstend - dstptr + 1), ".%d", *src); 282 283 if (*src >= 0) 284 return (NULL); 285 else 286 return (dst); 287 } 288 289 290 /* 291 * '_cupsSNMPOpen()' - Open a SNMP socket. 292 */ 293 294 int /* O - SNMP socket file descriptor */ 295 _cupsSNMPOpen(int family) /* I - Address family - @code AF_INET@ or @code AF_INET6@ */ 296 { 297 int fd; /* SNMP socket file descriptor */ 298 int val; /* Socket option value */ 299 300 301 /* 302 * Create the SNMP socket... 303 */ 304 305 DEBUG_printf(("4_cupsSNMPOpen(family=%d)", family)); 306 307 if ((fd = socket(family, SOCK_DGRAM, 0)) < 0) 308 { 309 DEBUG_printf(("5_cupsSNMPOpen: Returning -1 (%s)", strerror(errno))); 310 311 return (-1); 312 } 313 314 /* 315 * Set the "broadcast" flag... 316 */ 317 318 val = 1; 319 320 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, CUPS_SOCAST &val, sizeof(val))) 321 { 322 DEBUG_printf(("5_cupsSNMPOpen: Returning -1 (%s)", strerror(errno))); 323 324 close(fd); 325 326 return (-1); 327 } 328 329 DEBUG_printf(("5_cupsSNMPOpen: Returning %d", fd)); 330 331 return (fd); 332 } 333 334 335 /* 336 * '_cupsSNMPRead()' - Read and parse a SNMP response. 337 * 338 * If "timeout" is negative, @code _cupsSNMPRead@ will wait for a response 339 * indefinitely. 340 */ 341 342 cups_snmp_t * /* O - SNMP packet or @code NULL@ if none */ 343 _cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */ 344 cups_snmp_t *packet, /* I - SNMP packet buffer */ 345 double timeout) /* I - Timeout in seconds */ 346 { 347 unsigned char buffer[CUPS_SNMP_MAX_PACKET]; 348 /* Data packet */ 349 ssize_t bytes; /* Number of bytes received */ 350 socklen_t addrlen; /* Source address length */ 351 http_addr_t address; /* Source address */ 352 353 354 /* 355 * Range check input... 356 */ 357 358 DEBUG_printf(("4_cupsSNMPRead(fd=%d, packet=%p, timeout=%.1f)", fd, packet, 359 timeout)); 360 361 if (fd < 0 || !packet) 362 { 363 DEBUG_puts("5_cupsSNMPRead: Returning NULL"); 364 365 return (NULL); 366 } 367 368 /* 369 * Optionally wait for a response... 370 */ 371 372 if (timeout >= 0.0) 373 { 374 int ready; /* Data ready on socket? */ 375 #ifdef HAVE_POLL 376 struct pollfd pfd; /* Polled file descriptor */ 377 378 pfd.fd = fd; 379 pfd.events = POLLIN; 380 381 while ((ready = poll(&pfd, 1, (int)(timeout * 1000.0))) < 0 && 382 (errno == EINTR || errno == EAGAIN)); 383 384 #else 385 fd_set input_set; /* select() input set */ 386 struct timeval stimeout; /* select() timeout */ 387 388 do 389 { 390 FD_ZERO(&input_set); 391 FD_SET(fd, &input_set); 392 393 stimeout.tv_sec = (int)timeout; 394 stimeout.tv_usec = (int)((timeout - stimeout.tv_sec) * 1000000); 395 396 ready = select(fd + 1, &input_set, NULL, NULL, &stimeout); 397 } 398 # ifdef WIN32 399 while (ready < 0 && WSAGetLastError() == WSAEINTR); 400 # else 401 while (ready < 0 && (errno == EINTR || errno == EAGAIN)); 402 # endif /* WIN32 */ 403 #endif /* HAVE_POLL */ 404 405 /* 406 * If we don't have any data ready, return right away... 407 */ 408 409 if (ready <= 0) 410 { 411 DEBUG_puts("5_cupsSNMPRead: Returning NULL (timeout)"); 412 413 return (NULL); 414 } 415 } 416 417 /* 418 * Read the response data... 419 */ 420 421 addrlen = sizeof(address); 422 423 if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (void *)&address, 424 &addrlen)) < 0) 425 { 426 DEBUG_printf(("5_cupsSNMPRead: Returning NULL (%s)", strerror(errno))); 427 428 return (NULL); 429 } 430 431 /* 432 * Look for the response status code in the SNMP message header... 433 */ 434 435 asn1_debug("DEBUG: IN ", buffer, (size_t)bytes, 0); 436 437 asn1_decode_snmp(buffer, (size_t)bytes, packet); 438 439 memcpy(&(packet->address), &address, sizeof(packet->address)); 440 441 /* 442 * Return decoded data packet... 443 */ 444 445 DEBUG_puts("5_cupsSNMPRead: Returning packet"); 446 447 return (packet); 448 } 449 450 451 /* 452 * '_cupsSNMPSetDebug()' - Enable/disable debug logging to stderr. 453 */ 454 455 void 456 _cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */ 457 { 458 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 459 460 461 DEBUG_printf(("4_cupsSNMPSetDebug(level=%d)", level)); 462 463 cg->snmp_debug = level; 464 } 465 466 467 /* 468 * '_cupsSNMPStringToOID()' - Convert a numeric OID string to an OID array. 469 * 470 * This function converts a string of the form ".N.N.N.N.N" to the 471 * corresponding OID array terminated by -1. 472 * 473 * @code NULL@ is returned if the array is not large enough or the string is 474 * not a valid OID number. 475 */ 476 477 int * /* O - Pointer to OID array or @code NULL@ on error */ 478 _cupsSNMPStringToOID(const char *src, /* I - OID string */ 479 int *dst, /* I - OID array */ 480 int dstsize)/* I - Number of integers in OID array */ 481 { 482 int *dstptr, /* Pointer into OID array */ 483 *dstend; /* End of OID array */ 484 485 486 DEBUG_printf(("4_cupsSNMPStringToOID(src=\"%s\", dst=%p, dstsize=%d)", 487 src, dst, dstsize)); 488 489 /* 490 * Range check input... 491 */ 492 493 if (!src || !dst || dstsize < 2) 494 return (NULL); 495 496 /* 497 * Skip leading "."... 498 */ 499 500 if (*src == '.') 501 src ++; 502 503 /* 504 * Loop to the end of the string... 505 */ 506 507 for (dstend = dst + dstsize - 1, dstptr = dst, *dstptr = 0; 508 *src && dstptr < dstend; 509 src ++) 510 { 511 if (*src == '.') 512 { 513 dstptr ++; 514 *dstptr = 0; 515 } 516 else if (isdigit(*src & 255)) 517 *dstptr = *dstptr * 10 + *src - '0'; 518 else 519 break; 520 } 521 522 if (*src) 523 return (NULL); 524 525 /* 526 * Terminate the end of the OID array and return... 527 */ 528 529 dstptr[1] = -1; 530 531 return (dst); 532 } 533 534 535 /* 536 * '_cupsSNMPWalk()' - Enumerate a group of OIDs. 537 * 538 * This function queries all of the OIDs with the specified OID prefix, 539 * calling the "cb" function for every response that is received. 540 * 541 * The array pointed to by "prefix" is terminated by the value -1. 542 * 543 * If "timeout" is negative, @code _cupsSNMPWalk@ will wait for a response 544 * indefinitely. 545 */ 546 547 int /* O - Number of OIDs found or -1 on error */ 548 _cupsSNMPWalk(int fd, /* I - SNMP socket */ 549 http_addr_t *address, /* I - Address to query */ 550 int version, /* I - SNMP version */ 551 const char *community,/* I - Community name */ 552 const int *prefix, /* I - OID prefix */ 553 double timeout, /* I - Timeout for each response in seconds */ 554 cups_snmp_cb_t cb, /* I - Function to call for each response */ 555 void *data) /* I - User data pointer that is passed to the callback function */ 556 { 557 int count = 0; /* Number of OIDs found */ 558 unsigned request_id = 0; /* Current request ID */ 559 cups_snmp_t packet; /* Current response packet */ 560 int lastoid[CUPS_SNMP_MAX_OID]; 561 /* Last OID we got */ 562 563 564 /* 565 * Range check input... 566 */ 567 568 DEBUG_printf(("4_cupsSNMPWalk(fd=%d, address=%p, version=%d, " 569 "community=\"%s\", prefix=%p, timeout=%.1f, cb=%p, data=%p)", 570 fd, address, version, community, prefix, timeout, cb, data)); 571 572 if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community || 573 !prefix || !cb) 574 { 575 DEBUG_puts("5_cupsSNMPWalk: Returning -1"); 576 577 return (-1); 578 } 579 580 /* 581 * Copy the OID prefix and then loop until we have no more OIDs... 582 */ 583 584 _cupsSNMPCopyOID(packet.object_name, prefix, CUPS_SNMP_MAX_OID); 585 lastoid[0] = -1; 586 587 for (;;) 588 { 589 request_id ++; 590 591 if (!_cupsSNMPWrite(fd, address, version, community, 592 CUPS_ASN1_GET_NEXT_REQUEST, request_id, 593 packet.object_name)) 594 { 595 DEBUG_puts("5_cupsSNMPWalk: Returning -1"); 596 597 return (-1); 598 } 599 600 if (!_cupsSNMPRead(fd, &packet, timeout)) 601 { 602 DEBUG_puts("5_cupsSNMPWalk: Returning -1"); 603 604 return (-1); 605 } 606 607 if (!_cupsSNMPIsOIDPrefixed(&packet, prefix) || 608 _cupsSNMPIsOID(&packet, lastoid)) 609 { 610 DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count)); 611 612 return (count); 613 } 614 615 if (packet.error || packet.error_status) 616 { 617 DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count > 0 ? count : -1)); 618 619 return (count > 0 ? count : -1); 620 } 621 622 _cupsSNMPCopyOID(lastoid, packet.object_name, CUPS_SNMP_MAX_OID); 623 624 count ++; 625 626 (*cb)(&packet, data); 627 } 628 } 629 630 631 /* 632 * '_cupsSNMPWrite()' - Send an SNMP query packet. 633 * 634 * The array pointed to by "oid" is terminated by the value -1. 635 */ 636 637 int /* O - 1 on success, 0 on error */ 638 _cupsSNMPWrite( 639 int fd, /* I - SNMP socket */ 640 http_addr_t *address, /* I - Address to send to */ 641 int version, /* I - SNMP version */ 642 const char *community, /* I - Community name */ 643 cups_asn1_t request_type, /* I - Request type */ 644 const unsigned request_id, /* I - Request ID */ 645 const int *oid) /* I - OID */ 646 { 647 int i; /* Looping var */ 648 cups_snmp_t packet; /* SNMP message packet */ 649 unsigned char buffer[CUPS_SNMP_MAX_PACKET]; 650 /* SNMP message buffer */ 651 ssize_t bytes; /* Size of message */ 652 http_addr_t temp; /* Copy of address */ 653 654 655 /* 656 * Range check input... 657 */ 658 659 DEBUG_printf(("4_cupsSNMPWrite(fd=%d, address=%p, version=%d, " 660 "community=\"%s\", request_type=%d, request_id=%u, oid=%p)", 661 fd, address, version, community, request_type, request_id, oid)); 662 663 if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community || 664 (request_type != CUPS_ASN1_GET_REQUEST && 665 request_type != CUPS_ASN1_GET_NEXT_REQUEST) || request_id < 1 || !oid) 666 { 667 DEBUG_puts("5_cupsSNMPWrite: Returning 0 (bad arguments)"); 668 669 return (0); 670 } 671 672 /* 673 * Create the SNMP message... 674 */ 675 676 memset(&packet, 0, sizeof(packet)); 677 678 packet.version = version; 679 packet.request_type = request_type; 680 packet.request_id = request_id; 681 packet.object_type = CUPS_ASN1_NULL_VALUE; 682 683 strlcpy(packet.community, community, sizeof(packet.community)); 684 685 for (i = 0; oid[i] >= 0 && i < (CUPS_SNMP_MAX_OID - 1); i ++) 686 packet.object_name[i] = oid[i]; 687 packet.object_name[i] = -1; 688 689 if (oid[i] >= 0) 690 { 691 DEBUG_puts("5_cupsSNMPWrite: Returning 0 (OID too big)"); 692 693 errno = E2BIG; 694 return (0); 695 } 696 697 bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet); 698 699 if (bytes < 0) 700 { 701 DEBUG_puts("5_cupsSNMPWrite: Returning 0 (request too big)"); 702 703 errno = E2BIG; 704 return (0); 705 } 706 707 asn1_debug("DEBUG: OUT ", buffer, (size_t)bytes, 0); 708 709 /* 710 * Send the message... 711 */ 712 713 temp = *address; 714 715 _httpAddrSetPort(&temp, CUPS_SNMP_PORT); 716 717 return (sendto(fd, buffer, (size_t)bytes, 0, (void *)&temp, (socklen_t)httpAddrLength(&temp)) == bytes); 718 } 719 720 721 /* 722 * 'asn1_debug()' - Decode an ASN1-encoded message. 723 */ 724 725 static void 726 asn1_debug(const char *prefix, /* I - Prefix string */ 727 unsigned char *buffer, /* I - Buffer */ 728 size_t len, /* I - Length of buffer */ 729 int indent) /* I - Indentation */ 730 { 731 size_t i; /* Looping var */ 732 unsigned char *bufend; /* End of buffer */ 733 int integer; /* Number value */ 734 int oid[CUPS_SNMP_MAX_OID]; /* OID value */ 735 char string[CUPS_SNMP_MAX_STRING]; 736 /* String value */ 737 unsigned char value_type; /* Type of value */ 738 unsigned value_length; /* Length of value */ 739 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 740 741 742 if (cg->snmp_debug <= 0) 743 return; 744 745 if (cg->snmp_debug > 1 && indent == 0) 746 { 747 /* 748 * Do a hex dump of the packet... 749 */ 750 751 size_t j; 752 753 fprintf(stderr, "%sHex Dump (%d bytes):\n", prefix, (int)len); 754 755 for (i = 0; i < len; i += 16) 756 { 757 fprintf(stderr, "%s%04x:", prefix, (unsigned)i); 758 759 for (j = 0; j < 16 && (i + j) < len; j ++) 760 { 761 if (j && !(j & 3)) 762 fprintf(stderr, " %02x", buffer[i + j]); 763 else 764 fprintf(stderr, " %02x", buffer[i + j]); 765 } 766 767 while (j < 16) 768 { 769 if (j && !(j & 3)) 770 fputs(" ", stderr); 771 else 772 fputs(" ", stderr); 773 774 j ++; 775 } 776 777 fputs(" ", stderr); 778 779 for (j = 0; j < 16 && (i + j) < len; j ++) 780 if (buffer[i + j] < ' ' || buffer[i + j] >= 0x7f) 781 putc('.', stderr); 782 else 783 putc(buffer[i + j], stderr); 784 785 putc('\n', stderr); 786 } 787 } 788 789 if (indent == 0) 790 fprintf(stderr, "%sMessage:\n", prefix); 791 792 bufend = buffer + len; 793 794 while (buffer < bufend) 795 { 796 /* 797 * Get value type... 798 */ 799 800 value_type = (unsigned char)asn1_get_type(&buffer, bufend); 801 value_length = asn1_get_length(&buffer, bufend); 802 803 switch (value_type) 804 { 805 case CUPS_ASN1_BOOLEAN : 806 integer = asn1_get_integer(&buffer, bufend, value_length); 807 808 fprintf(stderr, "%s%*sBOOLEAN %d bytes %d\n", prefix, indent, "", 809 value_length, integer); 810 break; 811 812 case CUPS_ASN1_INTEGER : 813 integer = asn1_get_integer(&buffer, bufend, value_length); 814 815 fprintf(stderr, "%s%*sINTEGER %d bytes %d\n", prefix, indent, "", 816 value_length, integer); 817 break; 818 819 case CUPS_ASN1_COUNTER : 820 integer = asn1_get_integer(&buffer, bufend, value_length); 821 822 fprintf(stderr, "%s%*sCOUNTER %d bytes %u\n", prefix, indent, "", 823 value_length, (unsigned)integer); 824 break; 825 826 case CUPS_ASN1_GAUGE : 827 integer = asn1_get_integer(&buffer, bufend, value_length); 828 829 fprintf(stderr, "%s%*sGAUGE %d bytes %u\n", prefix, indent, "", 830 value_length, (unsigned)integer); 831 break; 832 833 case CUPS_ASN1_TIMETICKS : 834 integer = asn1_get_integer(&buffer, bufend, value_length); 835 836 fprintf(stderr, "%s%*sTIMETICKS %d bytes %u\n", prefix, indent, "", 837 value_length, (unsigned)integer); 838 break; 839 840 case CUPS_ASN1_OCTET_STRING : 841 fprintf(stderr, "%s%*sOCTET STRING %d bytes \"%s\"\n", prefix, 842 indent, "", value_length, 843 asn1_get_string(&buffer, bufend, value_length, string, 844 sizeof(string))); 845 break; 846 847 case CUPS_ASN1_HEX_STRING : 848 asn1_get_string(&buffer, bufend, value_length, string, 849 sizeof(string)); 850 fprintf(stderr, "%s%*sHex-STRING %d bytes", prefix, 851 indent, "", value_length); 852 for (i = 0; i < value_length; i ++) 853 fprintf(stderr, " %02X", string[i] & 255); 854 putc('\n', stderr); 855 break; 856 857 case CUPS_ASN1_NULL_VALUE : 858 fprintf(stderr, "%s%*sNULL VALUE %d bytes\n", prefix, indent, "", 859 value_length); 860 861 buffer += value_length; 862 break; 863 864 case CUPS_ASN1_OID : 865 integer = asn1_get_oid(&buffer, bufend, value_length, oid, 866 CUPS_SNMP_MAX_OID); 867 868 fprintf(stderr, "%s%*sOID %d bytes ", prefix, indent, "", 869 value_length); 870 for (i = 0; i < (unsigned)integer; i ++) 871 fprintf(stderr, ".%d", oid[i]); 872 putc('\n', stderr); 873 break; 874 875 case CUPS_ASN1_SEQUENCE : 876 fprintf(stderr, "%s%*sSEQUENCE %d bytes\n", prefix, indent, "", 877 value_length); 878 asn1_debug(prefix, buffer, value_length, indent + 4); 879 880 buffer += value_length; 881 break; 882 883 case CUPS_ASN1_GET_NEXT_REQUEST : 884 fprintf(stderr, "%s%*sGet-Next-Request-PDU %d bytes\n", prefix, 885 indent, "", value_length); 886 asn1_debug(prefix, buffer, value_length, indent + 4); 887 888 buffer += value_length; 889 break; 890 891 case CUPS_ASN1_GET_REQUEST : 892 fprintf(stderr, "%s%*sGet-Request-PDU %d bytes\n", prefix, indent, "", 893 value_length); 894 asn1_debug(prefix, buffer, value_length, indent + 4); 895 896 buffer += value_length; 897 break; 898 899 case CUPS_ASN1_GET_RESPONSE : 900 fprintf(stderr, "%s%*sGet-Response-PDU %d bytes\n", prefix, indent, 901 "", value_length); 902 asn1_debug(prefix, buffer, value_length, indent + 4); 903 904 buffer += value_length; 905 break; 906 907 default : 908 fprintf(stderr, "%s%*sUNKNOWN(%x) %d bytes\n", prefix, indent, "", 909 value_type, value_length); 910 911 buffer += value_length; 912 break; 913 } 914 } 915 } 916 917 918 /* 919 * 'asn1_decode_snmp()' - Decode a SNMP packet. 920 */ 921 922 static int /* O - 0 on success, -1 on error */ 923 asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */ 924 size_t len, /* I - Size of buffer */ 925 cups_snmp_t *packet) /* I - SNMP packet */ 926 { 927 unsigned char *bufptr, /* Pointer into the data */ 928 *bufend; /* End of data */ 929 unsigned length; /* Length of value */ 930 931 932 /* 933 * Initialize the decoding... 934 */ 935 936 memset(packet, 0, sizeof(cups_snmp_t)); 937 packet->object_name[0] = -1; 938 939 bufptr = buffer; 940 bufend = buffer + len; 941 942 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE) 943 snmp_set_error(packet, _("Packet does not start with SEQUENCE")); 944 else if (asn1_get_length(&bufptr, bufend) == 0) 945 snmp_set_error(packet, _("SEQUENCE uses indefinite length")); 946 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 947 snmp_set_error(packet, _("No version number")); 948 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 949 snmp_set_error(packet, _("Version uses indefinite length")); 950 else if ((packet->version = asn1_get_integer(&bufptr, bufend, length)) 951 != CUPS_SNMP_VERSION_1) 952 snmp_set_error(packet, _("Bad SNMP version number")); 953 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OCTET_STRING) 954 snmp_set_error(packet, _("No community name")); 955 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 956 snmp_set_error(packet, _("Community name uses indefinite length")); 957 else 958 { 959 asn1_get_string(&bufptr, bufend, length, packet->community, 960 sizeof(packet->community)); 961 962 if ((packet->request_type = (cups_asn1_t)asn1_get_type(&bufptr, bufend)) 963 != CUPS_ASN1_GET_RESPONSE) 964 snmp_set_error(packet, _("Packet does not contain a Get-Response-PDU")); 965 else if (asn1_get_length(&bufptr, bufend) == 0) 966 snmp_set_error(packet, _("Get-Response-PDU uses indefinite length")); 967 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 968 snmp_set_error(packet, _("No request-id")); 969 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 970 snmp_set_error(packet, _("request-id uses indefinite length")); 971 else 972 { 973 packet->request_id = (unsigned)asn1_get_integer(&bufptr, bufend, length); 974 975 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 976 snmp_set_error(packet, _("No error-status")); 977 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 978 snmp_set_error(packet, _("error-status uses indefinite length")); 979 else 980 { 981 packet->error_status = asn1_get_integer(&bufptr, bufend, length); 982 983 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 984 snmp_set_error(packet, _("No error-index")); 985 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 986 snmp_set_error(packet, _("error-index uses indefinite length")); 987 else 988 { 989 packet->error_index = asn1_get_integer(&bufptr, bufend, length); 990 991 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE) 992 snmp_set_error(packet, _("No variable-bindings SEQUENCE")); 993 else if (asn1_get_length(&bufptr, bufend) == 0) 994 snmp_set_error(packet, 995 _("variable-bindings uses indefinite length")); 996 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE) 997 snmp_set_error(packet, _("No VarBind SEQUENCE")); 998 else if (asn1_get_length(&bufptr, bufend) == 0) 999 snmp_set_error(packet, _("VarBind uses indefinite length")); 1000 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OID) 1001 snmp_set_error(packet, _("No name OID")); 1002 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 1003 snmp_set_error(packet, _("Name OID uses indefinite length")); 1004 else 1005 { 1006 asn1_get_oid(&bufptr, bufend, length, packet->object_name, 1007 CUPS_SNMP_MAX_OID); 1008 1009 packet->object_type = (cups_asn1_t)asn1_get_type(&bufptr, bufend); 1010 1011 if ((length = asn1_get_length(&bufptr, bufend)) == 0 && 1012 packet->object_type != CUPS_ASN1_NULL_VALUE && 1013 packet->object_type != CUPS_ASN1_OCTET_STRING) 1014 snmp_set_error(packet, _("Value uses indefinite length")); 1015 else 1016 { 1017 switch (packet->object_type) 1018 { 1019 case CUPS_ASN1_BOOLEAN : 1020 packet->object_value.boolean = 1021 asn1_get_integer(&bufptr, bufend, length); 1022 break; 1023 1024 case CUPS_ASN1_INTEGER : 1025 packet->object_value.integer = 1026 asn1_get_integer(&bufptr, bufend, length); 1027 break; 1028 1029 case CUPS_ASN1_NULL_VALUE : 1030 break; 1031 1032 case CUPS_ASN1_OCTET_STRING : 1033 case CUPS_ASN1_BIT_STRING : 1034 case CUPS_ASN1_HEX_STRING : 1035 packet->object_value.string.num_bytes = length; 1036 asn1_get_string(&bufptr, bufend, length, 1037 (char *)packet->object_value.string.bytes, 1038 sizeof(packet->object_value.string.bytes)); 1039 break; 1040 1041 case CUPS_ASN1_OID : 1042 asn1_get_oid(&bufptr, bufend, length, 1043 packet->object_value.oid, CUPS_SNMP_MAX_OID); 1044 break; 1045 1046 case CUPS_ASN1_COUNTER : 1047 packet->object_value.counter = 1048 asn1_get_integer(&bufptr, bufend, length); 1049 break; 1050 1051 case CUPS_ASN1_GAUGE : 1052 packet->object_value.gauge = 1053 (unsigned)asn1_get_integer(&bufptr, bufend, length); 1054 break; 1055 1056 case CUPS_ASN1_TIMETICKS : 1057 packet->object_value.timeticks = 1058 (unsigned)asn1_get_integer(&bufptr, bufend, length); 1059 break; 1060 1061 default : 1062 snmp_set_error(packet, _("Unsupported value type")); 1063 break; 1064 } 1065 } 1066 } 1067 } 1068 } 1069 } 1070 } 1071 1072 return (packet->error ? -1 : 0); 1073 } 1074 1075 1076 /* 1077 * 'asn1_encode_snmp()' - Encode a SNMP packet. 1078 */ 1079 1080 static int /* O - Length on success, -1 on error */ 1081 asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */ 1082 size_t bufsize, /* I - Size of buffer */ 1083 cups_snmp_t *packet) /* I - SNMP packet */ 1084 { 1085 unsigned char *bufptr; /* Pointer into buffer */ 1086 unsigned total, /* Total length */ 1087 msglen, /* Length of entire message */ 1088 commlen, /* Length of community string */ 1089 reqlen, /* Length of request */ 1090 listlen, /* Length of variable list */ 1091 varlen, /* Length of variable */ 1092 namelen, /* Length of object name OID */ 1093 valuelen; /* Length of object value */ 1094 1095 1096 /* 1097 * Get the lengths of the community string, OID, and message... 1098 */ 1099 1100 1101 namelen = asn1_size_oid(packet->object_name); 1102 1103 switch (packet->object_type) 1104 { 1105 case CUPS_ASN1_NULL_VALUE : 1106 valuelen = 0; 1107 break; 1108 1109 case CUPS_ASN1_BOOLEAN : 1110 valuelen = asn1_size_integer(packet->object_value.boolean); 1111 break; 1112 1113 case CUPS_ASN1_INTEGER : 1114 valuelen = asn1_size_integer(packet->object_value.integer); 1115 break; 1116 1117 case CUPS_ASN1_OCTET_STRING : 1118 valuelen = packet->object_value.string.num_bytes; 1119 break; 1120 1121 case CUPS_ASN1_OID : 1122 valuelen = asn1_size_oid(packet->object_value.oid); 1123 break; 1124 1125 default : 1126 packet->error = "Unknown object type"; 1127 return (-1); 1128 } 1129 1130 varlen = 1 + asn1_size_length(namelen) + namelen + 1131 1 + asn1_size_length(valuelen) + valuelen; 1132 listlen = 1 + asn1_size_length(varlen) + varlen; 1133 reqlen = 2 + asn1_size_integer((int)packet->request_id) + 1134 2 + asn1_size_integer(packet->error_status) + 1135 2 + asn1_size_integer(packet->error_index) + 1136 1 + asn1_size_length(listlen) + listlen; 1137 commlen = (unsigned)strlen(packet->community); 1138 msglen = 2 + asn1_size_integer(packet->version) + 1139 1 + asn1_size_length(commlen) + commlen + 1140 1 + asn1_size_length(reqlen) + reqlen; 1141 total = 1 + asn1_size_length(msglen) + msglen; 1142 1143 if (total > bufsize) 1144 { 1145 packet->error = "Message too large for buffer"; 1146 return (-1); 1147 } 1148 1149 /* 1150 * Then format the message... 1151 */ 1152 1153 bufptr = buffer; 1154 1155 *bufptr++ = CUPS_ASN1_SEQUENCE; /* SNMPv1 message header */ 1156 asn1_set_length(&bufptr, msglen); 1157 1158 asn1_set_integer(&bufptr, packet->version); 1159 /* version */ 1160 1161 *bufptr++ = CUPS_ASN1_OCTET_STRING; /* community */ 1162 asn1_set_length(&bufptr, commlen); 1163 memcpy(bufptr, packet->community, commlen); 1164 bufptr += commlen; 1165 1166 *bufptr++ = packet->request_type; /* Get-Request-PDU/Get-Next-Request-PDU */ 1167 asn1_set_length(&bufptr, reqlen); 1168 1169 asn1_set_integer(&bufptr, (int)packet->request_id); 1170 1171 asn1_set_integer(&bufptr, packet->error_status); 1172 1173 asn1_set_integer(&bufptr, packet->error_index); 1174 1175 *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable-bindings */ 1176 asn1_set_length(&bufptr, listlen); 1177 1178 *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable */ 1179 asn1_set_length(&bufptr, varlen); 1180 1181 asn1_set_oid(&bufptr, packet->object_name); 1182 /* ObjectName */ 1183 1184 switch (packet->object_type) 1185 { 1186 case CUPS_ASN1_NULL_VALUE : 1187 *bufptr++ = CUPS_ASN1_NULL_VALUE; 1188 /* ObjectValue */ 1189 *bufptr++ = 0; /* Length */ 1190 break; 1191 1192 case CUPS_ASN1_BOOLEAN : 1193 asn1_set_integer(&bufptr, packet->object_value.boolean); 1194 break; 1195 1196 case CUPS_ASN1_INTEGER : 1197 asn1_set_integer(&bufptr, packet->object_value.integer); 1198 break; 1199 1200 case CUPS_ASN1_OCTET_STRING : 1201 *bufptr++ = CUPS_ASN1_OCTET_STRING; 1202 asn1_set_length(&bufptr, valuelen); 1203 memcpy(bufptr, packet->object_value.string.bytes, valuelen); 1204 bufptr += valuelen; 1205 break; 1206 1207 case CUPS_ASN1_OID : 1208 asn1_set_oid(&bufptr, packet->object_value.oid); 1209 break; 1210 1211 default : 1212 break; 1213 } 1214 1215 return ((int)(bufptr - buffer)); 1216 } 1217 1218 1219 /* 1220 * 'asn1_get_integer()' - Get an integer value. 1221 */ 1222 1223 static int /* O - Integer value */ 1224 asn1_get_integer( 1225 unsigned char **buffer, /* IO - Pointer in buffer */ 1226 unsigned char *bufend, /* I - End of buffer */ 1227 unsigned length) /* I - Length of value */ 1228 { 1229 int value; /* Integer value */ 1230 1231 1232 if (length > sizeof(int)) 1233 { 1234 (*buffer) += length; 1235 return (0); 1236 } 1237 1238 for (value = (**buffer & 0x80) ? -1 : 0; 1239 length > 0 && *buffer < bufend; 1240 length --, (*buffer) ++) 1241 value = (value << 8) | **buffer; 1242 1243 return (value); 1244 } 1245 1246 1247 /* 1248 * 'asn1_get_length()' - Get a value length. 1249 */ 1250 1251 static unsigned /* O - Length */ 1252 asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */ 1253 unsigned char *bufend) /* I - End of buffer */ 1254 { 1255 unsigned length; /* Length */ 1256 1257 1258 length = **buffer; 1259 (*buffer) ++; 1260 1261 if (length & 128) 1262 { 1263 int count; /* Number of bytes for length */ 1264 1265 1266 if ((count = length & 127) > sizeof(unsigned)) 1267 { 1268 (*buffer) += count; 1269 return (0); 1270 } 1271 1272 for (length = 0; 1273 count > 0 && *buffer < bufend; 1274 count --, (*buffer) ++) 1275 length = (length << 8) | **buffer; 1276 } 1277 1278 return (length); 1279 } 1280 1281 1282 /* 1283 * 'asn1_get_oid()' - Get an OID value. 1284 */ 1285 1286 static int /* O - Number of OIDs */ 1287 asn1_get_oid( 1288 unsigned char **buffer, /* IO - Pointer in buffer */ 1289 unsigned char *bufend, /* I - End of buffer */ 1290 unsigned length, /* I - Length of value */ 1291 int *oid, /* I - OID buffer */ 1292 int oidsize) /* I - Size of OID buffer */ 1293 { 1294 unsigned char *valend; /* End of value */ 1295 int *oidptr, /* Current OID */ 1296 *oidend; /* End of OID buffer */ 1297 int number; /* OID number */ 1298 1299 1300 valend = *buffer + length; 1301 oidptr = oid; 1302 oidend = oid + oidsize - 1; 1303 1304 if (valend > bufend) 1305 valend = bufend; 1306 1307 number = asn1_get_packed(buffer, bufend); 1308 1309 if (number < 80) 1310 { 1311 *oidptr++ = number / 40; 1312 number = number % 40; 1313 *oidptr++ = number; 1314 } 1315 else 1316 { 1317 *oidptr++ = 2; 1318 number -= 80; 1319 *oidptr++ = number; 1320 } 1321 1322 while (*buffer < valend) 1323 { 1324 number = asn1_get_packed(buffer, bufend); 1325 1326 if (oidptr < oidend) 1327 *oidptr++ = number; 1328 } 1329 1330 *oidptr = -1; 1331 1332 return ((int)(oidptr - oid)); 1333 } 1334 1335 1336 /* 1337 * 'asn1_get_packed()' - Get a packed integer value. 1338 */ 1339 1340 static int /* O - Value */ 1341 asn1_get_packed( 1342 unsigned char **buffer, /* IO - Pointer in buffer */ 1343 unsigned char *bufend) /* I - End of buffer */ 1344 { 1345 int value; /* Value */ 1346 1347 1348 value = 0; 1349 1350 while ((**buffer & 128) && *buffer < bufend) 1351 { 1352 value = (value << 7) | (**buffer & 127); 1353 (*buffer) ++; 1354 } 1355 1356 if (*buffer < bufend) 1357 { 1358 value = (value << 7) | **buffer; 1359 (*buffer) ++; 1360 } 1361 1362 return (value); 1363 } 1364 1365 1366 /* 1367 * 'asn1_get_string()' - Get a string value. 1368 */ 1369 1370 static char * /* O - String */ 1371 asn1_get_string( 1372 unsigned char **buffer, /* IO - Pointer in buffer */ 1373 unsigned char *bufend, /* I - End of buffer */ 1374 unsigned length, /* I - Value length */ 1375 char *string, /* I - String buffer */ 1376 size_t strsize) /* I - String buffer size */ 1377 { 1378 if (length > (unsigned)(bufend - *buffer)) 1379 length = (unsigned)(bufend - *buffer); 1380 1381 if (length < strsize) 1382 { 1383 /* 1384 * String is smaller than the buffer... 1385 */ 1386 1387 if (length > 0) 1388 memcpy(string, *buffer, length); 1389 1390 string[length] = '\0'; 1391 } 1392 else 1393 { 1394 /* 1395 * String is larger than the buffer... 1396 */ 1397 1398 memcpy(string, *buffer, strsize - 1); 1399 string[strsize - 1] = '\0'; 1400 } 1401 1402 if (length > 0) 1403 (*buffer) += length; 1404 1405 return (string); 1406 } 1407 1408 1409 /* 1410 * 'asn1_get_type()' - Get a value type. 1411 */ 1412 1413 static int /* O - Type */ 1414 asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */ 1415 unsigned char *bufend) /* I - End of buffer */ 1416 { 1417 int type; /* Type */ 1418 1419 1420 type = **buffer; 1421 (*buffer) ++; 1422 1423 if ((type & 31) == 31) 1424 type = asn1_get_packed(buffer, bufend); 1425 1426 return (type); 1427 } 1428 1429 1430 /* 1431 * 'asn1_set_integer()' - Set an integer value. 1432 */ 1433 1434 static void 1435 asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */ 1436 int integer) /* I - Integer value */ 1437 { 1438 **buffer = CUPS_ASN1_INTEGER; 1439 (*buffer) ++; 1440 1441 if (integer > 0x7fffff || integer < -0x800000) 1442 { 1443 **buffer = 4; 1444 (*buffer) ++; 1445 **buffer = (unsigned char)(integer >> 24); 1446 (*buffer) ++; 1447 **buffer = (unsigned char)(integer >> 16); 1448 (*buffer) ++; 1449 **buffer = (unsigned char)(integer >> 8); 1450 (*buffer) ++; 1451 **buffer = (unsigned char)integer; 1452 (*buffer) ++; 1453 } 1454 else if (integer > 0x7fff || integer < -0x8000) 1455 { 1456 **buffer = 3; 1457 (*buffer) ++; 1458 **buffer = (unsigned char)(integer >> 16); 1459 (*buffer) ++; 1460 **buffer = (unsigned char)(integer >> 8); 1461 (*buffer) ++; 1462 **buffer = (unsigned char)integer; 1463 (*buffer) ++; 1464 } 1465 else if (integer > 0x7f || integer < -0x80) 1466 { 1467 **buffer = 2; 1468 (*buffer) ++; 1469 **buffer = (unsigned char)(integer >> 8); 1470 (*buffer) ++; 1471 **buffer = (unsigned char)integer; 1472 (*buffer) ++; 1473 } 1474 else 1475 { 1476 **buffer = 1; 1477 (*buffer) ++; 1478 **buffer = (unsigned char)integer; 1479 (*buffer) ++; 1480 } 1481 } 1482 1483 1484 /* 1485 * 'asn1_set_length()' - Set a value length. 1486 */ 1487 1488 static void 1489 asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */ 1490 unsigned length) /* I - Length value */ 1491 { 1492 if (length > 255) 1493 { 1494 **buffer = 0x82; /* 2-byte length */ 1495 (*buffer) ++; 1496 **buffer = (unsigned char)(length >> 8); 1497 (*buffer) ++; 1498 **buffer = (unsigned char)length; 1499 (*buffer) ++; 1500 } 1501 else if (length > 127) 1502 { 1503 **buffer = 0x81; /* 1-byte length */ 1504 (*buffer) ++; 1505 **buffer = (unsigned char)length; 1506 (*buffer) ++; 1507 } 1508 else 1509 { 1510 **buffer = (unsigned char)length; /* Length */ 1511 (*buffer) ++; 1512 } 1513 } 1514 1515 1516 /* 1517 * 'asn1_set_oid()' - Set an OID value. 1518 */ 1519 1520 static void 1521 asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */ 1522 const int *oid) /* I - OID value */ 1523 { 1524 **buffer = CUPS_ASN1_OID; 1525 (*buffer) ++; 1526 1527 asn1_set_length(buffer, asn1_size_oid(oid)); 1528 1529 if (oid[1] < 0) 1530 { 1531 asn1_set_packed(buffer, oid[0] * 40); 1532 return; 1533 } 1534 1535 asn1_set_packed(buffer, oid[0] * 40 + oid[1]); 1536 1537 for (oid += 2; *oid >= 0; oid ++) 1538 asn1_set_packed(buffer, *oid); 1539 } 1540 1541 1542 /* 1543 * 'asn1_set_packed()' - Set a packed integer value. 1544 */ 1545 1546 static void 1547 asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */ 1548 int integer) /* I - Integer value */ 1549 { 1550 if (integer > 0xfffffff) 1551 { 1552 **buffer = ((integer >> 28) & 0x7f) | 0x80; 1553 (*buffer) ++; 1554 } 1555 1556 if (integer > 0x1fffff) 1557 { 1558 **buffer = ((integer >> 21) & 0x7f) | 0x80; 1559 (*buffer) ++; 1560 } 1561 1562 if (integer > 0x3fff) 1563 { 1564 **buffer = ((integer >> 14) & 0x7f) | 0x80; 1565 (*buffer) ++; 1566 } 1567 1568 if (integer > 0x7f) 1569 { 1570 **buffer = ((integer >> 7) & 0x7f) | 0x80; 1571 (*buffer) ++; 1572 } 1573 1574 **buffer = integer & 0x7f; 1575 (*buffer) ++; 1576 } 1577 1578 1579 /* 1580 * 'asn1_size_integer()' - Figure out the number of bytes needed for an 1581 * integer value. 1582 */ 1583 1584 static unsigned /* O - Size in bytes */ 1585 asn1_size_integer(int integer) /* I - Integer value */ 1586 { 1587 if (integer > 0x7fffff || integer < -0x800000) 1588 return (4); 1589 else if (integer > 0x7fff || integer < -0x8000) 1590 return (3); 1591 else if (integer > 0x7f || integer < -0x80) 1592 return (2); 1593 else 1594 return (1); 1595 } 1596 1597 1598 /* 1599 * 'asn1_size_length()' - Figure out the number of bytes needed for a 1600 * length value. 1601 */ 1602 1603 static unsigned /* O - Size in bytes */ 1604 asn1_size_length(unsigned length) /* I - Length value */ 1605 { 1606 if (length > 0xff) 1607 return (3); 1608 else if (length > 0x7f) 1609 return (2); 1610 else 1611 return (1); 1612 } 1613 1614 1615 /* 1616 * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an 1617 * OID value. 1618 */ 1619 1620 static unsigned /* O - Size in bytes */ 1621 asn1_size_oid(const int *oid) /* I - OID value */ 1622 { 1623 unsigned length; /* Length of value */ 1624 1625 1626 if (oid[1] < 0) 1627 return (asn1_size_packed(oid[0] * 40)); 1628 1629 for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2; 1630 *oid >= 0; 1631 oid ++) 1632 length += asn1_size_packed(*oid); 1633 1634 return (length); 1635 } 1636 1637 1638 /* 1639 * 'asn1_size_packed()' - Figure out the number of bytes needed for a 1640 * packed integer value. 1641 */ 1642 1643 static unsigned /* O - Size in bytes */ 1644 asn1_size_packed(int integer) /* I - Integer value */ 1645 { 1646 if (integer > 0xfffffff) 1647 return (5); 1648 else if (integer > 0x1fffff) 1649 return (4); 1650 else if (integer > 0x3fff) 1651 return (3); 1652 else if (integer > 0x7f) 1653 return (2); 1654 else 1655 return (1); 1656 } 1657 1658 1659 /* 1660 * 'snmp_set_error()' - Set the localized error for a packet. 1661 */ 1662 1663 static void 1664 snmp_set_error(cups_snmp_t *packet, /* I - Packet */ 1665 const char *message) /* I - Error message */ 1666 { 1667 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 1668 1669 1670 if (!cg->lang_default) 1671 cg->lang_default = cupsLangDefault(); 1672 1673 packet->error = _cupsLangString(cg->lang_default, message); 1674 } 1675