]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/snmp.c
a291e8a829879901025d7158a3e63ee961cd6500
[thirdparty/cups.git] / cups / snmp.c
1 /*
2 * "$Id$"
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
33 static void asn1_debug(const char *prefix, unsigned char *buffer,
34 size_t len, int indent);
35 static int asn1_decode_snmp(unsigned char *buffer, size_t len,
36 cups_snmp_t *packet);
37 static int asn1_encode_snmp(unsigned char *buffer, size_t len,
38 cups_snmp_t *packet);
39 static int asn1_get_integer(unsigned char **buffer,
40 unsigned char *bufend,
41 unsigned length);
42 static int asn1_get_oid(unsigned char **buffer,
43 unsigned char *bufend,
44 unsigned length, int *oid, int oidsize);
45 static int asn1_get_packed(unsigned char **buffer,
46 unsigned char *bufend);
47 static char *asn1_get_string(unsigned char **buffer,
48 unsigned char *bufend,
49 unsigned length, char *string,
50 size_t strsize);
51 static unsigned asn1_get_length(unsigned char **buffer,
52 unsigned char *bufend);
53 static int asn1_get_type(unsigned char **buffer,
54 unsigned char *bufend);
55 static void asn1_set_integer(unsigned char **buffer,
56 int integer);
57 static void asn1_set_length(unsigned char **buffer,
58 unsigned length);
59 static void asn1_set_oid(unsigned char **buffer,
60 const int *oid);
61 static void asn1_set_packed(unsigned char **buffer,
62 int integer);
63 static unsigned asn1_size_integer(int integer);
64 static unsigned asn1_size_length(unsigned length);
65 static unsigned asn1_size_oid(const int *oid);
66 static unsigned asn1_size_packed(int integer);
67 static void snmp_set_error(cups_snmp_t *packet,
68 const char *message);
69
70
71 /*
72 * '_cupsSNMPClose()' - Close a SNMP socket.
73 */
74
75 void
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
90 int * /* 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
117 const 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
161 int /* 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
209 int /* 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
257 char * /* 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, 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
296 int /* 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
344 cups_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
457 void
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
479 int * /* 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
549 int /* 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
639 int /* 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
727 static void
728 asn1_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
924 static int /* O - 0 on success, -1 on error */
925 asn1_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
1082 static int /* O - Length on success, -1 on error */
1083 asn1_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
1225 static int /* O - Integer value */
1226 asn1_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
1253 static unsigned /* O - Length */
1254 asn1_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
1288 static int /* O - Number of OIDs */
1289 asn1_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
1342 static int /* O - Value */
1343 asn1_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
1372 static char * /* O - String */
1373 asn1_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
1415 static int /* O - Type */
1416 asn1_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
1436 static void
1437 asn1_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
1490 static void
1491 asn1_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
1522 static void
1523 asn1_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
1548 static void
1549 asn1_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
1586 static unsigned /* O - Size in bytes */
1587 asn1_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
1605 static unsigned /* O - Size in bytes */
1606 asn1_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
1622 static unsigned /* O - Size in bytes */
1623 asn1_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
1645 static unsigned /* O - Size in bytes */
1646 asn1_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
1665 static void
1666 snmp_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$".
1681 */