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