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