]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/snmp.c
Merge changes from CUPS 1.4svn-r7282.
[thirdparty/cups.git] / cups / snmp.c
CommitLineData
91c84a35
MS
1/*
2 * "$Id$"
3 *
4 * SNMP functions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 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 * cupsSNMPIsOID() - Test whether a SNMP response contains the
22 * specified OID.
23 * cupsSNMPIsOIDPrefixed() - Test whether a SNMP response uses the specified
24 * OID prefix.
25 * cupsSNMPOpen() - Open a SNMP socket.
26 * cupsSNMPRead() - Read and parse a SNMP response...
27 * cupsSNMPSetDebug() - Enable/disable debug logging to stderr.
28 * cupsSNMPWrite() - Send an SNMP query packet.
29 * asn1_decode_snmp() - Decode a SNMP packet.
30 * asn1_debug() - Decode an ASN1-encoded message.
31 * asn1_encode_snmp() - Encode a SNMP packet.
32 * asn1_get_integer() - Get an integer value.
33 * asn1_get_length() - Get a value length.
34 * asn1_get_oid() - Get an OID value.
35 * asn1_get_packed() - Get a packed integer value.
36 * asn1_get_string() - Get a string value.
37 * asn1_get_type() - Get a value type.
38 * asn1_set_integer() - Set an integer value.
39 * asn1_set_length() - Set a value length.
40 * asn1_set_oid() - Set an OID value.
41 * asn1_set_packed() - Set a packed integer value.
42 * asn1_size_integer() - Figure out the number of bytes needed for an
43 * integer value.
44 * asn1_size_length() - Figure out the number of bytes needed for a
45 * length value.
46 * asn1_size_oid() - Figure out the numebr of bytes needed for an OID
47 * value.
48 * asn1_size_packed() - Figure out the number of bytes needed for a
49 * packed integer value.
50 * snmp_set_error() - Set the localized error for a packet.
51 */
52
53/*
54 * Include necessary headers.
55 */
56
57#include "globals.h"
58#include "snmp.h"
59#include <errno.h>
60#ifdef HAVE_POLL
61# include <sys/poll.h>
62#endif /* HAVE_POLL */
63
64
65/*
66 * Local functions...
67 */
68
69static int asn1_decode_snmp(unsigned char *buffer, size_t len,
70 cups_snmp_t *packet);
71static void asn1_debug(const char *prefix, unsigned char *buffer,
72 size_t len, int indent);
73static int asn1_encode_snmp(unsigned char *buffer, size_t len,
74 cups_snmp_t *packet);
75static int asn1_get_integer(unsigned char **buffer,
76 unsigned char *bufend,
77 int length);
78static int asn1_get_oid(unsigned char **buffer,
79 unsigned char *bufend,
80 int length, int *oid, int oidsize);
81static int asn1_get_packed(unsigned char **buffer,
82 unsigned char *bufend);
83static char *asn1_get_string(unsigned char **buffer,
84 unsigned char *bufend,
85 int length, char *string,
86 int strsize);
87static int asn1_get_length(unsigned char **buffer,
88 unsigned char *bufend);
89static int asn1_get_type(unsigned char **buffer,
90 unsigned char *bufend);
91static void asn1_set_integer(unsigned char **buffer,
92 int integer);
93static void asn1_set_length(unsigned char **buffer,
94 int length);
95static void asn1_set_oid(unsigned char **buffer,
96 const int *oid);
97static void asn1_set_packed(unsigned char **buffer,
98 int integer);
99static int asn1_size_integer(int integer);
100static int asn1_size_length(int length);
101static int asn1_size_oid(const int *oid);
102static int asn1_size_packed(int integer);
103static void snmp_set_error(cups_snmp_t *packet,
104 const char *message);
105
106
107/*
108 * 'cupsSNMPClose()' - Close a SNMP socket.
109 *
110 * @since CUPS 1.4@
111 */
112
113void
114cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */
115{
116#ifdef WIN32
117 closesocket(fd);
118#else
119 close(fd);
120#endif /* WIN32 */
121}
122
123
124/*
125 * 'cupsSNMPCopyOID()' - Copy an OID.
126 */
127
128int * /* O - New OID */
129cupsSNMPCopyOID(int *dst, /* I - Destination OID */
130 const int *src, /* I - Source OID */
131 int dstsize) /* I - Number of integers in dst */
132{
133 int i; /* Looping var */
134
135
136 for (i = 0, dstsize --; src[i] && i < dstsize; i ++)
137 dst[i] = src[i];
138
139 dst[i] = 0;
140
141 return (dst);
142}
143
144
145/*
146 * 'cupsSNMPIsOID()' - Test whether a SNMP response contains the specified OID.
147 *
148 * The array pointed to by "oid" is 0-terminated.
149 *
150 * @since CUPS 1.4@
151 */
152
153int /* O - 1 if equal, 0 if not equal */
154cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */
155 const int *oid) /* I - OID */
156{
157 int i; /* Looping var */
158
159
160 /*
161 * Range check input...
162 */
163
164 if (!packet || !oid)
165 return (0);
166
167 /*
168 * Compare OIDs...
169 */
170
171 for (i = 0; i < CUPS_SNMP_MAX_OID && oid[i] && packet->object_name[i]; i ++)
172 if (oid[i] != packet->object_name[i])
173 return (0);
174
175 return (i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i]);
176}
177
178
179/*
180 * 'cupsSNMPIsOIDPrefixed()' - Test whether a SNMP response uses the specified
181 * OID prefix.
182 *
183 * The array pointed to by "prefix" is 0-terminated.
184 *
185 * @since CUPS 1.4@
186 */
187
188int /* O - 1 if prefixed, 0 if not prefixed */
189cupsSNMPIsOIDPrefixed(
190 cups_snmp_t *packet, /* I - Response packet */
191 const int *prefix) /* I - OID prefix */
192{
193 int i; /* Looping var */
194
195
196 /*
197 * Range check input...
198 */
199
200 if (!packet || !prefix)
201 return (0);
202
203 /*
204 * Compare OIDs...
205 */
206
207 for (i = 0;
208 i < CUPS_SNMP_MAX_OID && prefix[i] && packet->object_name[i];
209 i ++)
210 if (prefix[i] != packet->object_name[i])
211 return (0);
212
213 return (i < CUPS_SNMP_MAX_OID);
214}
215
216
217/*
218 * 'cupsSNMPOpen()' - Open a SNMP socket.
219 *
220 * @since CUPS 1.4@
221 */
222
223int /* O - SNMP socket file descriptor */
224cupsSNMPOpen(void)
225{
226 int fd; /* SNMP socket file descriptor */
227 int val; /* Socket option value */
228
229
230 /*
231 * Create the SNMP socket...
232 */
233
234 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
235 return (-1);
236
237 /*
238 * Set the "broadcast" flag...
239 */
240
241 val = 1;
242
243 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
244 {
245 close(fd);
246
247 return (-1);
248 }
249
250 return (fd);
251}
252
253
254/*
255 * 'cupsSNMPRead()' - Read and parse a SNMP response...
256 *
257 * If "timeout" is negative, cupsSNMPRead() will wait for a response
258 * indefinitely.
259 *
260 * @since CUPS 1.4@
261 */
262
263cups_snmp_t * /* O - SNMP packet or NULL if none */
264cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */
265 cups_snmp_t *packet, /* I - SNMP packet buffer */
266 int msec) /* I - Timeout in milliseconds */
267{
268 unsigned char buffer[CUPS_SNMP_MAX_PACKET];
269 /* Data packet */
270 int bytes; /* Number of bytes received */
271 socklen_t addrlen; /* Source address length */
272
273
274 /*
275 * Range check input...
276 */
277
278 if (fd < 0 || !packet)
279 return (NULL);
280
281 /*
282 * Optionally wait for a response...
283 */
284
285 if (msec >= 0)
286 {
287 int ready; /* Data ready on socket? */
288#ifdef HAVE_POLL
289 struct pollfd pfd; /* Polled file descriptor */
290
291 pfd.fd = fd;
292 pfd.events = POLLIN;
293
294 while ((ready = poll(&pfd, 1, msec)) < 0 && errno == EINTR);
295
296#else
297 fd_set input_set; /* select() input set */
298 struct timeval timeout; /* select() timeout */
299
300 do
301 {
302 FD_ZERO(&input_set);
303 FD_SET(fd, &input_set);
304
305 timeout.tv_sec = msec / 1000;
306 timeout.tv_usec = (msec % 1000) * 1000;
307
308 ready = select(fd + 1, &input_set, NULL, NULL, &timeout);
309 }
310# ifdef WIN32
311 while (ready < 0 && WSAGetLastError() == WSAEINTR);
312# else
313 while (ready < 0 && errno == EINTR);
314# endif /* WIN32 */
315#endif /* HAVE_POLL */
316
317 /*
318 * If we don't have any data ready, return right away...
319 */
320
321 if (ready <= 0)
322 return (NULL);
323 }
324
325 /*
326 * Read the response data...
327 */
328
329 addrlen = sizeof(packet->address);
330
331 if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0,
332 (void *)&(packet->address), &addrlen)) < 0)
333 return (NULL);
334
335 /*
336 * Look for the response status code in the SNMP message header...
337 */
338
339 asn1_debug("DEBUG: IN ", buffer, bytes, 0);
340
341 asn1_decode_snmp(buffer, bytes, packet);
342
343 /*
344 * Return decoded data packet...
345 */
346
347 return (packet);
348}
349
350
351/*
352 * 'cupsSNMPSetDebug()' - Enable/disable debug logging to stderr.
353 *
354 * @since CUPS 1.4@
355 */
356
357void
358cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */
359{
360 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
361
362
363 cg->snmp_debug = level;
364}
365
366
367/*
368 * 'cupsSNMPWrite()' - Send an SNMP query packet.
369 *
370 * The array pointed to by "oid" is 0-terminated.
371 *
372 * @since CUPS 1.4@
373 */
374
375int /* O - 1 on success, 0 on error */
376cupsSNMPWrite(
377 int fd, /* I - SNMP socket */
378 http_addr_t *address, /* I - Address to send to */
379 int version, /* I - SNMP version */
380 const char *community, /* I - Community name */
381 cups_asn1_t request_type, /* I - Request type */
382 const unsigned request_id, /* I - Request ID */
383 const int *oid) /* I - OID */
384{
385 int i; /* Looping var */
386 cups_snmp_t packet; /* SNMP message packet */
387 unsigned char buffer[CUPS_SNMP_MAX_PACKET];
388 /* SNMP message buffer */
389 int bytes; /* Size of message */
390
391
392 /*
393 * Create the SNMP message...
394 */
395
396 memset(&packet, 0, sizeof(packet));
397
398 packet.version = version;
399 packet.request_type = request_type;
400 packet.request_id = request_id;
401 packet.object_type = CUPS_ASN1_NULL_VALUE;
402
403 strlcpy(packet.community, community, sizeof(packet.community));
404
405 for (i = 0; oid[i]; i ++)
406 packet.object_name[i] = oid[i];
407
408 bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);
409
410 if (bytes < 0)
411 {
412 errno = E2BIG;
413
414 return (0);
415 }
416
417 asn1_debug("DEBUG: OUT ", buffer, bytes, 0);
418
419 /*
420 * Send the message...
421 */
422
423#ifdef AF_INET6
424 if (address->addr.sa_family == AF_INET6)
425 address->ipv6.sin6_port = htons(CUPS_SNMP_PORT);
426 else
427#endif /* AF_INET6 */
428 address->ipv4.sin_port = htons(CUPS_SNMP_PORT);
429
430 return (sendto(fd, buffer, bytes, 0, (void *)address,
431 httpAddrLength(address)) == bytes);
432}
433
434
435/*
436 * 'asn1_decode_snmp()' - Decode a SNMP packet.
437 */
438
439static int /* O - 0 on success, -1 on error */
440asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */
441 size_t len, /* I - Size of buffer */
442 cups_snmp_t *packet) /* I - SNMP packet */
443{
444 unsigned char *bufptr, /* Pointer into the data */
445 *bufend; /* End of data */
446 int length; /* Length of value */
447
448
449 /*
450 * Initialize the decoding...
451 */
452
453 memset(packet, 0, sizeof(cups_snmp_t));
454
455 bufptr = buffer;
456 bufend = buffer + len;
457
458 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
459 snmp_set_error(packet, _("Packet does not start with SEQUENCE"));
460 else if (asn1_get_length(&bufptr, bufend) == 0)
461 snmp_set_error(packet, _("SEQUENCE uses indefinite length"));
462 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
463 snmp_set_error(packet, _("No version number"));
464 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
465 snmp_set_error(packet, _("Version uses indefinite length"));
466 else if ((packet->version = asn1_get_integer(&bufptr, bufend, length))
467 != CUPS_SNMP_VERSION_1)
468 snmp_set_error(packet, _("Bad SNMP version number"));
469 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OCTET_STRING)
470 snmp_set_error(packet, _("No community name"));
471 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
472 snmp_set_error(packet, _("Community name uses indefinite length"));
473 else
474 {
475 asn1_get_string(&bufptr, bufend, length, packet->community,
476 sizeof(packet->community));
477
478 if ((packet->request_type = asn1_get_type(&bufptr, bufend))
479 != CUPS_ASN1_GET_RESPONSE)
480 snmp_set_error(packet, _("Packet does not contain a Get-Response-PDU"));
481 else if (asn1_get_length(&bufptr, bufend) == 0)
482 snmp_set_error(packet, _("Get-Response-PDU uses indefinite length"));
483 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
484 snmp_set_error(packet, _("No request-id"));
485 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
486 snmp_set_error(packet, _("request-id uses indefinite length"));
487 else
488 {
489 packet->request_id = asn1_get_integer(&bufptr, bufend, length);
490
491 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
492 snmp_set_error(packet, _("No error-status"));
493 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
494 snmp_set_error(packet, _("error-status uses indefinite length"));
495 else
496 {
497 packet->error_status = asn1_get_integer(&bufptr, bufend, length);
498
499 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
500 snmp_set_error(packet, _("No error-index"));
501 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
502 snmp_set_error(packet, _("error-index uses indefinite length"));
503 else
504 {
505 packet->error_index = asn1_get_integer(&bufptr, bufend, length);
506
507 if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
508 snmp_set_error(packet, _("No variable-bindings SEQUENCE"));
509 else if (asn1_get_length(&bufptr, bufend) == 0)
510 snmp_set_error(packet,
511 _("variable-bindings uses indefinite length"));
512 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
513 snmp_set_error(packet, _("No VarBind SEQUENCE"));
514 else if (asn1_get_length(&bufptr, bufend) == 0)
515 snmp_set_error(packet, _("VarBind uses indefinite length"));
516 else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OID)
517 snmp_set_error(packet, _("No name OID"));
518 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
519 snmp_set_error(packet, _("Name OID uses indefinite length"));
520 else
521 {
522 asn1_get_oid(&bufptr, bufend, length, packet->object_name,
523 CUPS_SNMP_MAX_OID);
524
525 packet->object_type = asn1_get_type(&bufptr, bufend);
526
527 if ((length = asn1_get_length(&bufptr, bufend)) == 0 &&
528 packet->object_type != CUPS_ASN1_NULL_VALUE &&
529 packet->object_type != CUPS_ASN1_OCTET_STRING)
530 snmp_set_error(packet, _("Value uses indefinite length"));
531 else
532 {
533 switch (packet->object_type)
534 {
535 case CUPS_ASN1_BOOLEAN :
536 packet->object_value.boolean =
537 asn1_get_integer(&bufptr, bufend, length);
538 break;
539
540 case CUPS_ASN1_INTEGER :
541 packet->object_value.integer =
542 asn1_get_integer(&bufptr, bufend, length);
543 break;
544
545 case CUPS_ASN1_NULL_VALUE :
546 break;
547
548 case CUPS_ASN1_OCTET_STRING :
549 asn1_get_string(&bufptr, bufend, length,
550 packet->object_value.string,
551 CUPS_SNMP_MAX_STRING);
552 break;
553
554 case CUPS_ASN1_OID :
555 asn1_get_oid(&bufptr, bufend, length,
556 packet->object_value.oid, CUPS_SNMP_MAX_OID);
557 break;
558
559 case CUPS_ASN1_COUNTER :
560 packet->object_value.counter =
561 asn1_get_integer(&bufptr, bufend, length);
562 break;
563
564 case CUPS_ASN1_GAUGE :
565 packet->object_value.gauge =
566 asn1_get_integer(&bufptr, bufend, length);
567 break;
568
569 default :
570 snmp_set_error(packet, _("Unsupported value type"));
571 break;
572 }
573 }
574 }
575 }
576 }
577 }
578 }
579
580 return (packet->error ? -1 : 0);
581}
582
583
584/*
585 * 'asn1_debug()' - Decode an ASN1-encoded message.
586 */
587
588static void
589asn1_debug(const char *prefix, /* I - Prefix string */
590 unsigned char *buffer, /* I - Buffer */
591 size_t len, /* I - Length of buffer */
592 int indent) /* I - Indentation */
593{
594 int i; /* Looping var */
595 unsigned char *bufend; /* End of buffer */
596 int integer; /* Number value */
597 int oid[CUPS_SNMP_MAX_OID]; /* OID value */
598 char string[CUPS_SNMP_MAX_STRING];
599 /* String value */
600 unsigned char value_type; /* Type of value */
601 int value_length; /* Length of value */
602 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
603
604
605 if (cg->snmp_debug <= 0)
606 return;
607
608 bufend = buffer + len;
609
610 while (buffer < bufend)
611 {
612 /*
613 * Get value type...
614 */
615
616 value_type = asn1_get_type(&buffer, bufend);
617 value_length = asn1_get_length(&buffer, bufend);
618
619 switch (value_type)
620 {
621 case CUPS_ASN1_BOOLEAN :
622 integer = asn1_get_integer(&buffer, bufend, value_length);
623
624 fprintf(stderr, "%s%*sBOOLEAN %d bytes %d\n", prefix, indent, "",
625 value_length, integer);
626 break;
627
628 case CUPS_ASN1_INTEGER :
629 integer = asn1_get_integer(&buffer, bufend, value_length);
630
631 fprintf(stderr, "%s%*sINTEGER %d bytes %d\n", prefix, indent, "",
632 value_length, integer);
633 break;
634
635 case CUPS_ASN1_OCTET_STRING :
636 fprintf(stderr, "%s%*sOCTET STRING %d bytes \"%s\"\n", prefix,
637 indent, "", value_length,
638 asn1_get_string(&buffer, bufend, value_length, string,
639 sizeof(string)));
640 break;
641
642 case CUPS_ASN1_NULL_VALUE :
643 fprintf(stderr, "%s%*sNULL VALUE %d bytes\n", prefix, indent, "",
644 value_length);
645
646 buffer += value_length;
647 break;
648
649 case CUPS_ASN1_OID :
650 asn1_get_oid(&buffer, bufend, value_length, oid, CUPS_SNMP_MAX_OID);
651
652 fprintf(stderr, "%s%*sOID %d bytes ", prefix, indent, "",
653 value_length);
654 for (i = 0; oid[i]; i ++)
655 fprintf(stderr, ".%d", oid[i]);
656 putc('\n', stderr);
657 break;
658
659 case CUPS_ASN1_SEQUENCE :
660 fprintf(stderr, "%s%*sSEQUENCE %d bytes\n", prefix, indent, "",
661 value_length);
662 asn1_debug(prefix, buffer, value_length, indent + 4);
663
664 buffer += value_length;
665 break;
666
667 case CUPS_ASN1_GET_REQUEST :
668 fprintf(stderr, "%s%*sGet-Request-PDU %d bytes\n", prefix, indent, "",
669 value_length);
670 asn1_debug(prefix, buffer, value_length, indent + 4);
671
672 buffer += value_length;
673 break;
674
675 case CUPS_ASN1_GET_RESPONSE :
676 fprintf(stderr, "%s%*sGet-Response-PDU %d bytes\n", prefix, indent,
677 "", value_length);
678 asn1_debug(prefix, buffer, value_length, indent + 4);
679
680 buffer += value_length;
681 break;
682
683 default :
684 fprintf(stderr, "%s%*sUNKNOWN(%x) %d bytes\n", prefix, indent, "",
685 value_type, value_length);
686
687 buffer += value_length;
688 break;
689 }
690 }
691}
692
693
694/*
695 * 'asn1_encode_snmp()' - Encode a SNMP packet.
696 */
697
698static int /* O - Length on success, -1 on error */
699asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */
700 size_t bufsize, /* I - Size of buffer */
701 cups_snmp_t *packet) /* I - SNMP packet */
702{
703 unsigned char *bufptr; /* Pointer into buffer */
704 int total, /* Total length */
705 msglen, /* Length of entire message */
706 commlen, /* Length of community string */
707 reqlen, /* Length of request */
708 listlen, /* Length of variable list */
709 varlen, /* Length of variable */
710 namelen, /* Length of object name OID */
711 valuelen; /* Length of object value */
712
713
714 /*
715 * Get the lengths of the community string, OID, and message...
716 */
717
718 namelen = asn1_size_oid(packet->object_name);
719
720 switch (packet->object_type)
721 {
722 case CUPS_ASN1_NULL_VALUE :
723 valuelen = 0;
724 break;
725
726 case CUPS_ASN1_BOOLEAN :
727 valuelen = asn1_size_integer(packet->object_value.boolean);
728 break;
729
730 case CUPS_ASN1_INTEGER :
731 valuelen = asn1_size_integer(packet->object_value.integer);
732 break;
733
734 case CUPS_ASN1_OCTET_STRING :
735 valuelen = strlen(packet->object_value.string);
736 break;
737
738 case CUPS_ASN1_OID :
739 valuelen = asn1_size_oid(packet->object_value.oid);
740 break;
741
742 default :
743 packet->error = "Unknown object type";
744 return (-1);
745 }
746
747 varlen = 1 + asn1_size_length(namelen) + namelen +
748 1 + asn1_size_length(valuelen) + valuelen;
749 listlen = 1 + asn1_size_length(varlen) + varlen;
750 reqlen = 2 + asn1_size_integer(packet->request_id) +
751 2 + asn1_size_integer(packet->error_status) +
752 2 + asn1_size_integer(packet->error_index) +
753 1 + asn1_size_length(listlen) + listlen;
754 commlen = strlen(packet->community);
755 msglen = 2 + asn1_size_integer(packet->version) +
756 1 + asn1_size_length(commlen) + commlen +
757 1 + asn1_size_length(reqlen) + reqlen;
758 total = 1 + asn1_size_length(msglen) + msglen;
759
760 if (total > bufsize)
761 {
762 packet->error = "Message too large for buffer";
763 return (-1);
764 }
765
766 /*
767 * Then format the message...
768 */
769
770 bufptr = buffer;
771
772 *bufptr++ = CUPS_ASN1_SEQUENCE; /* SNMPv1 message header */
773 asn1_set_length(&bufptr, msglen);
774
775 asn1_set_integer(&bufptr, packet->version);
776 /* version */
777
778 *bufptr++ = CUPS_ASN1_OCTET_STRING; /* community */
779 asn1_set_length(&bufptr, commlen);
780 memcpy(bufptr, packet->community, commlen);
781 bufptr += commlen;
782
783 *bufptr++ = packet->request_type; /* Get-Request-PDU */
784 asn1_set_length(&bufptr, reqlen);
785
786 asn1_set_integer(&bufptr, packet->request_id);
787
788 asn1_set_integer(&bufptr, packet->error_status);
789
790 asn1_set_integer(&bufptr, packet->error_index);
791
792 *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable-bindings */
793 asn1_set_length(&bufptr, listlen);
794
795 *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable */
796 asn1_set_length(&bufptr, varlen);
797
798 asn1_set_oid(&bufptr, packet->object_name);
799 /* ObjectName */
800
801 switch (packet->object_type)
802 {
803 case CUPS_ASN1_NULL_VALUE :
804 *bufptr++ = CUPS_ASN1_NULL_VALUE;
805 /* ObjectValue */
806 *bufptr++ = 0; /* Length */
807 break;
808
809 case CUPS_ASN1_BOOLEAN :
810 asn1_set_integer(&bufptr, packet->object_value.boolean);
811 break;
812
813 case CUPS_ASN1_INTEGER :
814 asn1_set_integer(&bufptr, packet->object_value.integer);
815 break;
816
817 case CUPS_ASN1_OCTET_STRING :
818 *bufptr++ = CUPS_ASN1_OCTET_STRING;
819 asn1_set_length(&bufptr, valuelen);
820 memcpy(bufptr, packet->object_value.string, valuelen);
821 bufptr += valuelen;
822 break;
823
824 case CUPS_ASN1_OID :
825 asn1_set_oid(&bufptr, packet->object_value.oid);
826 break;
827
828 default :
829 break;
830 }
831
832 return (bufptr - buffer);
833}
834
835
836/*
837 * 'asn1_get_integer()' - Get an integer value.
838 */
839
840static int /* O - Integer value */
841asn1_get_integer(
842 unsigned char **buffer, /* IO - Pointer in buffer */
843 unsigned char *bufend, /* I - End of buffer */
844 int length) /* I - Length of value */
845{
846 int value; /* Integer value */
847
848
849 for (value = 0;
850 length > 0 && *buffer < bufend;
851 length --, (*buffer) ++)
852 value = (value << 8) | **buffer;
853
854 return (value);
855}
856
857
858/*
859 * 'asn1_get_length()' - Get a value length.
860 */
861
862static int /* O - Length */
863asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */
864 unsigned char *bufend) /* I - End of buffer */
865{
866 int length; /* Length */
867
868
869 length = **buffer;
870 (*buffer) ++;
871
872 if (length & 128)
873 length = asn1_get_integer(buffer, bufend, length & 127);
874
875 return (length);
876}
877
878
879/*
880 * 'asn1_get_oid()' - Get an OID value.
881 */
882
883static int /* O - Last OID number */
884asn1_get_oid(
885 unsigned char **buffer, /* IO - Pointer in buffer */
886 unsigned char *bufend, /* I - End of buffer */
887 int length, /* I - Length of value */
888 int *oid, /* I - OID buffer */
889 int oidsize) /* I - Size of OID buffer */
890{
891 unsigned char *valend; /* End of value */
892 int *oidend; /* End of OID buffer */
893 int number; /* OID number */
894
895
896 valend = *buffer + length;
897 oidend = oid + oidsize - 1;
898
899 if (valend > bufend)
900 valend = bufend;
901
902 number = asn1_get_packed(buffer, bufend);
903
904 if (number < 80)
905 {
906 *oid++ = number / 40;
907 number = number % 40;
908 *oid++ = number;
909 }
910 else
911 {
912 *oid++ = 2;
913 number -= 80;
914 *oid++ = number;
915 }
916
917 while (*buffer < valend)
918 {
919 number = asn1_get_packed(buffer, bufend);
920
921 if (oid < oidend)
922 *oid++ = number;
923 }
924
925 *oid = 0;
926
927 return (number);
928}
929
930
931/*
932 * 'asn1_get_packed()' - Get a packed integer value.
933 */
934
935static int /* O - Value */
936asn1_get_packed(
937 unsigned char **buffer, /* IO - Pointer in buffer */
938 unsigned char *bufend) /* I - End of buffer */
939{
940 int value; /* Value */
941
942
943 value = 0;
944
945 while ((**buffer & 128) && *buffer < bufend)
946 {
947 value = (value << 7) | (**buffer & 127);
948 (*buffer) ++;
949 }
950
951 if (*buffer < bufend)
952 {
953 value = (value << 7) | **buffer;
954 (*buffer) ++;
955 }
956
957 return (value);
958}
959
960
961/*
962 * 'asn1_get_string()' - Get a string value.
963 */
964
965static char * /* O - String */
966asn1_get_string(
967 unsigned char **buffer, /* IO - Pointer in buffer */
968 unsigned char *bufend, /* I - End of buffer */
969 int length, /* I - Value length */
970 char *string, /* I - String buffer */
971 int strsize) /* I - String buffer size */
972{
973 if (length < 0)
974 {
975 /*
976 * Disallow negative lengths!
977 */
978
979 *string = '\0';
980 }
981 else if (length < strsize)
982 {
983 /*
984 * String is smaller than the buffer...
985 */
986
987 if (length > 0)
988 memcpy(string, *buffer, length);
989
990 string[length] = '\0';
991 }
992 else
993 {
994 /*
995 * String is larger than the buffer...
996 */
997
998 memcpy(string, *buffer, strsize - 1);
999 string[strsize - 1] = '\0';
1000 }
1001
1002 if (length > 0)
1003 (*buffer) += length;
1004
1005 return (length < 0 ? NULL : string);
1006}
1007
1008
1009/*
1010 * 'asn1_get_type()' - Get a value type.
1011 */
1012
1013static int /* O - Type */
1014asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */
1015 unsigned char *bufend) /* I - End of buffer */
1016{
1017 int type; /* Type */
1018
1019
1020 type = **buffer;
1021 (*buffer) ++;
1022
1023 if ((type & 31) == 31)
1024 type = asn1_get_packed(buffer, bufend);
1025
1026 return (type);
1027}
1028
1029
1030/*
1031 * 'asn1_set_integer()' - Set an integer value.
1032 */
1033
1034static void
1035asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */
1036 int integer) /* I - Integer value */
1037{
1038 **buffer = CUPS_ASN1_INTEGER;
1039 (*buffer) ++;
1040
1041 if (integer > 0x7fffff || integer < -0x800000)
1042 {
1043 **buffer = 4;
1044 (*buffer) ++;
1045 **buffer = integer >> 24;
1046 (*buffer) ++;
1047 **buffer = integer >> 16;
1048 (*buffer) ++;
1049 **buffer = integer >> 8;
1050 (*buffer) ++;
1051 **buffer = integer;
1052 (*buffer) ++;
1053 }
1054 else if (integer > 0x7fff || integer < -0x8000)
1055 {
1056 **buffer = 3;
1057 (*buffer) ++;
1058 **buffer = integer >> 16;
1059 (*buffer) ++;
1060 **buffer = integer >> 8;
1061 (*buffer) ++;
1062 **buffer = integer;
1063 (*buffer) ++;
1064 }
1065 else if (integer > 0x7f || integer < -0x80)
1066 {
1067 **buffer = 2;
1068 (*buffer) ++;
1069 **buffer = integer >> 8;
1070 (*buffer) ++;
1071 **buffer = integer;
1072 (*buffer) ++;
1073 }
1074 else
1075 {
1076 **buffer = 1;
1077 (*buffer) ++;
1078 **buffer = integer;
1079 (*buffer) ++;
1080 }
1081}
1082
1083
1084/*
1085 * 'asn1_set_length()' - Set a value length.
1086 */
1087
1088static void
1089asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */
1090 int length) /* I - Length value */
1091{
1092 if (length > 255)
1093 {
1094 **buffer = 0x82; /* 2-byte length */
1095 (*buffer) ++;
1096 **buffer = length >> 8;
1097 (*buffer) ++;
1098 **buffer = length;
1099 (*buffer) ++;
1100 }
1101 else if (length > 127)
1102 {
1103 **buffer = 0x81; /* 1-byte length */
1104 (*buffer) ++;
1105 **buffer = length;
1106 (*buffer) ++;
1107 }
1108 else
1109 {
1110 **buffer = length; /* Length */
1111 (*buffer) ++;
1112 }
1113}
1114
1115
1116/*
1117 * 'asn1_set_oid()' - Set an OID value.
1118 */
1119
1120static void
1121asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */
1122 const int *oid) /* I - OID value */
1123{
1124 **buffer = CUPS_ASN1_OID;
1125 (*buffer) ++;
1126
1127 asn1_set_length(buffer, asn1_size_oid(oid));
1128
1129 asn1_set_packed(buffer, oid[0] * 40 + oid[1]);
1130
1131 for (oid += 2; *oid; oid ++)
1132 asn1_set_packed(buffer, *oid);
1133}
1134
1135
1136/*
1137 * 'asn1_set_packed()' - Set a packed integer value.
1138 */
1139
1140static void
1141asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */
1142 int integer) /* I - Integer value */
1143{
1144 if (integer > 0xfffffff)
1145 {
1146 **buffer = (integer >> 28) & 0x7f;
1147 (*buffer) ++;
1148 }
1149
1150 if (integer > 0x1fffff)
1151 {
1152 **buffer = (integer >> 21) & 0x7f;
1153 (*buffer) ++;
1154 }
1155
1156 if (integer > 0x3fff)
1157 {
1158 **buffer = (integer >> 14) & 0x7f;
1159 (*buffer) ++;
1160 }
1161
1162 if (integer > 0x7f)
1163 {
1164 **buffer = (integer >> 7) & 0x7f;
1165 (*buffer) ++;
1166 }
1167
1168 **buffer = integer & 0x7f;
1169 (*buffer) ++;
1170}
1171
1172
1173/*
1174 * 'asn1_size_integer()' - Figure out the number of bytes needed for an
1175 * integer value.
1176 */
1177
1178static int /* O - Size in bytes */
1179asn1_size_integer(int integer) /* I - Integer value */
1180{
1181 if (integer > 0x7fffff || integer < -0x800000)
1182 return (4);
1183 else if (integer > 0x7fff || integer < -0x8000)
1184 return (3);
1185 else if (integer > 0x7f || integer < -0x80)
1186 return (2);
1187 else
1188 return (1);
1189}
1190
1191
1192/*
1193 * 'asn1_size_length()' - Figure out the number of bytes needed for a
1194 * length value.
1195 */
1196
1197static int /* O - Size in bytes */
1198asn1_size_length(int length) /* I - Length value */
1199{
1200 if (length > 0xff)
1201 return (3);
1202 else if (length > 0x7f)
1203 return (2);
1204 else
1205 return (1);
1206}
1207
1208
1209/*
1210 * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an
1211 * OID value.
1212 */
1213
1214static int /* O - Size in bytes */
1215asn1_size_oid(const int *oid) /* I - OID value */
1216{
1217 int length; /* Length of value */
1218
1219
1220 for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2; *oid; oid ++)
1221 length += asn1_size_packed(*oid);
1222
1223 return (length);
1224}
1225
1226
1227/*
1228 * 'asn1_size_packed()' - Figure out the number of bytes needed for a
1229 * packed integer value.
1230 */
1231
1232static int /* O - Size in bytes */
1233asn1_size_packed(int integer) /* I - Integer value */
1234{
1235 if (integer > 0xfffffff)
1236 return (5);
1237 else if (integer > 0x1fffff)
1238 return (4);
1239 else if (integer > 0x3fff)
1240 return (3);
1241 else if (integer > 0x7f)
1242 return (2);
1243 else
1244 return (1);
1245}
1246
1247
1248/*
1249 * 'snmp_set_error()' - Set the localized error for a packet.
1250 */
1251
1252static void
1253snmp_set_error(cups_snmp_t *packet, /* I - Packet */
1254 const char *message) /* I - Error message */
1255{
1256 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
1257
1258
1259 if (!cg->lang_default)
1260 cg->lang_default = cupsLangDefault();
1261
1262 packet->error = _cupsLangString(cg->lang_default, message);
1263}
1264
1265
1266/*
1267 * End of "$Id$".
1268 */