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 #ifdef __clang_analyzer__ /* Suppress bogus clang error */ 743 memset(string, 0, sizeof(string)); 744 #endif /* __clang_analyzer__ */ 745 746 if (cg->snmp_debug <= 0) 747 return; 748 749 if (cg->snmp_debug > 1 && indent == 0) 750 { 751 /* 752 * Do a hex dump of the packet... 753 */ 754 755 size_t j; 756 757 fprintf(stderr, "%sHex Dump (%d bytes):\n", prefix, (int)len); 758 759 for (i = 0; i < len; i += 16) 760 { 761 fprintf(stderr, "%s%04x:", prefix, (unsigned)i); 762 763 for (j = 0; j < 16 && (i + j) < len; j ++) 764 { 765 if (j && !(j & 3)) 766 fprintf(stderr, " %02x", buffer[i + j]); 767 else 768 fprintf(stderr, " %02x", buffer[i + j]); 769 } 770 771 while (j < 16) 772 { 773 if (j && !(j & 3)) 774 fputs(" ", stderr); 775 else 776 fputs(" ", stderr); 777 778 j ++; 779 } 780 781 fputs(" ", stderr); 782 783 for (j = 0; j < 16 && (i + j) < len; j ++) 784 if (buffer[i + j] < ' ' || buffer[i + j] >= 0x7f) 785 putc('.', stderr); 786 else 787 putc(buffer[i + j], stderr); 788 789 putc('\n', stderr); 790 } 791 } 792 793 if (indent == 0) 794 fprintf(stderr, "%sMessage:\n", prefix); 795 796 bufend = buffer + len; 797 798 while (buffer < bufend) 799 { 800 /* 801 * Get value type... 802 */ 803 804 value_type = (unsigned char)asn1_get_type(&buffer, bufend); 805 value_length = asn1_get_length(&buffer, bufend); 806 807 switch (value_type) 808 { 809 case CUPS_ASN1_BOOLEAN : 810 integer = asn1_get_integer(&buffer, bufend, value_length); 811 812 fprintf(stderr, "%s%*sBOOLEAN %d bytes %d\n", prefix, indent, "", 813 value_length, integer); 814 break; 815 816 case CUPS_ASN1_INTEGER : 817 integer = asn1_get_integer(&buffer, bufend, value_length); 818 819 fprintf(stderr, "%s%*sINTEGER %d bytes %d\n", prefix, indent, "", 820 value_length, integer); 821 break; 822 823 case CUPS_ASN1_COUNTER : 824 integer = asn1_get_integer(&buffer, bufend, value_length); 825 826 fprintf(stderr, "%s%*sCOUNTER %d bytes %u\n", prefix, indent, "", 827 value_length, (unsigned)integer); 828 break; 829 830 case CUPS_ASN1_GAUGE : 831 integer = asn1_get_integer(&buffer, bufend, value_length); 832 833 fprintf(stderr, "%s%*sGAUGE %d bytes %u\n", prefix, indent, "", 834 value_length, (unsigned)integer); 835 break; 836 837 case CUPS_ASN1_TIMETICKS : 838 integer = asn1_get_integer(&buffer, bufend, value_length); 839 840 fprintf(stderr, "%s%*sTIMETICKS %d bytes %u\n", prefix, indent, "", 841 value_length, (unsigned)integer); 842 break; 843 844 case CUPS_ASN1_OCTET_STRING : 845 fprintf(stderr, "%s%*sOCTET STRING %d bytes \"%s\"\n", prefix, 846 indent, "", value_length, 847 asn1_get_string(&buffer, bufend, value_length, string, 848 sizeof(string))); 849 break; 850 851 case CUPS_ASN1_HEX_STRING : 852 asn1_get_string(&buffer, bufend, value_length, string, 853 sizeof(string)); 854 fprintf(stderr, "%s%*sHex-STRING %d bytes", prefix, 855 indent, "", value_length); 856 for (i = 0; i < value_length; i ++) 857 fprintf(stderr, " %02X", string[i] & 255); 858 putc('\n', stderr); 859 break; 860 861 case CUPS_ASN1_NULL_VALUE : 862 fprintf(stderr, "%s%*sNULL VALUE %d bytes\n", prefix, indent, "", 863 value_length); 864 865 buffer += value_length; 866 break; 867 868 case CUPS_ASN1_OID : 869 integer = asn1_get_oid(&buffer, bufend, value_length, oid, 870 CUPS_SNMP_MAX_OID); 871 872 fprintf(stderr, "%s%*sOID %d bytes ", prefix, indent, "", 873 value_length); 874 for (i = 0; i < (unsigned)integer; i ++) 875 fprintf(stderr, ".%d", oid[i]); 876 putc('\n', stderr); 877 break; 878 879 case CUPS_ASN1_SEQUENCE : 880 fprintf(stderr, "%s%*sSEQUENCE %d bytes\n", prefix, indent, "", 881 value_length); 882 asn1_debug(prefix, buffer, value_length, indent + 4); 883 884 buffer += value_length; 885 break; 886 887 case CUPS_ASN1_GET_NEXT_REQUEST : 888 fprintf(stderr, "%s%*sGet-Next-Request-PDU %d bytes\n", prefix, 889 indent, "", value_length); 890 asn1_debug(prefix, buffer, value_length, indent + 4); 891 892 buffer += value_length; 893 break; 894 895 case CUPS_ASN1_GET_REQUEST : 896 fprintf(stderr, "%s%*sGet-Request-PDU %d bytes\n", prefix, indent, "", 897 value_length); 898 asn1_debug(prefix, buffer, value_length, indent + 4); 899 900 buffer += value_length; 901 break; 902 903 case CUPS_ASN1_GET_RESPONSE : 904 fprintf(stderr, "%s%*sGet-Response-PDU %d bytes\n", prefix, indent, 905 "", value_length); 906 asn1_debug(prefix, buffer, value_length, indent + 4); 907 908 buffer += value_length; 909 break; 910 911 default : 912 fprintf(stderr, "%s%*sUNKNOWN(%x) %d bytes\n", prefix, indent, "", 913 value_type, value_length); 914 915 buffer += value_length; 916 break; 917 } 918 } 919 } 920 921 922 /* 923 * 'asn1_decode_snmp()' - Decode a SNMP packet. 924 */ 925 926 static int /* O - 0 on success, -1 on error */ 927 asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */ 928 size_t len, /* I - Size of buffer */ 929 cups_snmp_t *packet) /* I - SNMP packet */ 930 { 931 unsigned char *bufptr, /* Pointer into the data */ 932 *bufend; /* End of data */ 933 unsigned length; /* Length of value */ 934 935 936 /* 937 * Initialize the decoding... 938 */ 939 940 memset(packet, 0, sizeof(cups_snmp_t)); 941 packet->object_name[0] = -1; 942 943 bufptr = buffer; 944 bufend = buffer + len; 945 946 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE) 947 snmp_set_error(packet, _("Packet does not start with SEQUENCE")); 948 else if (asn1_get_length(&bufptr, bufend) == 0) 949 snmp_set_error(packet, _("SEQUENCE uses indefinite length")); 950 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 951 snmp_set_error(packet, _("No version number")); 952 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 953 snmp_set_error(packet, _("Version uses indefinite length")); 954 else if ((packet->version = asn1_get_integer(&bufptr, bufend, length)) 955 != CUPS_SNMP_VERSION_1) 956 snmp_set_error(packet, _("Bad SNMP version number")); 957 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OCTET_STRING) 958 snmp_set_error(packet, _("No community name")); 959 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 960 snmp_set_error(packet, _("Community name uses indefinite length")); 961 else 962 { 963 asn1_get_string(&bufptr, bufend, length, packet->community, 964 sizeof(packet->community)); 965 966 if ((packet->request_type = (cups_asn1_t)asn1_get_type(&bufptr, bufend)) 967 != CUPS_ASN1_GET_RESPONSE) 968 snmp_set_error(packet, _("Packet does not contain a Get-Response-PDU")); 969 else if (asn1_get_length(&bufptr, bufend) == 0) 970 snmp_set_error(packet, _("Get-Response-PDU uses indefinite length")); 971 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 972 snmp_set_error(packet, _("No request-id")); 973 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 974 snmp_set_error(packet, _("request-id uses indefinite length")); 975 else 976 { 977 packet->request_id = (unsigned)asn1_get_integer(&bufptr, bufend, length); 978 979 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 980 snmp_set_error(packet, _("No error-status")); 981 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 982 snmp_set_error(packet, _("error-status uses indefinite length")); 983 else 984 { 985 packet->error_status = asn1_get_integer(&bufptr, bufend, length); 986 987 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER) 988 snmp_set_error(packet, _("No error-index")); 989 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 990 snmp_set_error(packet, _("error-index uses indefinite length")); 991 else 992 { 993 packet->error_index = asn1_get_integer(&bufptr, bufend, length); 994 995 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE) 996 snmp_set_error(packet, _("No variable-bindings SEQUENCE")); 997 else if (asn1_get_length(&bufptr, bufend) == 0) 998 snmp_set_error(packet, 999 _("variable-bindings uses indefinite length")); 1000 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE) 1001 snmp_set_error(packet, _("No VarBind SEQUENCE")); 1002 else if (asn1_get_length(&bufptr, bufend) == 0) 1003 snmp_set_error(packet, _("VarBind uses indefinite length")); 1004 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OID) 1005 snmp_set_error(packet, _("No name OID")); 1006 else if ((length = asn1_get_length(&bufptr, bufend)) == 0) 1007 snmp_set_error(packet, _("Name OID uses indefinite length")); 1008 else 1009 { 1010 asn1_get_oid(&bufptr, bufend, length, packet->object_name, 1011 CUPS_SNMP_MAX_OID); 1012 1013 packet->object_type = (cups_asn1_t)asn1_get_type(&bufptr, bufend); 1014 1015 if ((length = asn1_get_length(&bufptr, bufend)) == 0 && 1016 packet->object_type != CUPS_ASN1_NULL_VALUE && 1017 packet->object_type != CUPS_ASN1_OCTET_STRING) 1018 snmp_set_error(packet, _("Value uses indefinite length")); 1019 else 1020 { 1021 switch (packet->object_type) 1022 { 1023 case CUPS_ASN1_BOOLEAN : 1024 packet->object_value.boolean = 1025 asn1_get_integer(&bufptr, bufend, length); 1026 break; 1027 1028 case CUPS_ASN1_INTEGER : 1029 packet->object_value.integer = 1030 asn1_get_integer(&bufptr, bufend, length); 1031 break; 1032 1033 case CUPS_ASN1_NULL_VALUE : 1034 break; 1035 1036 case CUPS_ASN1_OCTET_STRING : 1037 case CUPS_ASN1_BIT_STRING : 1038 case CUPS_ASN1_HEX_STRING : 1039 packet->object_value.string.num_bytes = length; 1040 asn1_get_string(&bufptr, bufend, length, 1041 (char *)packet->object_value.string.bytes, 1042 sizeof(packet->object_value.string.bytes)); 1043 break; 1044 1045 case CUPS_ASN1_OID : 1046 asn1_get_oid(&bufptr, bufend, length, 1047 packet->object_value.oid, CUPS_SNMP_MAX_OID); 1048 break; 1049 1050 case CUPS_ASN1_COUNTER : 1051 packet->object_value.counter = 1052 asn1_get_integer(&bufptr, bufend, length); 1053 break; 1054 1055 case CUPS_ASN1_GAUGE : 1056 packet->object_value.gauge = 1057 (unsigned)asn1_get_integer(&bufptr, bufend, length); 1058 break; 1059 1060 case CUPS_ASN1_TIMETICKS : 1061 packet->object_value.timeticks = 1062 (unsigned)asn1_get_integer(&bufptr, bufend, length); 1063 break; 1064 1065 default : 1066 snmp_set_error(packet, _("Unsupported value type")); 1067 break; 1068 } 1069 } 1070 } 1071 } 1072 } 1073 } 1074 } 1075 1076 return (packet->error ? -1 : 0); 1077 } 1078 1079 1080 /* 1081 * 'asn1_encode_snmp()' - Encode a SNMP packet. 1082 */ 1083 1084 static int /* O - Length on success, -1 on error */ 1085 asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */ 1086 size_t bufsize, /* I - Size of buffer */ 1087 cups_snmp_t *packet) /* I - SNMP packet */ 1088 { 1089 unsigned char *bufptr; /* Pointer into buffer */ 1090 unsigned total, /* Total length */ 1091 msglen, /* Length of entire message */ 1092 commlen, /* Length of community string */ 1093 reqlen, /* Length of request */ 1094 listlen, /* Length of variable list */ 1095 varlen, /* Length of variable */ 1096 namelen, /* Length of object name OID */ 1097 valuelen; /* Length of object value */ 1098 1099 1100 /* 1101 * Get the lengths of the community string, OID, and message... 1102 */ 1103 1104 1105 namelen = asn1_size_oid(packet->object_name); 1106 1107 switch (packet->object_type) 1108 { 1109 case CUPS_ASN1_NULL_VALUE : 1110 valuelen = 0; 1111 break; 1112 1113 case CUPS_ASN1_BOOLEAN : 1114 valuelen = asn1_size_integer(packet->object_value.boolean); 1115 break; 1116 1117 case CUPS_ASN1_INTEGER : 1118 valuelen = asn1_size_integer(packet->object_value.integer); 1119 break; 1120 1121 case CUPS_ASN1_OCTET_STRING : 1122 valuelen = packet->object_value.string.num_bytes; 1123 break; 1124 1125 case CUPS_ASN1_OID : 1126 valuelen = asn1_size_oid(packet->object_value.oid); 1127 break; 1128 1129 default : 1130 packet->error = "Unknown object type"; 1131 return (-1); 1132 } 1133 1134 varlen = 1 + asn1_size_length(namelen) + namelen + 1135 1 + asn1_size_length(valuelen) + valuelen; 1136 listlen = 1 + asn1_size_length(varlen) + varlen; 1137 reqlen = 2 + asn1_size_integer((int)packet->request_id) + 1138 2 + asn1_size_integer(packet->error_status) + 1139 2 + asn1_size_integer(packet->error_index) + 1140 1 + asn1_size_length(listlen) + listlen; 1141 commlen = (unsigned)strlen(packet->community); 1142 msglen = 2 + asn1_size_integer(packet->version) + 1143 1 + asn1_size_length(commlen) + commlen + 1144 1 + asn1_size_length(reqlen) + reqlen; 1145 total = 1 + asn1_size_length(msglen) + msglen; 1146 1147 if (total > bufsize) 1148 { 1149 packet->error = "Message too large for buffer"; 1150 return (-1); 1151 } 1152 1153 /* 1154 * Then format the message... 1155 */ 1156 1157 bufptr = buffer; 1158 1159 *bufptr++ = CUPS_ASN1_SEQUENCE; /* SNMPv1 message header */ 1160 asn1_set_length(&bufptr, msglen); 1161 1162 asn1_set_integer(&bufptr, packet->version); 1163 /* version */ 1164 1165 *bufptr++ = CUPS_ASN1_OCTET_STRING; /* community */ 1166 asn1_set_length(&bufptr, commlen); 1167 memcpy(bufptr, packet->community, commlen); 1168 bufptr += commlen; 1169 1170 *bufptr++ = packet->request_type; /* Get-Request-PDU/Get-Next-Request-PDU */ 1171 asn1_set_length(&bufptr, reqlen); 1172 1173 asn1_set_integer(&bufptr, (int)packet->request_id); 1174 1175 asn1_set_integer(&bufptr, packet->error_status); 1176 1177 asn1_set_integer(&bufptr, packet->error_index); 1178 1179 *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable-bindings */ 1180 asn1_set_length(&bufptr, listlen); 1181 1182 *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable */ 1183 asn1_set_length(&bufptr, varlen); 1184 1185 asn1_set_oid(&bufptr, packet->object_name); 1186 /* ObjectName */ 1187 1188 switch (packet->object_type) 1189 { 1190 case CUPS_ASN1_NULL_VALUE : 1191 *bufptr++ = CUPS_ASN1_NULL_VALUE; 1192 /* ObjectValue */ 1193 *bufptr++ = 0; /* Length */ 1194 break; 1195 1196 case CUPS_ASN1_BOOLEAN : 1197 asn1_set_integer(&bufptr, packet->object_value.boolean); 1198 break; 1199 1200 case CUPS_ASN1_INTEGER : 1201 asn1_set_integer(&bufptr, packet->object_value.integer); 1202 break; 1203 1204 case CUPS_ASN1_OCTET_STRING : 1205 *bufptr++ = CUPS_ASN1_OCTET_STRING; 1206 asn1_set_length(&bufptr, valuelen); 1207 memcpy(bufptr, packet->object_value.string.bytes, valuelen); 1208 bufptr += valuelen; 1209 break; 1210 1211 case CUPS_ASN1_OID : 1212 asn1_set_oid(&bufptr, packet->object_value.oid); 1213 break; 1214 1215 default : 1216 break; 1217 } 1218 1219 return ((int)(bufptr - buffer)); 1220 } 1221 1222 1223 /* 1224 * 'asn1_get_integer()' - Get an integer value. 1225 */ 1226 1227 static int /* O - Integer value */ 1228 asn1_get_integer( 1229 unsigned char **buffer, /* IO - Pointer in buffer */ 1230 unsigned char *bufend, /* I - End of buffer */ 1231 unsigned length) /* I - Length of value */ 1232 { 1233 int value; /* Integer value */ 1234 1235 1236 if (length > sizeof(int)) 1237 { 1238 (*buffer) += length; 1239 return (0); 1240 } 1241 1242 for (value = (**buffer & 0x80) ? -1 : 0; 1243 length > 0 && *buffer < bufend; 1244 length --, (*buffer) ++) 1245 value = (value << 8) | **buffer; 1246 1247 return (value); 1248 } 1249 1250 1251 /* 1252 * 'asn1_get_length()' - Get a value length. 1253 */ 1254 1255 static unsigned /* O - Length */ 1256 asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */ 1257 unsigned char *bufend) /* I - End of buffer */ 1258 { 1259 unsigned length; /* Length */ 1260 1261 1262 length = **buffer; 1263 (*buffer) ++; 1264 1265 if (length & 128) 1266 { 1267 int count; /* Number of bytes for length */ 1268 1269 1270 if ((count = length & 127) > sizeof(unsigned)) 1271 { 1272 (*buffer) += count; 1273 return (0); 1274 } 1275 1276 for (length = 0; 1277 count > 0 && *buffer < bufend; 1278 count --, (*buffer) ++) 1279 length = (length << 8) | **buffer; 1280 } 1281 1282 return (length); 1283 } 1284 1285 1286 /* 1287 * 'asn1_get_oid()' - Get an OID value. 1288 */ 1289 1290 static int /* O - Number of OIDs */ 1291 asn1_get_oid( 1292 unsigned char **buffer, /* IO - Pointer in buffer */ 1293 unsigned char *bufend, /* I - End of buffer */ 1294 unsigned length, /* I - Length of value */ 1295 int *oid, /* I - OID buffer */ 1296 int oidsize) /* I - Size of OID buffer */ 1297 { 1298 unsigned char *valend; /* End of value */ 1299 int *oidptr, /* Current OID */ 1300 *oidend; /* End of OID buffer */ 1301 int number; /* OID number */ 1302 1303 1304 valend = *buffer + length; 1305 oidptr = oid; 1306 oidend = oid + oidsize - 1; 1307 1308 if (valend > bufend) 1309 valend = bufend; 1310 1311 number = asn1_get_packed(buffer, bufend); 1312 1313 if (number < 80) 1314 { 1315 *oidptr++ = number / 40; 1316 number = number % 40; 1317 *oidptr++ = number; 1318 } 1319 else 1320 { 1321 *oidptr++ = 2; 1322 number -= 80; 1323 *oidptr++ = number; 1324 } 1325 1326 while (*buffer < valend) 1327 { 1328 number = asn1_get_packed(buffer, bufend); 1329 1330 if (oidptr < oidend) 1331 *oidptr++ = number; 1332 } 1333 1334 *oidptr = -1; 1335 1336 return ((int)(oidptr - oid)); 1337 } 1338 1339 1340 /* 1341 * 'asn1_get_packed()' - Get a packed integer value. 1342 */ 1343 1344 static int /* O - Value */ 1345 asn1_get_packed( 1346 unsigned char **buffer, /* IO - Pointer in buffer */ 1347 unsigned char *bufend) /* I - End of buffer */ 1348 { 1349 int value; /* Value */ 1350 1351 1352 value = 0; 1353 1354 while ((**buffer & 128) && *buffer < bufend) 1355 { 1356 value = (value << 7) | (**buffer & 127); 1357 (*buffer) ++; 1358 } 1359 1360 if (*buffer < bufend) 1361 { 1362 value = (value << 7) | **buffer; 1363 (*buffer) ++; 1364 } 1365 1366 return (value); 1367 } 1368 1369 1370 /* 1371 * 'asn1_get_string()' - Get a string value. 1372 */ 1373 1374 static char * /* O - String */ 1375 asn1_get_string( 1376 unsigned char **buffer, /* IO - Pointer in buffer */ 1377 unsigned char *bufend, /* I - End of buffer */ 1378 unsigned length, /* I - Value length */ 1379 char *string, /* I - String buffer */ 1380 size_t strsize) /* I - String buffer size */ 1381 { 1382 if (length > (unsigned)(bufend - *buffer)) 1383 length = (unsigned)(bufend - *buffer); 1384 1385 if (length < strsize) 1386 { 1387 /* 1388 * String is smaller than the buffer... 1389 */ 1390 1391 if (length > 0) 1392 memcpy(string, *buffer, length); 1393 1394 string[length] = '\0'; 1395 } 1396 else 1397 { 1398 /* 1399 * String is larger than the buffer... 1400 */ 1401 1402 memcpy(string, *buffer, strsize - 1); 1403 string[strsize - 1] = '\0'; 1404 } 1405 1406 if (length > 0) 1407 (*buffer) += length; 1408 1409 return (string); 1410 } 1411 1412 1413 /* 1414 * 'asn1_get_type()' - Get a value type. 1415 */ 1416 1417 static int /* O - Type */ 1418 asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */ 1419 unsigned char *bufend) /* I - End of buffer */ 1420 { 1421 int type; /* Type */ 1422 1423 1424 type = **buffer; 1425 (*buffer) ++; 1426 1427 if ((type & 31) == 31) 1428 type = asn1_get_packed(buffer, bufend); 1429 1430 return (type); 1431 } 1432 1433 1434 /* 1435 * 'asn1_set_integer()' - Set an integer value. 1436 */ 1437 1438 static void 1439 asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */ 1440 int integer) /* I - Integer value */ 1441 { 1442 **buffer = CUPS_ASN1_INTEGER; 1443 (*buffer) ++; 1444 1445 if (integer > 0x7fffff || integer < -0x800000) 1446 { 1447 **buffer = 4; 1448 (*buffer) ++; 1449 **buffer = (unsigned char)(integer >> 24); 1450 (*buffer) ++; 1451 **buffer = (unsigned char)(integer >> 16); 1452 (*buffer) ++; 1453 **buffer = (unsigned char)(integer >> 8); 1454 (*buffer) ++; 1455 **buffer = (unsigned char)integer; 1456 (*buffer) ++; 1457 } 1458 else if (integer > 0x7fff || integer < -0x8000) 1459 { 1460 **buffer = 3; 1461 (*buffer) ++; 1462 **buffer = (unsigned char)(integer >> 16); 1463 (*buffer) ++; 1464 **buffer = (unsigned char)(integer >> 8); 1465 (*buffer) ++; 1466 **buffer = (unsigned char)integer; 1467 (*buffer) ++; 1468 } 1469 else if (integer > 0x7f || integer < -0x80) 1470 { 1471 **buffer = 2; 1472 (*buffer) ++; 1473 **buffer = (unsigned char)(integer >> 8); 1474 (*buffer) ++; 1475 **buffer = (unsigned char)integer; 1476 (*buffer) ++; 1477 } 1478 else 1479 { 1480 **buffer = 1; 1481 (*buffer) ++; 1482 **buffer = (unsigned char)integer; 1483 (*buffer) ++; 1484 } 1485 } 1486 1487 1488 /* 1489 * 'asn1_set_length()' - Set a value length. 1490 */ 1491 1492 static void 1493 asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */ 1494 unsigned length) /* I - Length value */ 1495 { 1496 if (length > 255) 1497 { 1498 **buffer = 0x82; /* 2-byte length */ 1499 (*buffer) ++; 1500 **buffer = (unsigned char)(length >> 8); 1501 (*buffer) ++; 1502 **buffer = (unsigned char)length; 1503 (*buffer) ++; 1504 } 1505 else if (length > 127) 1506 { 1507 **buffer = 0x81; /* 1-byte length */ 1508 (*buffer) ++; 1509 **buffer = (unsigned char)length; 1510 (*buffer) ++; 1511 } 1512 else 1513 { 1514 **buffer = (unsigned char)length; /* Length */ 1515 (*buffer) ++; 1516 } 1517 } 1518 1519 1520 /* 1521 * 'asn1_set_oid()' - Set an OID value. 1522 */ 1523 1524 static void 1525 asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */ 1526 const int *oid) /* I - OID value */ 1527 { 1528 **buffer = CUPS_ASN1_OID; 1529 (*buffer) ++; 1530 1531 asn1_set_length(buffer, asn1_size_oid(oid)); 1532 1533 if (oid[1] < 0) 1534 { 1535 asn1_set_packed(buffer, oid[0] * 40); 1536 return; 1537 } 1538 1539 asn1_set_packed(buffer, oid[0] * 40 + oid[1]); 1540 1541 for (oid += 2; *oid >= 0; oid ++) 1542 asn1_set_packed(buffer, *oid); 1543 } 1544 1545 1546 /* 1547 * 'asn1_set_packed()' - Set a packed integer value. 1548 */ 1549 1550 static void 1551 asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */ 1552 int integer) /* I - Integer value */ 1553 { 1554 if (integer > 0xfffffff) 1555 { 1556 **buffer = ((integer >> 28) & 0x7f) | 0x80; 1557 (*buffer) ++; 1558 } 1559 1560 if (integer > 0x1fffff) 1561 { 1562 **buffer = ((integer >> 21) & 0x7f) | 0x80; 1563 (*buffer) ++; 1564 } 1565 1566 if (integer > 0x3fff) 1567 { 1568 **buffer = ((integer >> 14) & 0x7f) | 0x80; 1569 (*buffer) ++; 1570 } 1571 1572 if (integer > 0x7f) 1573 { 1574 **buffer = ((integer >> 7) & 0x7f) | 0x80; 1575 (*buffer) ++; 1576 } 1577 1578 **buffer = integer & 0x7f; 1579 (*buffer) ++; 1580 } 1581 1582 1583 /* 1584 * 'asn1_size_integer()' - Figure out the number of bytes needed for an 1585 * integer value. 1586 */ 1587 1588 static unsigned /* O - Size in bytes */ 1589 asn1_size_integer(int integer) /* I - Integer value */ 1590 { 1591 if (integer > 0x7fffff || integer < -0x800000) 1592 return (4); 1593 else if (integer > 0x7fff || integer < -0x8000) 1594 return (3); 1595 else if (integer > 0x7f || integer < -0x80) 1596 return (2); 1597 else 1598 return (1); 1599 } 1600 1601 1602 /* 1603 * 'asn1_size_length()' - Figure out the number of bytes needed for a 1604 * length value. 1605 */ 1606 1607 static unsigned /* O - Size in bytes */ 1608 asn1_size_length(unsigned length) /* I - Length value */ 1609 { 1610 if (length > 0xff) 1611 return (3); 1612 else if (length > 0x7f) 1613 return (2); 1614 else 1615 return (1); 1616 } 1617 1618 1619 /* 1620 * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an 1621 * OID value. 1622 */ 1623 1624 static unsigned /* O - Size in bytes */ 1625 asn1_size_oid(const int *oid) /* I - OID value */ 1626 { 1627 unsigned length; /* Length of value */ 1628 1629 1630 if (oid[1] < 0) 1631 return (asn1_size_packed(oid[0] * 40)); 1632 1633 for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2; 1634 *oid >= 0; 1635 oid ++) 1636 length += asn1_size_packed(*oid); 1637 1638 return (length); 1639 } 1640 1641 1642 /* 1643 * 'asn1_size_packed()' - Figure out the number of bytes needed for a 1644 * packed integer value. 1645 */ 1646 1647 static unsigned /* O - Size in bytes */ 1648 asn1_size_packed(int integer) /* I - Integer value */ 1649 { 1650 if (integer > 0xfffffff) 1651 return (5); 1652 else if (integer > 0x1fffff) 1653 return (4); 1654 else if (integer > 0x3fff) 1655 return (3); 1656 else if (integer > 0x7f) 1657 return (2); 1658 else 1659 return (1); 1660 } 1661 1662 1663 /* 1664 * 'snmp_set_error()' - Set the localized error for a packet. 1665 */ 1666 1667 static void 1668 snmp_set_error(cups_snmp_t *packet, /* I - Packet */ 1669 const char *message) /* I - Error message */ 1670 { 1671 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 1672 1673 1674 if (!cg->lang_default) 1675 cg->lang_default = cupsLangDefault(); 1676 1677 packet->error = _cupsLangString(cg->lang_default, message); 1678 } 1679