]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/snmp.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / cups / snmp.c
1 /*
2 * SNMP functions for CUPS.
3 *
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * "LICENSE" which should have been included with this file. If this
11 * file is missing or damaged, see the license at "http://www.cups.org/".
12 */
13
14 /*
15 * Include necessary headers.
16 */
17
18 #include "cups-private.h"
19 #include "snmp-private.h"
20 #ifdef HAVE_POLL
21 # include <poll.h>
22 #endif /* HAVE_POLL */
23
24
25 /*
26 * Local functions...
27 */
28
29 static void asn1_debug(const char *prefix, unsigned char *buffer,
30 size_t len, int indent);
31 static int asn1_decode_snmp(unsigned char *buffer, size_t len,
32 cups_snmp_t *packet);
33 static int asn1_encode_snmp(unsigned char *buffer, size_t len,
34 cups_snmp_t *packet);
35 static int asn1_get_integer(unsigned char **buffer,
36 unsigned char *bufend,
37 unsigned length);
38 static int asn1_get_oid(unsigned char **buffer,
39 unsigned char *bufend,
40 unsigned length, int *oid, int oidsize);
41 static int asn1_get_packed(unsigned char **buffer,
42 unsigned char *bufend);
43 static char *asn1_get_string(unsigned char **buffer,
44 unsigned char *bufend,
45 unsigned length, char *string,
46 size_t strsize);
47 static unsigned asn1_get_length(unsigned char **buffer,
48 unsigned char *bufend);
49 static int asn1_get_type(unsigned char **buffer,
50 unsigned char *bufend);
51 static void asn1_set_integer(unsigned char **buffer,
52 int integer);
53 static void asn1_set_length(unsigned char **buffer,
54 unsigned length);
55 static void asn1_set_oid(unsigned char **buffer,
56 const int *oid);
57 static void asn1_set_packed(unsigned char **buffer,
58 int integer);
59 static unsigned asn1_size_integer(int integer);
60 static unsigned asn1_size_length(unsigned length);
61 static unsigned asn1_size_oid(const int *oid);
62 static unsigned asn1_size_packed(int integer);
63 static void snmp_set_error(cups_snmp_t *packet,
64 const char *message);
65
66
67 /*
68 * '_cupsSNMPClose()' - Close a SNMP socket.
69 */
70
71 void
72 _cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */
73 {
74 DEBUG_printf(("4_cupsSNMPClose(fd=%d)", fd));
75
76 httpAddrClose(NULL, fd);
77 }
78
79
80 /*
81 * '_cupsSNMPCopyOID()' - Copy an OID.
82 *
83 * The array pointed to by "src" is terminated by the value -1.
84 */
85
86 int * /* O - New OID */
87 _cupsSNMPCopyOID(int *dst, /* I - Destination OID */
88 const int *src, /* I - Source OID */
89 int dstsize) /* I - Number of integers in dst */
90 {
91 int i; /* Looping var */
92
93
94 DEBUG_printf(("4_cupsSNMPCopyOID(dst=%p, src=%p, dstsize=%d)", dst, src,
95 dstsize));
96
97 for (i = 0, dstsize --; src[i] >= 0 && i < dstsize; i ++)
98 dst[i] = src[i];
99
100 dst[i] = -1;
101
102 return (dst);
103 }
104
105
106 /*
107 * '_cupsSNMPDefaultCommunity()' - Get the default SNMP community name.
108 *
109 * The default community name is the first community name found in the
110 * snmp.conf file. If no community name is defined there, "public" is used.
111 */
112
113 const char * /* O - Default community name */
114 _cupsSNMPDefaultCommunity(void)
115 {
116 cups_file_t *fp; /* snmp.conf file */
117 char line[1024], /* Line from file */
118 *value; /* Value from file */
119 int linenum; /* Line number in file */
120 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
121
122
123 DEBUG_puts("4_cupsSNMPDefaultCommunity()");
124
125 if (!cg->snmp_community[0])
126 {
127 strlcpy(cg->snmp_community, "public", sizeof(cg->snmp_community));
128
129 snprintf(line, sizeof(line), "%s/snmp.conf", cg->cups_serverroot);
130 if ((fp = cupsFileOpen(line, "r")) != NULL)
131 {
132 linenum = 0;
133 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
134 if (!_cups_strcasecmp(line, "Community") && value)
135 {
136 strlcpy(cg->snmp_community, value, sizeof(cg->snmp_community));
137 break;
138 }
139
140 cupsFileClose(fp);
141 }
142 }
143
144 DEBUG_printf(("5_cupsSNMPDefaultCommunity: Returning \"%s\"",
145 cg->snmp_community));
146
147 return (cg->snmp_community);
148 }
149
150
151 /*
152 * '_cupsSNMPIsOID()' - Test whether a SNMP response contains the specified OID.
153 *
154 * The array pointed to by "oid" is terminated by the value -1.
155 */
156
157 int /* O - 1 if equal, 0 if not equal */
158 _cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */
159 const int *oid) /* I - OID */
160 {
161 int i; /* Looping var */
162
163
164 /*
165 * Range check input...
166 */
167
168 DEBUG_printf(("4_cupsSNMPIsOID(packet=%p, oid=%p)", packet, oid));
169
170 if (!packet || !oid)
171 {
172 DEBUG_puts("5_cupsSNMPIsOID: Returning 0");
173
174 return (0);
175 }
176
177 /*
178 * Compare OIDs...
179 */
180
181 for (i = 0;
182 i < CUPS_SNMP_MAX_OID && oid[i] >= 0 && packet->object_name[i] >= 0;
183 i ++)
184 if (oid[i] != packet->object_name[i])
185 {
186 DEBUG_puts("5_cupsSNMPIsOID: Returning 0");
187
188 return (0);
189 }
190
191 DEBUG_printf(("5_cupsSNMPIsOID: Returning %d",
192 i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i]));
193
194 return (i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i]);
195 }
196
197
198 /*
199 * '_cupsSNMPIsOIDPrefixed()' - Test whether a SNMP response uses the specified
200 * OID prefix.
201 *
202 * The array pointed to by "prefix" is terminated by the value -1.
203 */
204
205 int /* O - 1 if prefixed, 0 if not prefixed */
206 _cupsSNMPIsOIDPrefixed(
207 cups_snmp_t *packet, /* I - Response packet */
208 const int *prefix) /* I - OID prefix */
209 {
210 int i; /* Looping var */
211
212
213 /*
214 * Range check input...
215 */
216
217 DEBUG_printf(("4_cupsSNMPIsOIDPrefixed(packet=%p, prefix=%p)", packet,
218 prefix));
219
220 if (!packet || !prefix)
221 {
222 DEBUG_puts("5_cupsSNMPIsOIDPrefixed: Returning 0");
223
224 return (0);
225 }
226
227 /*
228 * Compare OIDs...
229 */
230
231 for (i = 0;
232 i < CUPS_SNMP_MAX_OID && prefix[i] >= 0 && packet->object_name[i] >= 0;
233 i ++)
234 if (prefix[i] != packet->object_name[i])
235 {
236 DEBUG_puts("5_cupsSNMPIsOIDPrefixed: Returning 0");
237
238 return (0);
239 }
240
241 DEBUG_printf(("5_cupsSNMPIsOIDPrefixed: Returning %d",
242 i < CUPS_SNMP_MAX_OID));
243
244 return (i < CUPS_SNMP_MAX_OID);
245 }
246
247
248 /*
249 * '_cupsSNMPOIDToString()' - Convert an OID to a string.
250 */
251
252
253 char * /* O - New string or @code NULL@ on error */
254 _cupsSNMPOIDToString(const int *src, /* I - OID */
255 char *dst, /* I - String buffer */
256 size_t dstsize) /* I - Size of string buffer */
257 {
258 char *dstptr, /* Pointer into string buffer */
259 *dstend; /* End of string buffer */
260
261
262 DEBUG_printf(("4_cupsSNMPOIDToString(src=%p, dst=%p, dstsize=" CUPS_LLFMT ")",
263 src, dst, CUPS_LLCAST dstsize));
264
265 /*
266 * Range check input...
267 */
268
269 if (!src || !dst || dstsize < 4)
270 return (NULL);
271
272 /*
273 * Loop through the OID array and build a string...
274 */
275
276 for (dstptr = dst, dstend = dstptr + dstsize - 1;
277 *src >= 0 && dstptr < dstend;
278 src ++, dstptr += strlen(dstptr))
279 snprintf(dstptr, (size_t)(dstend - dstptr + 1), ".%d", *src);
280
281 if (*src >= 0)
282 return (NULL);
283 else
284 return (dst);
285 }
286
287
288 /*
289 * '_cupsSNMPOpen()' - Open a SNMP socket.
290 */
291
292 int /* O - SNMP socket file descriptor */
293 _cupsSNMPOpen(int family) /* I - Address family - @code AF_INET@ or @code AF_INET6@ */
294 {
295 int fd; /* SNMP socket file descriptor */
296 int val; /* Socket option value */
297
298
299 /*
300 * Create the SNMP socket...
301 */
302
303 DEBUG_printf(("4_cupsSNMPOpen(family=%d)", family));
304
305 if ((fd = socket(family, SOCK_DGRAM, 0)) < 0)
306 {
307 DEBUG_printf(("5_cupsSNMPOpen: Returning -1 (%s)", strerror(errno)));
308
309 return (-1);
310 }
311
312 /*
313 * Set the "broadcast" flag...
314 */
315
316 val = 1;
317
318 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, CUPS_SOCAST &val, sizeof(val)))
319 {
320 DEBUG_printf(("5_cupsSNMPOpen: Returning -1 (%s)", strerror(errno)));
321
322 close(fd);
323
324 return (-1);
325 }
326
327 DEBUG_printf(("5_cupsSNMPOpen: Returning %d", fd));
328
329 return (fd);
330 }
331
332
333 /*
334 * '_cupsSNMPRead()' - Read and parse a SNMP response.
335 *
336 * If "timeout" is negative, @code _cupsSNMPRead@ will wait for a response
337 * indefinitely.
338 */
339
340 cups_snmp_t * /* O - SNMP packet or @code NULL@ if none */
341 _cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */
342 cups_snmp_t *packet, /* I - SNMP packet buffer */
343 double timeout) /* I - Timeout in seconds */
344 {
345 unsigned char buffer[CUPS_SNMP_MAX_PACKET];
346 /* Data packet */
347 ssize_t bytes; /* Number of bytes received */
348 socklen_t addrlen; /* Source address length */
349 http_addr_t address; /* Source address */
350
351
352 /*
353 * Range check input...
354 */
355
356 DEBUG_printf(("4_cupsSNMPRead(fd=%d, packet=%p, timeout=%.1f)", fd, packet,
357 timeout));
358
359 if (fd < 0 || !packet)
360 {
361 DEBUG_puts("5_cupsSNMPRead: Returning NULL");
362
363 return (NULL);
364 }
365
366 /*
367 * Optionally wait for a response...
368 */
369
370 if (timeout >= 0.0)
371 {
372 int ready; /* Data ready on socket? */
373 #ifdef HAVE_POLL
374 struct pollfd pfd; /* Polled file descriptor */
375
376 pfd.fd = fd;
377 pfd.events = POLLIN;
378
379 while ((ready = poll(&pfd, 1, (int)(timeout * 1000.0))) < 0 &&
380 (errno == EINTR || errno == EAGAIN));
381
382 #else
383 fd_set input_set; /* select() input set */
384 struct timeval stimeout; /* select() timeout */
385
386 do
387 {
388 FD_ZERO(&input_set);
389 FD_SET(fd, &input_set);
390
391 stimeout.tv_sec = (int)timeout;
392 stimeout.tv_usec = (int)((timeout - stimeout.tv_sec) * 1000000);
393
394 ready = select(fd + 1, &input_set, NULL, NULL, &stimeout);
395 }
396 # ifdef WIN32
397 while (ready < 0 && WSAGetLastError() == WSAEINTR);
398 # else
399 while (ready < 0 && (errno == EINTR || errno == EAGAIN));
400 # endif /* WIN32 */
401 #endif /* HAVE_POLL */
402
403 /*
404 * If we don't have any data ready, return right away...
405 */
406
407 if (ready <= 0)
408 {
409 DEBUG_puts("5_cupsSNMPRead: Returning NULL (timeout)");
410
411 return (NULL);
412 }
413 }
414
415 /*
416 * Read the response data...
417 */
418
419 addrlen = sizeof(address);
420
421 if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (void *)&address,
422 &addrlen)) < 0)
423 {
424 DEBUG_printf(("5_cupsSNMPRead: Returning NULL (%s)", strerror(errno)));
425
426 return (NULL);
427 }
428
429 /*
430 * Look for the response status code in the SNMP message header...
431 */
432
433 asn1_debug("DEBUG: IN ", buffer, (size_t)bytes, 0);
434
435 asn1_decode_snmp(buffer, (size_t)bytes, packet);
436
437 memcpy(&(packet->address), &address, sizeof(packet->address));
438
439 /*
440 * Return decoded data packet...
441 */
442
443 DEBUG_puts("5_cupsSNMPRead: Returning packet");
444
445 return (packet);
446 }
447
448
449 /*
450 * '_cupsSNMPSetDebug()' - Enable/disable debug logging to stderr.
451 */
452
453 void
454 _cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */
455 {
456 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
457
458
459 DEBUG_printf(("4_cupsSNMPSetDebug(level=%d)", level));
460
461 cg->snmp_debug = level;
462 }
463
464
465 /*
466 * '_cupsSNMPStringToOID()' - Convert a numeric OID string to an OID array.
467 *
468 * This function converts a string of the form ".N.N.N.N.N" to the
469 * corresponding OID array terminated by -1.
470 *
471 * @code NULL@ is returned if the array is not large enough or the string is
472 * not a valid OID number.
473 */
474
475 int * /* O - Pointer to OID array or @code NULL@ on error */
476 _cupsSNMPStringToOID(const char *src, /* I - OID string */
477 int *dst, /* I - OID array */
478 int dstsize)/* I - Number of integers in OID array */
479 {
480 int *dstptr, /* Pointer into OID array */
481 *dstend; /* End of OID array */
482
483
484 DEBUG_printf(("4_cupsSNMPStringToOID(src=\"%s\", dst=%p, dstsize=%d)",
485 src, dst, dstsize));
486
487 /*
488 * Range check input...
489 */
490
491 if (!src || !dst || dstsize < 2)
492 return (NULL);
493
494 /*
495 * Skip leading "."...
496 */
497
498 if (*src == '.')
499 src ++;
500
501 /*
502 * Loop to the end of the string...
503 */
504
505 for (dstend = dst + dstsize - 1, dstptr = dst, *dstptr = 0;
506 *src && dstptr < dstend;
507 src ++)
508 {
509 if (*src == '.')
510 {
511 dstptr ++;
512 *dstptr = 0;
513 }
514 else if (isdigit(*src & 255))
515 *dstptr = *dstptr * 10 + *src - '0';
516 else
517 break;
518 }
519
520 if (*src)
521 return (NULL);
522
523 /*
524 * Terminate the end of the OID array and return...
525 */
526
527 dstptr[1] = -1;
528
529 return (dst);
530 }
531
532
533 /*
534 * '_cupsSNMPWalk()' - Enumerate a group of OIDs.
535 *
536 * This function queries all of the OIDs with the specified OID prefix,
537 * calling the "cb" function for every response that is received.
538 *
539 * The array pointed to by "prefix" is terminated by the value -1.
540 *
541 * If "timeout" is negative, @code _cupsSNMPWalk@ will wait for a response
542 * indefinitely.
543 */
544
545 int /* O - Number of OIDs found or -1 on error */
546 _cupsSNMPWalk(int fd, /* I - SNMP socket */
547 http_addr_t *address, /* I - Address to query */
548 int version, /* I - SNMP version */
549 const char *community,/* I - Community name */
550 const int *prefix, /* I - OID prefix */
551 double timeout, /* I - Timeout for each response in seconds */
552 cups_snmp_cb_t cb, /* I - Function to call for each response */
553 void *data) /* I - User data pointer that is passed to the callback function */
554 {
555 int count = 0; /* Number of OIDs found */
556 unsigned request_id = 0; /* Current request ID */
557 cups_snmp_t packet; /* Current response packet */
558 int lastoid[CUPS_SNMP_MAX_OID];
559 /* Last OID we got */
560
561
562 /*
563 * Range check input...
564 */
565
566 DEBUG_printf(("4_cupsSNMPWalk(fd=%d, address=%p, version=%d, "
567 "community=\"%s\", prefix=%p, timeout=%.1f, cb=%p, data=%p)",
568 fd, address, version, community, prefix, timeout, cb, data));
569
570 if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community ||
571 !prefix || !cb)
572 {
573 DEBUG_puts("5_cupsSNMPWalk: Returning -1");
574
575 return (-1);
576 }
577
578 /*
579 * Copy the OID prefix and then loop until we have no more OIDs...
580 */
581
582 _cupsSNMPCopyOID(packet.object_name, prefix, CUPS_SNMP_MAX_OID);
583 lastoid[0] = -1;
584
585 for (;;)
586 {
587 request_id ++;
588
589 if (!_cupsSNMPWrite(fd, address, version, community,
590 CUPS_ASN1_GET_NEXT_REQUEST, request_id,
591 packet.object_name))
592 {
593 DEBUG_puts("5_cupsSNMPWalk: Returning -1");
594
595 return (-1);
596 }
597
598 if (!_cupsSNMPRead(fd, &packet, timeout))
599 {
600 DEBUG_puts("5_cupsSNMPWalk: Returning -1");
601
602 return (-1);
603 }
604
605 if (!_cupsSNMPIsOIDPrefixed(&packet, prefix) ||
606 _cupsSNMPIsOID(&packet, lastoid))
607 {
608 DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count));
609
610 return (count);
611 }
612
613 if (packet.error || packet.error_status)
614 {
615 DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count > 0 ? count : -1));
616
617 return (count > 0 ? count : -1);
618 }
619
620 _cupsSNMPCopyOID(lastoid, packet.object_name, CUPS_SNMP_MAX_OID);
621
622 count ++;
623
624 (*cb)(&packet, data);
625 }
626 }
627
628
629 /*
630 * '_cupsSNMPWrite()' - Send an SNMP query packet.
631 *
632 * The array pointed to by "oid" is terminated by the value -1.
633 */
634
635 int /* O - 1 on success, 0 on error */
636 _cupsSNMPWrite(
637 int fd, /* I - SNMP socket */
638 http_addr_t *address, /* I - Address to send to */
639 int version, /* I - SNMP version */
640 const char *community, /* I - Community name */
641 cups_asn1_t request_type, /* I - Request type */
642 const unsigned request_id, /* I - Request ID */
643 const int *oid) /* I - OID */
644 {
645 int i; /* Looping var */
646 cups_snmp_t packet; /* SNMP message packet */
647 unsigned char buffer[CUPS_SNMP_MAX_PACKET];
648 /* SNMP message buffer */
649 ssize_t bytes; /* Size of message */
650 http_addr_t temp; /* Copy of address */
651
652
653 /*
654 * Range check input...
655 */
656
657 DEBUG_printf(("4_cupsSNMPWrite(fd=%d, address=%p, version=%d, "
658 "community=\"%s\", request_type=%d, request_id=%u, oid=%p)",
659 fd, address, version, community, request_type, request_id, oid));
660
661 if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community ||
662 (request_type != CUPS_ASN1_GET_REQUEST &&
663 request_type != CUPS_ASN1_GET_NEXT_REQUEST) || request_id < 1 || !oid)
664 {
665 DEBUG_puts("5_cupsSNMPWrite: Returning 0 (bad arguments)");
666
667 return (0);
668 }
669
670 /*
671 * Create the SNMP message...
672 */
673
674 memset(&packet, 0, sizeof(packet));
675
676 packet.version = version;
677 packet.request_type = request_type;
678 packet.request_id = request_id;
679 packet.object_type = CUPS_ASN1_NULL_VALUE;
680
681 strlcpy(packet.community, community, sizeof(packet.community));
682
683 for (i = 0; oid[i] >= 0 && i < (CUPS_SNMP_MAX_OID - 1); i ++)
684 packet.object_name[i] = oid[i];
685 packet.object_name[i] = -1;
686
687 if (oid[i] >= 0)
688 {
689 DEBUG_puts("5_cupsSNMPWrite: Returning 0 (OID too big)");
690
691 errno = E2BIG;
692 return (0);
693 }
694
695 bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);
696
697 if (bytes < 0)
698 {
699 DEBUG_puts("5_cupsSNMPWrite: Returning 0 (request too big)");
700
701 errno = E2BIG;
702 return (0);
703 }
704
705 asn1_debug("DEBUG: OUT ", buffer, (size_t)bytes, 0);
706
707 /*
708 * Send the message...
709 */
710
711 temp = *address;
712
713 _httpAddrSetPort(&temp, CUPS_SNMP_PORT);
714
715 return (sendto(fd, buffer, (size_t)bytes, 0, (void *)&temp, (socklen_t)httpAddrLength(&temp)) == bytes);
716 }
717
718
719 /*
720 * 'asn1_debug()' - Decode an ASN1-encoded message.
721 */
722
723 static void
724 asn1_debug(const char *prefix, /* I - Prefix string */
725 unsigned char *buffer, /* I - Buffer */
726 size_t len, /* I - Length of buffer */
727 int indent) /* I - Indentation */
728 {
729 size_t i; /* Looping var */
730 unsigned char *bufend; /* End of buffer */
731 int integer; /* Number value */
732 int oid[CUPS_SNMP_MAX_OID]; /* OID value */
733 char string[CUPS_SNMP_MAX_STRING];
734 /* String value */
735 unsigned char value_type; /* Type of value */
736 unsigned value_length; /* Length of value */
737 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
738
739
740 #ifdef __clang_analyzer__ /* Suppress bogus clang error */
741 memset(string, 0, sizeof(string));
742 #endif /* __clang_analyzer__ */
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 }