]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / snmp.c
1 /*
2 * "$Id: snmp.c 6495 2007-04-30 21:23:04Z mike $"
3 *
4 * SNMP discovery backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Discover printers via SNMP.
29 * add_array() - Add a string to an array.
30 * add_cache() - Add a cached device...
31 * add_device_uri() - Add a device URI to the cache.
32 * alarm_handler() - Handle alarm signals...
33 * asn1_decode_snmp() - Decode a SNMP packet.
34 * asn1_debug() - Decode an ASN1-encoded message.
35 * asn1_encode_snmp() - Encode a SNMP packet.
36 * asn1_get_integer() - Get an integer value.
37 * asn1_get_length() - Get a value length.
38 * asn1_get_oid() - Get an OID value.
39 * asn1_get_packed() - Get a packed integer value.
40 * asn1_get_string() - Get a string value.
41 * asn1_get_type() - Get a value type.
42 * asn1_set_integer() - Set an integer value.
43 * asn1_set_length() - Set a value length.
44 * asn1_set_oid() - Set an OID value.
45 * asn1_set_packed() - Set a packed integer value.
46 * asn1_size_integer() - Figure out the number of bytes needed for an
47 * integer value.
48 * asn1_size_length() - Figure out the number of bytes needed for a
49 * length value.
50 * asn1_size_oid() - Figure out the numebr of bytes needed for an
51 * OID value.
52 * asn1_size_packed() - Figure out the number of bytes needed for a
53 * packed integer value.
54 * compare_cache() - Compare two cache entries.
55 * debug_printf() - Display some debugging information.
56 * fix_make_model() - Fix common problems in the make-and-model
57 * string.
58 * free_array() - Free an array of strings.
59 * free_cache() - Free the array of cached devices.
60 * get_interface_addresses() - Get the broadcast address(es) associated
61 * with an interface.
62 * hex_debug() - Output hex debugging data...
63 * list_device() - List a device we found...
64 * open_snmp_socket() - Open the SNMP broadcast socket.
65 * password_cb() - Handle authentication requests.
66 * probe_device() - Probe a device to discover whether it is a
67 * printer.
68 * read_snmp_conf() - Read the snmp.conf file.
69 * read_snmp_response() - Read and parse a SNMP response...
70 * run_time() - Return the total running time...
71 * scan_devices() - Scan for devices using SNMP.
72 * send_snmp_query() - Send an SNMP query packet.
73 * try_connect() - Try connecting on a port...
74 * update_cache() - Update a cached device...
75 */
76
77 /*
78 * Include necessary headers.
79 */
80
81 #include <cups/http-private.h>
82 #include "backend-private.h"
83 #include <cups/array.h>
84 #include <cups/file.h>
85 #include <regex.h>
86
87
88 /*
89 * This backend implements SNMP printer discovery. It uses a broadcast-
90 * based approach to get SNMP response packets from potential printers,
91 * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on
92 * the device description string, and finally a probe of port 9100
93 * (AppSocket) and 515 (LPD).
94 *
95 * The current focus is on printers with internal network cards, although
96 * the code also works with many external print servers as well. Future
97 * versions will support scanning for vendor-specific SNMP OIDs and the
98 * new PWG Port Monitor MIB and not just the Host MIB OIDs.
99 *
100 * The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
101 * which can contain comments, blank lines, or any number of the following
102 * directives:
103 *
104 * Address ip-address
105 * Address @LOCAL
106 * Address @IF(name)
107 * Community name
108 * DebugLevel N
109 * DeviceURI "regex pattern" uri
110 * HostNameLookups on
111 * HostNameLookups off
112 * MaxRunTime N
113 *
114 * The default is to use:
115 *
116 * Address @LOCAL
117 * Community public
118 * DebugLevel 0
119 * HostNameLookups off
120 * MaxRunTime 10
121 *
122 * This backend is known to work with the following network printers and
123 * print servers:
124 *
125 * Axis OfficeBasic, 5400, 5600
126 * EPSON
127 * Genicom
128 * HP JetDirect
129 * Lexmark
130 * Sharp
131 * Tektronix
132 * Xerox
133 *
134 * It does not currently work with:
135 *
136 * DLink
137 * Linksys
138 * Netgear
139 * Okidata
140 *
141 * (for all of these, they do not support the Host MIB)
142 */
143
144 /*
145 * Constants...
146 */
147
148 #define SNMP_PORT 161 /* SNMP well-known port */
149 #define SNMP_MAX_OID 64 /* Maximum number of OID numbers */
150 #define SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */
151 #define SNMP_MAX_STRING 512 /* Maximum size of string */
152 #define SNMP_VERSION_1 0 /* SNMPv1 */
153
154 #define ASN1_END_OF_CONTENTS 0x00 /* End-of-contents */
155 #define ASN1_BOOLEAN 0x01 /* BOOLEAN */
156 #define ASN1_INTEGER 0x02 /* INTEGER or ENUMERATION */
157 #define ASN1_BIT_STRING 0x03 /* BIT STRING */
158 #define ASN1_OCTET_STRING 0x04 /* OCTET STRING */
159 #define ASN1_NULL_VALUE 0x05 /* NULL VALUE */
160 #define ASN1_OID 0x06 /* OBJECT IDENTIFIER */
161 #define ASN1_SEQUENCE 0x30 /* SEQUENCE */
162 #define ASN1_GET_REQUEST 0xa0 /* Get-Request-PDU */
163 #define ASN1_GET_RESPONSE 0xa2 /* Get-Response-PDU */
164
165
166 /*
167 * Types...
168 */
169
170 typedef struct device_uri_s /**** DeviceURI values ****/
171 {
172 regex_t re; /* Regular expression to match */
173 cups_array_t *uris; /* URIs */
174 } device_uri_t;
175
176 typedef struct snmp_cache_s /**** SNMP scan cache ****/
177 {
178 http_addr_t address; /* Address of device */
179 char *addrname, /* Name of device */
180 *uri, /* device-uri */
181 *id, /* device-id */
182 *make_and_model; /* device-make-and-model */
183 } snmp_cache_t;
184
185 typedef struct snmp_packet_s /**** SNMP packet ****/
186 {
187 const char *error; /* Encode/decode error */
188 int version; /* Version number */
189 char community[SNMP_MAX_STRING];
190 /* Community name */
191 int request_type; /* Request type */
192 int request_id; /* request-id value */
193 int error_status; /* error-status value */
194 int error_index; /* error-index value */
195 int object_name[SNMP_MAX_OID];
196 /* object-name value */
197 int object_type; /* object-value type */
198 union
199 {
200 int boolean; /* Boolean value */
201 int integer; /* Integer value */
202 int oid[SNMP_MAX_OID]; /* OID value */
203 char string[SNMP_MAX_STRING];/* String value */
204 } object_value; /* object-value value */
205 } snmp_packet_t;
206
207
208 /*
209 * Private CUPS API to set the last error...
210 */
211
212 extern void _cupsSetError(ipp_status_t status, const char *message);
213
214
215 /*
216 * Local functions...
217 */
218
219 static char *add_array(cups_array_t *a, const char *s);
220 static void add_cache(http_addr_t *addr, const char *addrname,
221 const char *uri, const char *id,
222 const char *make_and_model);
223 static device_uri_t *add_device_uri(char *value);
224 static void alarm_handler(int sig);
225 static int asn1_decode_snmp(unsigned char *buffer, size_t len,
226 snmp_packet_t *packet);
227 static void asn1_debug(unsigned char *buffer, size_t len,
228 int indent);
229 static int asn1_encode_snmp(unsigned char *buffer, size_t len,
230 snmp_packet_t *packet);
231 static int asn1_get_integer(unsigned char **buffer,
232 unsigned char *bufend,
233 int length);
234 static int asn1_get_oid(unsigned char **buffer,
235 unsigned char *bufend,
236 int length, int *oid, int oidsize);
237 static int asn1_get_packed(unsigned char **buffer,
238 unsigned char *bufend);
239 static char *asn1_get_string(unsigned char **buffer,
240 unsigned char *bufend,
241 int length, char *string,
242 int strsize);
243 static int asn1_get_length(unsigned char **buffer,
244 unsigned char *bufend);
245 static int asn1_get_type(unsigned char **buffer,
246 unsigned char *bufend);
247 static void asn1_set_integer(unsigned char **buffer,
248 int integer);
249 static void asn1_set_length(unsigned char **buffer,
250 int length);
251 static void asn1_set_oid(unsigned char **buffer,
252 const int *oid);
253 static void asn1_set_packed(unsigned char **buffer,
254 int integer);
255 static int asn1_size_integer(int integer);
256 static int asn1_size_length(int length);
257 static int asn1_size_oid(const int *oid);
258 static int asn1_size_packed(int integer);
259 static int compare_cache(snmp_cache_t *a, snmp_cache_t *b);
260 static void debug_printf(const char *format, ...);
261 static void fix_make_model(char *make_model,
262 const char *old_make_model,
263 int make_model_size);
264 static void free_array(cups_array_t *a);
265 static void free_cache(void);
266 static http_addrlist_t *get_interface_addresses(const char *ifname);
267 static void hex_debug(unsigned char *buffer, size_t len);
268 static void list_device(snmp_cache_t *cache);
269 static int open_snmp_socket(void);
270 static const char *password_cb(const char *prompt);
271 static void probe_device(snmp_cache_t *device);
272 static void read_snmp_conf(const char *address);
273 static void read_snmp_response(int fd);
274 static double run_time(void);
275 static void scan_devices(int fd);
276 static void send_snmp_query(int fd, http_addr_t *addr, int version,
277 const char *community,
278 const unsigned request_id,
279 const int *oid);
280 static int try_connect(http_addr_t *addr, const char *addrname,
281 int port);
282 static void update_cache(snmp_cache_t *device, const char *uri,
283 const char *id, const char *make_model);
284
285
286 /*
287 * Local globals...
288 */
289
290 static cups_array_t *Addresses = NULL;
291 static cups_array_t *Communities = NULL;
292 static cups_array_t *Devices = NULL;
293 static int DebugLevel = 0;
294 static int DeviceDescOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
295 2, 1, 3, 1, 0 };
296 static unsigned DeviceDescRequest;
297 static int DeviceTypeOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
298 2, 1, 2, 1, 0 };
299 static unsigned DeviceTypeRequest;
300 static cups_array_t *DeviceURIs = NULL;
301 static int HostNameLookups = 0;
302 static int MaxRunTime = 10;
303 static struct timeval StartTime;
304
305
306 /*
307 * 'main()' - Discover printers via SNMP.
308 */
309
310 int /* O - Exit status */
311 main(int argc, /* I - Number of command-line arguments (6 or 7) */
312 char *argv[]) /* I - Command-line arguments */
313 {
314 int fd; /* SNMP socket */
315 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
316 struct sigaction action; /* Actions for POSIX signals */
317 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
318
319
320 /*
321 * Check command-line options...
322 */
323
324 if (argc > 2)
325 {
326 fputs(_("Usage: snmp [host-or-ip-address]\n"), stderr);
327 return (1);
328 }
329
330 /*
331 * Set the password callback for IPP operations...
332 */
333
334 cupsSetPasswordCB(password_cb);
335
336 /*
337 * Catch SIGALRM signals...
338 */
339
340 #ifdef HAVE_SIGSET
341 sigset(SIGALRM, alarm_handler);
342 #elif defined(HAVE_SIGACTION)
343 memset(&action, 0, sizeof(action));
344
345 sigemptyset(&action.sa_mask);
346 sigaddset(&action.sa_mask, SIGALRM);
347 action.sa_handler = alarm_handler;
348 sigaction(SIGALRM, &action, NULL);
349 #else
350 signal(SIGALRM, alarm_handler);
351 #endif /* HAVE_SIGSET */
352
353 /*
354 * Open the SNMP socket...
355 */
356
357 if ((fd = open_snmp_socket()) < 0)
358 return (1);
359
360 /*
361 * Read the configuration file and any cache data...
362 */
363
364 read_snmp_conf(argv[1]);
365
366 Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
367
368 /*
369 * Scan for devices...
370 */
371
372 scan_devices(fd);
373
374 /*
375 * Close, free, and return with no errors...
376 */
377
378 close(fd);
379
380 free_array(Addresses);
381 free_array(Communities);
382 free_cache();
383
384 return (0);
385 }
386
387
388 /*
389 * 'add_array()' - Add a string to an array.
390 */
391
392 static char * /* O - New string */
393 add_array(cups_array_t *a, /* I - Array */
394 const char *s) /* I - String to add */
395 {
396 char *dups; /* New string */
397
398
399 dups = strdup(s);
400
401 cupsArrayAdd(a, dups);
402
403 return (dups);
404 }
405
406
407 /*
408 * 'add_cache()' - Add a cached device...
409 */
410
411 static void
412 add_cache(http_addr_t *addr, /* I - Device IP address */
413 const char *addrname, /* I - IP address or name string */
414 const char *uri, /* I - Device URI */
415 const char *id, /* I - 1284 device ID */
416 const char *make_and_model) /* I - Make and model */
417 {
418 snmp_cache_t *temp; /* New device entry */
419
420
421 debug_printf("DEBUG: add_cache(addr=%p, addrname=\"%s\", uri=\"%s\", "
422 "id=\"%s\", make_and_model=\"%s\")\n",
423 addr, addrname, uri ? uri : "(null)", id ? id : "(null)",
424 make_and_model ? make_and_model : "(null)");
425
426 temp = calloc(1, sizeof(snmp_cache_t));
427 memcpy(&(temp->address), addr, sizeof(temp->address));
428
429 temp->addrname = strdup(addrname);
430
431 if (uri)
432 temp->uri = strdup(uri);
433
434 if (id)
435 temp->id = strdup(id);
436
437 if (make_and_model)
438 temp->make_and_model = strdup(make_and_model);
439
440 cupsArrayAdd(Devices, temp);
441
442 if (uri)
443 list_device(temp);
444 }
445
446
447 /*
448 * 'add_device_uri()' - Add a device URI to the cache.
449 *
450 * The value string is modified (chopped up) as needed.
451 */
452
453 static device_uri_t * /* O - Device URI */
454 add_device_uri(char *value) /* I - Value from snmp.conf */
455 {
456 device_uri_t *device_uri; /* Device URI */
457 char *start; /* Start of value */
458
459
460 /*
461 * Allocate memory as needed...
462 */
463
464 if (!DeviceURIs)
465 DeviceURIs = cupsArrayNew(NULL, NULL);
466
467 if (!DeviceURIs)
468 return (NULL);
469
470 if ((device_uri = calloc(1, sizeof(device_uri_t))) == NULL)
471 return (NULL);
472
473 if ((device_uri->uris = cupsArrayNew(NULL, NULL)) == NULL)
474 {
475 free(device_uri);
476 return (NULL);
477 }
478
479 /*
480 * Scan the value string for the regular expression and URI(s)...
481 */
482
483 value ++; /* Skip leading " */
484
485 for (start = value; *value && *value != '\"'; value ++)
486 if (*value == '\\' && value[1])
487 _cups_strcpy(value, value + 1);
488
489 if (!*value)
490 {
491 fputs("ERROR: Missing end quote for DeviceURI!\n", stderr);
492
493 cupsArrayDelete(device_uri->uris);
494 free(device_uri);
495
496 return (NULL);
497 }
498
499 *value++ = '\0';
500
501 if (regcomp(&(device_uri->re), start, REG_EXTENDED | REG_ICASE))
502 {
503 fputs("ERROR: Bad regular expression for DeviceURI!\n", stderr);
504
505 cupsArrayDelete(device_uri->uris);
506 free(device_uri);
507
508 return (NULL);
509 }
510
511 while (*value)
512 {
513 while (isspace(*value & 255))
514 value ++;
515
516 if (!*value)
517 break;
518
519 for (start = value; *value && !isspace(*value & 255); value ++);
520
521 if (*value)
522 *value++ = '\0';
523
524 cupsArrayAdd(device_uri->uris, strdup(start));
525 }
526
527 /*
528 * Add the device URI to the list and return it...
529 */
530
531 cupsArrayAdd(DeviceURIs, device_uri);
532
533 return (device_uri);
534 }
535
536
537 /*
538 * 'alarm_handler()' - Handle alarm signals...
539 */
540
541 static void
542 alarm_handler(int sig) /* I - Signal number */
543 {
544 /*
545 * Do nothing...
546 */
547
548 (void)sig;
549
550 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
551 signal(SIGALRM, alarm_handler);
552 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
553
554 if (DebugLevel)
555 write(2, "DEBUG: ALARM!\n", 14);
556 }
557
558
559 /*
560 * 'asn1_decode_snmp()' - Decode a SNMP packet.
561 */
562
563 static int /* O - 0 on success, -1 on error */
564 asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */
565 size_t len, /* I - Size of buffer */
566 snmp_packet_t *packet) /* I - SNMP packet */
567 {
568 unsigned char *bufptr, /* Pointer into the data */
569 *bufend; /* End of data */
570 int length; /* Length of value */
571
572
573 /*
574 * Initialize the decoding...
575 */
576
577 memset(packet, 0, sizeof(snmp_packet_t));
578
579 bufptr = buffer;
580 bufend = buffer + len;
581
582 if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
583 packet->error = "Packet does not start with SEQUENCE";
584 else if (asn1_get_length(&bufptr, bufend) == 0)
585 packet->error = "SEQUENCE uses indefinite length";
586 else if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
587 packet->error = "No version number";
588 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
589 packet->error = "Version uses indefinite length";
590 else if ((packet->version = asn1_get_integer(&bufptr, bufend, length))
591 != SNMP_VERSION_1)
592 packet->error = "Bad SNMP version number";
593 else if (asn1_get_type(&bufptr, bufend) != ASN1_OCTET_STRING)
594 packet->error = "No community name";
595 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
596 packet->error = "Community name uses indefinite length";
597 else
598 {
599 asn1_get_string(&bufptr, bufend, length, packet->community,
600 sizeof(packet->community));
601
602 if ((packet->request_type = asn1_get_type(&bufptr, bufend))
603 != ASN1_GET_RESPONSE)
604 packet->error = "Packet does not contain a Get-Response-PDU";
605 else if (asn1_get_length(&bufptr, bufend) == 0)
606 packet->error = "Get-Response-PDU uses indefinite length";
607 else if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
608 packet->error = "No request-id";
609 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
610 packet->error = "request-id uses indefinite length";
611 else
612 {
613 packet->request_id = asn1_get_integer(&bufptr, bufend, length);
614
615 if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
616 packet->error = "No error-status";
617 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
618 packet->error = "error-status uses indefinite length";
619 else
620 {
621 packet->error_status = asn1_get_integer(&bufptr, bufend, length);
622
623 if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
624 packet->error = "No error-index";
625 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
626 packet->error = "error-index uses indefinite length";
627 else
628 {
629 packet->error_index = asn1_get_integer(&bufptr, bufend, length);
630
631 if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
632 packet->error = "No variable-bindings SEQUENCE";
633 else if (asn1_get_length(&bufptr, bufend) == 0)
634 packet->error = "variable-bindings uses indefinite length";
635 else if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
636 packet->error = "No VarBind SEQUENCE";
637 else if (asn1_get_length(&bufptr, bufend) == 0)
638 packet->error = "VarBind uses indefinite length";
639 else if (asn1_get_type(&bufptr, bufend) != ASN1_OID)
640 packet->error = "No name OID";
641 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
642 packet->error = "Name OID uses indefinite length";
643 else
644 {
645 asn1_get_oid(&bufptr, bufend, length, packet->object_name,
646 SNMP_MAX_OID);
647
648 packet->object_type = asn1_get_type(&bufptr, bufend);
649
650 if ((length = asn1_get_length(&bufptr, bufend)) == 0 &&
651 packet->object_type != ASN1_NULL_VALUE &&
652 packet->object_type != ASN1_OCTET_STRING)
653 packet->error = "Value uses indefinite length";
654 else
655 {
656 switch (packet->object_type)
657 {
658 case ASN1_BOOLEAN :
659 packet->object_value.boolean =
660 asn1_get_integer(&bufptr, bufend, length);
661 break;
662
663 case ASN1_INTEGER :
664 packet->object_value.integer =
665 asn1_get_integer(&bufptr, bufend, length);
666 break;
667
668 case ASN1_NULL_VALUE :
669 break;
670
671 case ASN1_OCTET_STRING :
672 asn1_get_string(&bufptr, bufend, length,
673 packet->object_value.string,
674 SNMP_MAX_STRING);
675 break;
676
677 case ASN1_OID :
678 asn1_get_oid(&bufptr, bufend, length,
679 packet->object_value.oid, SNMP_MAX_OID);
680 break;
681
682 default :
683 packet->error = "Unsupported value type";
684 break;
685 }
686 }
687 }
688 }
689 }
690 }
691 }
692
693 return (packet->error ? -1 : 0);
694 }
695
696
697 /*
698 * 'asn1_debug()' - Decode an ASN1-encoded message.
699 */
700
701 static void
702 asn1_debug(unsigned char *buffer, /* I - Buffer */
703 size_t len, /* I - Length of buffer */
704 int indent) /* I - Indentation */
705 {
706 int i; /* Looping var */
707 unsigned char *bufend; /* End of buffer */
708 int integer; /* Number value */
709 int oid[SNMP_MAX_OID]; /* OID value */
710 char string[SNMP_MAX_STRING];/* String value */
711 unsigned char value_type; /* Type of value */
712 int value_length; /* Length of value */
713
714
715 bufend = buffer + len;
716
717 while (buffer < bufend)
718 {
719 /*
720 * Get value type...
721 */
722
723 value_type = asn1_get_type(&buffer, bufend);
724 value_length = asn1_get_length(&buffer, bufend);
725
726 switch (value_type)
727 {
728 case ASN1_BOOLEAN :
729 integer = asn1_get_integer(&buffer, bufend, value_length);
730
731 fprintf(stderr, "DEBUG: %*sBOOLEAN %d bytes %d\n", indent, "",
732 value_length, integer);
733 break;
734
735 case ASN1_INTEGER :
736 integer = asn1_get_integer(&buffer, bufend, value_length);
737
738 fprintf(stderr, "DEBUG: %*sINTEGER %d bytes %d\n", indent, "",
739 value_length, integer);
740 break;
741
742 case ASN1_OCTET_STRING :
743 fprintf(stderr, "DEBUG: %*sOCTET STRING %d bytes \"%s\"\n", indent, "",
744 value_length, asn1_get_string(&buffer, bufend,
745 value_length, string,
746 sizeof(string)));
747 break;
748
749 case ASN1_NULL_VALUE :
750 fprintf(stderr, "DEBUG: %*sNULL VALUE %d bytes\n", indent, "",
751 value_length);
752
753 buffer += value_length;
754 break;
755
756 case ASN1_OID :
757 asn1_get_oid(&buffer, bufend, value_length, oid, SNMP_MAX_OID);
758
759 fprintf(stderr, "DEBUG: %*sOID %d bytes ", indent, "",
760 value_length);
761 for (i = 0; oid[i]; i ++)
762 fprintf(stderr, ".%d", oid[i]);
763 putc('\n', stderr);
764 break;
765
766 case ASN1_SEQUENCE :
767 fprintf(stderr, "DEBUG: %*sSEQUENCE %d bytes\n", indent, "",
768 value_length);
769 asn1_debug(buffer, value_length, indent + 4);
770
771 buffer += value_length;
772 break;
773
774 case ASN1_GET_REQUEST :
775 fprintf(stderr, "DEBUG: %*sGet-Request-PDU %d bytes\n", indent, "",
776 value_length);
777 asn1_debug(buffer, value_length, indent + 4);
778
779 buffer += value_length;
780 break;
781
782 case ASN1_GET_RESPONSE :
783 fprintf(stderr, "DEBUG: %*sGet-Response-PDU %d bytes\n", indent, "",
784 value_length);
785 asn1_debug(buffer, value_length, indent + 4);
786
787 buffer += value_length;
788 break;
789
790 default :
791 fprintf(stderr, "DEBUG: %*sUNKNOWN(%x) %d bytes\n", indent, "",
792 value_type, value_length);
793
794 buffer += value_length;
795 break;
796 }
797 }
798 }
799
800
801 /*
802 * 'asn1_encode_snmp()' - Encode a SNMP packet.
803 */
804
805 static int /* O - Length on success, -1 on error */
806 asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */
807 size_t bufsize, /* I - Size of buffer */
808 snmp_packet_t *packet) /* I - SNMP packet */
809 {
810 unsigned char *bufptr; /* Pointer into buffer */
811 int total, /* Total length */
812 msglen, /* Length of entire message */
813 commlen, /* Length of community string */
814 reqlen, /* Length of request */
815 listlen, /* Length of variable list */
816 varlen, /* Length of variable */
817 namelen, /* Length of object name OID */
818 valuelen; /* Length of object value */
819
820
821 /*
822 * Get the lengths of the community string, OID, and message...
823 */
824
825 namelen = asn1_size_oid(packet->object_name);
826
827 switch (packet->object_type)
828 {
829 case ASN1_NULL_VALUE :
830 valuelen = 0;
831 break;
832
833 case ASN1_BOOLEAN :
834 valuelen = asn1_size_integer(packet->object_value.boolean);
835 break;
836
837 case ASN1_INTEGER :
838 valuelen = asn1_size_integer(packet->object_value.integer);
839 break;
840
841 case ASN1_OCTET_STRING :
842 valuelen = strlen(packet->object_value.string);
843 break;
844
845 case ASN1_OID :
846 valuelen = asn1_size_oid(packet->object_value.oid);
847 break;
848
849 default :
850 packet->error = "Unknown object type";
851 return (-1);
852 }
853
854 varlen = 1 + asn1_size_length(namelen) + namelen +
855 1 + asn1_size_length(valuelen) + valuelen;
856 listlen = 1 + asn1_size_length(varlen) + varlen;
857 reqlen = 2 + asn1_size_integer(packet->request_id) +
858 2 + asn1_size_integer(packet->error_status) +
859 2 + asn1_size_integer(packet->error_index) +
860 1 + asn1_size_length(listlen) + listlen;
861 commlen = strlen(packet->community);
862 msglen = 2 + asn1_size_integer(packet->version) +
863 1 + asn1_size_length(commlen) + commlen +
864 1 + asn1_size_length(reqlen) + reqlen;
865 total = 1 + asn1_size_length(msglen) + msglen;
866
867 if (total > bufsize)
868 {
869 packet->error = "Message too large for buffer";
870 return (-1);
871 }
872
873 /*
874 * Then format the message...
875 */
876
877 bufptr = buffer;
878
879 *bufptr++ = ASN1_SEQUENCE; /* SNMPv1 message header */
880 asn1_set_length(&bufptr, msglen);
881
882 asn1_set_integer(&bufptr, packet->version);
883 /* version */
884
885 *bufptr++ = ASN1_OCTET_STRING; /* community */
886 asn1_set_length(&bufptr, commlen);
887 memcpy(bufptr, packet->community, commlen);
888 bufptr += commlen;
889
890 *bufptr++ = packet->request_type; /* Get-Request-PDU */
891 asn1_set_length(&bufptr, reqlen);
892
893 asn1_set_integer(&bufptr, packet->request_id);
894
895 asn1_set_integer(&bufptr, packet->error_status);
896
897 asn1_set_integer(&bufptr, packet->error_index);
898
899 *bufptr++ = ASN1_SEQUENCE; /* variable-bindings */
900 asn1_set_length(&bufptr, listlen);
901
902 *bufptr++ = ASN1_SEQUENCE; /* variable */
903 asn1_set_length(&bufptr, varlen);
904
905 asn1_set_oid(&bufptr, packet->object_name);
906 /* ObjectName */
907
908 switch (packet->object_type)
909 {
910 case ASN1_NULL_VALUE :
911 *bufptr++ = ASN1_NULL_VALUE; /* ObjectValue */
912 *bufptr++ = 0; /* Length */
913 break;
914
915 case ASN1_BOOLEAN :
916 asn1_set_integer(&bufptr, packet->object_value.boolean);
917 break;
918
919 case ASN1_INTEGER :
920 asn1_set_integer(&bufptr, packet->object_value.integer);
921 break;
922
923 case ASN1_OCTET_STRING :
924 *bufptr++ = ASN1_OCTET_STRING;
925 asn1_set_length(&bufptr, valuelen);
926 memcpy(bufptr, packet->object_value.string, valuelen);
927 bufptr += valuelen;
928 break;
929
930 case ASN1_OID :
931 asn1_set_oid(&bufptr, packet->object_value.oid);
932 break;
933 }
934
935 return (bufptr - buffer);
936 }
937
938
939 /*
940 * 'asn1_get_integer()' - Get an integer value.
941 */
942
943 static int /* O - Integer value */
944 asn1_get_integer(
945 unsigned char **buffer, /* IO - Pointer in buffer */
946 unsigned char *bufend, /* I - End of buffer */
947 int length) /* I - Length of value */
948 {
949 int value; /* Integer value */
950
951
952 for (value = 0;
953 length > 0 && *buffer < bufend;
954 length --, (*buffer) ++)
955 value = (value << 8) | **buffer;
956
957 return (value);
958 }
959
960
961 /*
962 * 'asn1_get_length()' - Get a value length.
963 */
964
965 static int /* O - Length */
966 asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */
967 unsigned char *bufend) /* I - End of buffer */
968 {
969 int length; /* Length */
970
971
972 length = **buffer;
973 (*buffer) ++;
974
975 if (length & 128)
976 length = asn1_get_integer(buffer, bufend, length & 127);
977
978 return (length);
979 }
980
981
982 /*
983 * 'asn1_get_oid()' - Get an OID value.
984 */
985
986 static int /* O - Last OID number */
987 asn1_get_oid(
988 unsigned char **buffer, /* IO - Pointer in buffer */
989 unsigned char *bufend, /* I - End of buffer */
990 int length, /* I - Length of value */
991 int *oid, /* I - OID buffer */
992 int oidsize) /* I - Size of OID buffer */
993 {
994 unsigned char *valend; /* End of value */
995 int *oidend; /* End of OID buffer */
996 int number; /* OID number */
997
998
999 valend = *buffer + length;
1000 oidend = oid + oidsize - 1;
1001
1002 if (valend > bufend)
1003 valend = bufend;
1004
1005 number = asn1_get_packed(buffer, bufend);
1006
1007 if (number < 80)
1008 {
1009 *oid++ = number / 40;
1010 number = number % 40;
1011 *oid++ = number;
1012 }
1013 else
1014 {
1015 *oid++ = 2;
1016 number -= 80;
1017 *oid++ = number;
1018 }
1019
1020 while (*buffer < valend)
1021 {
1022 number = asn1_get_packed(buffer, bufend);
1023
1024 if (oid < oidend)
1025 *oid++ = number;
1026 }
1027
1028 *oid = 0;
1029
1030 return (number);
1031 }
1032
1033
1034 /*
1035 * 'asn1_get_packed()' - Get a packed integer value.
1036 */
1037
1038 static int /* O - Value */
1039 asn1_get_packed(
1040 unsigned char **buffer, /* IO - Pointer in buffer */
1041 unsigned char *bufend) /* I - End of buffer */
1042 {
1043 int value; /* Value */
1044
1045
1046 value = 0;
1047
1048 while ((**buffer & 128) && *buffer < bufend)
1049 {
1050 value = (value << 7) | (**buffer & 127);
1051 (*buffer) ++;
1052 }
1053
1054 if (*buffer < bufend)
1055 {
1056 value = (value << 7) | **buffer;
1057 (*buffer) ++;
1058 }
1059
1060 return (value);
1061 }
1062
1063
1064 /*
1065 * 'asn1_get_string()' - Get a string value.
1066 */
1067
1068 static char * /* O - String */
1069 asn1_get_string(
1070 unsigned char **buffer, /* IO - Pointer in buffer */
1071 unsigned char *bufend, /* I - End of buffer */
1072 int length, /* I - Value length */
1073 char *string, /* I - String buffer */
1074 int strsize) /* I - String buffer size */
1075 {
1076 if (length < strsize)
1077 {
1078 memcpy(string, *buffer, length);
1079 string[length] = '\0';
1080 }
1081 else
1082 {
1083 memcpy(string, buffer, strsize - 1);
1084 string[strsize - 1] = '\0';
1085 }
1086
1087 (*buffer) += length;
1088
1089 return (string);
1090 }
1091
1092
1093 /*
1094 * 'asn1_get_type()' - Get a value type.
1095 */
1096
1097 static int /* O - Type */
1098 asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */
1099 unsigned char *bufend) /* I - End of buffer */
1100 {
1101 int type; /* Type */
1102
1103
1104 type = **buffer;
1105 (*buffer) ++;
1106
1107 if ((type & 31) == 31)
1108 type = asn1_get_packed(buffer, bufend);
1109
1110 return (type);
1111 }
1112
1113
1114 /*
1115 * 'asn1_set_integer()' - Set an integer value.
1116 */
1117
1118 static void
1119 asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */
1120 int integer) /* I - Integer value */
1121 {
1122 **buffer = ASN1_INTEGER;
1123 (*buffer) ++;
1124
1125 if (integer > 0x7fffff || integer < -0x800000)
1126 {
1127 **buffer = 4;
1128 (*buffer) ++;
1129 **buffer = integer >> 24;
1130 (*buffer) ++;
1131 **buffer = integer >> 16;
1132 (*buffer) ++;
1133 **buffer = integer >> 8;
1134 (*buffer) ++;
1135 **buffer = integer;
1136 (*buffer) ++;
1137 }
1138 else if (integer > 0x7fff || integer < -0x8000)
1139 {
1140 **buffer = 3;
1141 (*buffer) ++;
1142 **buffer = integer >> 16;
1143 (*buffer) ++;
1144 **buffer = integer >> 8;
1145 (*buffer) ++;
1146 **buffer = integer;
1147 (*buffer) ++;
1148 }
1149 else if (integer > 0x7f || integer < -0x80)
1150 {
1151 **buffer = 2;
1152 (*buffer) ++;
1153 **buffer = integer >> 8;
1154 (*buffer) ++;
1155 **buffer = integer;
1156 (*buffer) ++;
1157 }
1158 else
1159 {
1160 **buffer = 1;
1161 (*buffer) ++;
1162 **buffer = integer;
1163 (*buffer) ++;
1164 }
1165 }
1166
1167
1168 /*
1169 * 'asn1_set_length()' - Set a value length.
1170 */
1171
1172 static void
1173 asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */
1174 int length) /* I - Length value */
1175 {
1176 if (length > 255)
1177 {
1178 **buffer = 0x82; /* 2-byte length */
1179 (*buffer) ++;
1180 **buffer = length >> 8;
1181 (*buffer) ++;
1182 **buffer = length;
1183 (*buffer) ++;
1184 }
1185 else if (length > 127)
1186 {
1187 **buffer = 0x81; /* 1-byte length */
1188 (*buffer) ++;
1189 **buffer = length;
1190 (*buffer) ++;
1191 }
1192 else
1193 {
1194 **buffer = length; /* Length */
1195 (*buffer) ++;
1196 }
1197 }
1198
1199
1200 /*
1201 * 'asn1_set_oid()' - Set an OID value.
1202 */
1203
1204 static void
1205 asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */
1206 const int *oid) /* I - OID value */
1207 {
1208 **buffer = ASN1_OID;
1209 (*buffer) ++;
1210
1211 asn1_set_length(buffer, asn1_size_oid(oid));
1212
1213 asn1_set_packed(buffer, oid[0] * 40 + oid[1]);
1214
1215 for (oid += 2; *oid; oid ++)
1216 asn1_set_packed(buffer, *oid);
1217 }
1218
1219
1220 /*
1221 * 'asn1_set_packed()' - Set a packed integer value.
1222 */
1223
1224 static void
1225 asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */
1226 int integer) /* I - Integer value */
1227 {
1228 if (integer > 0xfffffff)
1229 {
1230 **buffer = (integer >> 28) & 0x7f;
1231 (*buffer) ++;
1232 }
1233
1234 if (integer > 0x1fffff)
1235 {
1236 **buffer = (integer >> 21) & 0x7f;
1237 (*buffer) ++;
1238 }
1239
1240 if (integer > 0x3fff)
1241 {
1242 **buffer = (integer >> 14) & 0x7f;
1243 (*buffer) ++;
1244 }
1245
1246 if (integer > 0x7f)
1247 {
1248 **buffer = (integer >> 7) & 0x7f;
1249 (*buffer) ++;
1250 }
1251
1252 **buffer = integer & 0x7f;
1253 (*buffer) ++;
1254 }
1255
1256 /*
1257 * 'asn1_size_integer()' - Figure out the number of bytes needed for an
1258 * integer value.
1259 */
1260
1261 static int /* O - Size in bytes */
1262 asn1_size_integer(int integer) /* I - Integer value */
1263 {
1264 if (integer > 0x7fffff || integer < -0x800000)
1265 return (4);
1266 else if (integer > 0x7fff || integer < -0x8000)
1267 return (3);
1268 else if (integer > 0x7f || integer < -0x80)
1269 return (2);
1270 else
1271 return (1);
1272 }
1273
1274
1275 /*
1276 * 'asn1_size_length()' - Figure out the number of bytes needed for a
1277 * length value.
1278 */
1279
1280 static int /* O - Size in bytes */
1281 asn1_size_length(int length) /* I - Length value */
1282 {
1283 if (length > 0xff)
1284 return (3);
1285 else if (length > 0x7f)
1286 return (2);
1287 else
1288 return (1);
1289 }
1290
1291
1292 /*
1293 * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an
1294 * OID value.
1295 */
1296
1297 static int /* O - Size in bytes */
1298 asn1_size_oid(const int *oid) /* I - OID value */
1299 {
1300 int length; /* Length of value */
1301
1302
1303 for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2; *oid; oid ++)
1304 length += asn1_size_packed(*oid);
1305
1306 return (length);
1307 }
1308
1309
1310 /*
1311 * 'asn1_size_packed()' - Figure out the number of bytes needed for a
1312 * packed integer value.
1313 */
1314
1315 static int /* O - Size in bytes */
1316 asn1_size_packed(int integer) /* I - Integer value */
1317 {
1318 if (integer > 0xfffffff)
1319 return (5);
1320 else if (integer > 0x1fffff)
1321 return (4);
1322 else if (integer > 0x3fff)
1323 return (3);
1324 else if (integer > 0x7f)
1325 return (2);
1326 else
1327 return (1);
1328 }
1329
1330
1331 /*
1332 * 'compare_cache()' - Compare two cache entries.
1333 */
1334
1335 static int /* O - Result of comparison */
1336 compare_cache(snmp_cache_t *a, /* I - First cache entry */
1337 snmp_cache_t *b) /* I - Second cache entry */
1338 {
1339 return (strcasecmp(a->addrname, b->addrname));
1340 }
1341
1342
1343 /*
1344 * 'debug_printf()' - Display some debugging information.
1345 */
1346
1347 static void
1348 debug_printf(const char *format, /* I - Printf-style format string */
1349 ...) /* I - Additional arguments as needed */
1350 {
1351 va_list ap; /* Pointer to arguments */
1352
1353
1354 if (!DebugLevel)
1355 return;
1356
1357 va_start(ap, format);
1358 vfprintf(stderr, format, ap);
1359 va_end(ap);
1360 }
1361
1362
1363 /*
1364 * 'fix_make_model()' - Fix common problems in the make-and-model string.
1365 */
1366
1367 static void
1368 fix_make_model(
1369 char *make_model, /* I - New make-and-model string */
1370 const char *old_make_model, /* I - Old make-and-model string */
1371 int make_model_size) /* I - Size of new string buffer */
1372 {
1373 char *mmptr; /* Pointer into make-and-model string */
1374
1375
1376 /*
1377 * Fix some common problems with the make-and-model string so
1378 * that printer driver detection works better...
1379 */
1380
1381 if (!strncasecmp(old_make_model, "Hewlett-Packard", 15))
1382 {
1383 /*
1384 * Strip leading Hewlett-Packard and hp prefixes and replace
1385 * with a single HP manufacturer prefix...
1386 */
1387
1388 mmptr = (char *)old_make_model + 15;
1389
1390 while (isspace(*mmptr & 255))
1391 mmptr ++;
1392
1393 if (!strncasecmp(mmptr, "hp", 2))
1394 {
1395 mmptr += 2;
1396
1397 while (isspace(*mmptr & 255))
1398 mmptr ++;
1399 }
1400
1401 make_model[0] = 'H';
1402 make_model[1] = 'P';
1403 make_model[2] = ' ';
1404 strlcpy(make_model + 3, mmptr, make_model_size - 3);
1405 }
1406 else if (!strncasecmp(old_make_model, "deskjet", 7))
1407 snprintf(make_model, make_model_size, "HP DeskJet%s", old_make_model + 7);
1408 else if (!strncasecmp(old_make_model, "officejet", 9))
1409 snprintf(make_model, make_model_size, "HP OfficeJet%s", old_make_model + 9);
1410 else if (!strncasecmp(old_make_model, "stylus_pro_", 11))
1411 snprintf(make_model, make_model_size, "EPSON Stylus Pro %s",
1412 old_make_model + 11);
1413 else
1414 strlcpy(make_model, old_make_model, make_model_size);
1415
1416 if ((mmptr = strstr(make_model, ", Inc.,")) != NULL)
1417 {
1418 /*
1419 * Strip inc. from name, e.g. "Tektronix, Inc., Phaser 560"
1420 * becomes "Tektronix Phaser 560"...
1421 */
1422
1423 _cups_strcpy(mmptr, mmptr + 7);
1424 }
1425
1426 if ((mmptr = strstr(make_model, " Network")) != NULL)
1427 {
1428 /*
1429 * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
1430 * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
1431 */
1432
1433 *mmptr = '\0';
1434 }
1435
1436 if ((mmptr = strchr(make_model, ',')) != NULL)
1437 {
1438 /*
1439 * Drop anything after a trailing comma...
1440 */
1441
1442 *mmptr = '\0';
1443 }
1444 }
1445
1446
1447 /*
1448 * 'free_array()' - Free an array of strings.
1449 */
1450
1451 static void
1452 free_array(cups_array_t *a) /* I - Array */
1453 {
1454 char *s; /* Current string */
1455
1456
1457 for (s = (char *)cupsArrayFirst(a); s; s = (char *)cupsArrayNext(a))
1458 free(s);
1459
1460 cupsArrayDelete(a);
1461 }
1462
1463
1464 /*
1465 * 'free_cache()' - Free the array of cached devices.
1466 */
1467
1468 static void
1469 free_cache(void)
1470 {
1471 snmp_cache_t *cache; /* Cached device */
1472
1473
1474 for (cache = (snmp_cache_t *)cupsArrayFirst(Devices);
1475 cache;
1476 cache = (snmp_cache_t *)cupsArrayNext(Devices))
1477 {
1478 free(cache->addrname);
1479
1480 if (cache->uri)
1481 free(cache->uri);
1482
1483 if (cache->id)
1484 free(cache->id);
1485
1486 if (cache->make_and_model)
1487 free(cache->make_and_model);
1488
1489 free(cache);
1490 }
1491
1492 cupsArrayDelete(Devices);
1493 Devices = NULL;
1494 }
1495
1496
1497 /*
1498 * 'get_interface_addresses()' - Get the broadcast address(es) associated
1499 * with an interface.
1500 */
1501
1502 static http_addrlist_t * /* O - List of addresses */
1503 get_interface_addresses(
1504 const char *ifname) /* I - Interface name */
1505 {
1506 struct ifaddrs *addrs, /* Interface address list */
1507 *addr; /* Current interface address */
1508 http_addrlist_t *first, /* First address in list */
1509 *last, /* Last address in list */
1510 *current; /* Current address */
1511
1512
1513 if (getifaddrs(&addrs) < 0)
1514 return (NULL);
1515
1516 for (addr = addrs, first = NULL, last = NULL; addr; addr = addr->ifa_next)
1517 if ((addr->ifa_flags & IFF_BROADCAST) && addr->ifa_broadaddr &&
1518 addr->ifa_broadaddr->sa_family == AF_INET &&
1519 (!ifname || !strcmp(ifname, addr->ifa_name)))
1520 {
1521 current = calloc(1, sizeof(http_addrlist_t));
1522
1523 memcpy(&(current->addr), addr->ifa_broadaddr,
1524 sizeof(struct sockaddr_in));
1525
1526 if (!last)
1527 first = current;
1528 else
1529 last->next = current;
1530
1531 last = current;
1532 }
1533
1534 freeifaddrs(addrs);
1535
1536 return (first);
1537 }
1538
1539
1540 /*
1541 * 'hex_debug()' - Output hex debugging data...
1542 */
1543
1544 static void
1545 hex_debug(unsigned char *buffer, /* I - Buffer */
1546 size_t len) /* I - Number of bytes */
1547 {
1548 int col; /* Current column */
1549
1550
1551 fputs("DEBUG: Hex dump of packet:\n", stderr);
1552
1553 for (col = 0; len > 0; col ++, buffer ++, len --)
1554 {
1555 if ((col & 15) == 0)
1556 fprintf(stderr, "DEBUG: %04X ", col);
1557
1558 fprintf(stderr, " %02X", *buffer);
1559
1560 if ((col & 15) == 15)
1561 putc('\n', stderr);
1562 }
1563
1564 if (col & 15)
1565 putc('\n', stderr);
1566 }
1567
1568
1569 /*
1570 * 'list_device()' - List a device we found...
1571 */
1572
1573 static void
1574 list_device(snmp_cache_t *cache) /* I - Cached device */
1575 {
1576 if (cache->uri)
1577 printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
1578 cache->uri,
1579 cache->make_and_model ? cache->make_and_model : "Unknown",
1580 cache->make_and_model ? cache->make_and_model : "Unknown",
1581 cache->addrname, cache->id ? cache->id : "");
1582 }
1583
1584
1585 /*
1586 * 'open_snmp_socket()' - Open the SNMP broadcast socket.
1587 */
1588
1589 static int /* O - SNMP socket file descriptor */
1590 open_snmp_socket(void)
1591 {
1592 int fd; /* SNMP socket file descriptor */
1593 int val; /* Socket option value */
1594
1595
1596 /*
1597 * Create the SNMP socket...
1598 */
1599
1600 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1601 {
1602 fprintf(stderr, "ERROR: Unable to create SNMP socket - %s\n",
1603 strerror(errno));
1604
1605 return (-1);
1606 }
1607
1608 /*
1609 * Set the "broadcast" flag...
1610 */
1611
1612 val = 1;
1613
1614 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1615 {
1616 fprintf(stderr, "ERROR: Unable to set broadcast mode - %s\n",
1617 strerror(errno));
1618
1619 close(fd);
1620
1621 return (-1);
1622 }
1623
1624 return (fd);
1625 }
1626
1627
1628 /*
1629 * 'password_cb()' - Handle authentication requests.
1630 *
1631 * All we do right now is return NULL, indicating that no authentication
1632 * is possible.
1633 */
1634
1635 static const char * /* O - Password (NULL) */
1636 password_cb(const char *prompt) /* I - Prompt message */
1637 {
1638 (void)prompt; /* Anti-compiler-warning-code */
1639
1640 return (NULL);
1641 }
1642
1643
1644 /*
1645 * 'probe_device()' - Probe a device to discover whether it is a printer.
1646 *
1647 * TODO: Try using the Port Monitor MIB to discover the correct protocol
1648 * to use - first need a commercially-available printer that supports
1649 * it, though...
1650 */
1651
1652 static void
1653 probe_device(snmp_cache_t *device) /* I - Device */
1654 {
1655 char uri[1024], /* Full device URI */
1656 *uriptr, /* Pointer into URI */
1657 *format; /* Format string for device */
1658 device_uri_t *device_uri; /* Current DeviceURI match */
1659
1660
1661 debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);
1662
1663 #ifdef __APPLE__
1664 /*
1665 * TODO: Try an mDNS query first, and then fallback on direct probes...
1666 */
1667
1668 if (!try_connect(&(device->address), device->addrname, 5353))
1669 {
1670 debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device->addrname);
1671 return;
1672 }
1673 #endif /* __APPLE__ */
1674
1675 /*
1676 * Lookup the device in the match table...
1677 */
1678
1679 for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs);
1680 device_uri;
1681 device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs))
1682 if (!regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0))
1683 {
1684 /*
1685 * Found a match, add the URIs...
1686 */
1687
1688 for (format = (char *)cupsArrayFirst(device_uri->uris);
1689 format;
1690 format = (char *)cupsArrayNext(device_uri->uris))
1691 {
1692 for (uriptr = uri; *format && uriptr < (uri + sizeof(uri) - 1);)
1693 if (*format == '%' && format[1] == 's')
1694 {
1695 /*
1696 * Insert hostname/address...
1697 */
1698
1699 strlcpy(uriptr, device->addrname, sizeof(uri) - (uriptr - uri));
1700 uriptr += strlen(uriptr);
1701 format += 2;
1702 }
1703 else
1704 *uriptr++ = *format++;
1705
1706 *uriptr = '\0';
1707
1708 update_cache(device, uri, NULL, NULL);
1709 }
1710
1711 return;
1712 }
1713
1714 /*
1715 * Then try the standard ports...
1716 */
1717
1718 if (!try_connect(&(device->address), device->addrname, 9100))
1719 {
1720 debug_printf("DEBUG: %s supports AppSocket!\n", device->addrname);
1721
1722 snprintf(uri, sizeof(uri), "socket://%s", device->addrname);
1723 update_cache(device, uri, NULL, NULL);
1724 }
1725 else if (!try_connect(&(device->address), device->addrname, 515))
1726 {
1727 debug_printf("DEBUG: %s supports LPD!\n", device->addrname);
1728
1729 snprintf(uri, sizeof(uri), "lpd://%s/", device->addrname);
1730 update_cache(device, uri, NULL, NULL);
1731 }
1732 }
1733
1734
1735 /*
1736 * 'read_snmp_conf()' - Read the snmp.conf file.
1737 */
1738
1739 static void
1740 read_snmp_conf(const char *address) /* I - Single address to probe */
1741 {
1742 cups_file_t *fp; /* File pointer */
1743 char filename[1024], /* Filename */
1744 line[1024], /* Line from file */
1745 *value; /* Value on line */
1746 int linenum; /* Line number */
1747 const char *cups_serverroot; /* CUPS_SERVERROOT env var */
1748 const char *debug; /* CUPS_DEBUG_LEVEL env var */
1749 const char *runtime; /* CUPS_MAX_RUN_TIME env var */
1750
1751
1752 /*
1753 * Initialize the global address and community lists...
1754 */
1755
1756 Addresses = cupsArrayNew(NULL, NULL);
1757 Communities = cupsArrayNew(NULL, NULL);
1758
1759 if (address)
1760 add_array(Addresses, address);
1761
1762 if ((debug = getenv("CUPS_DEBUG_LEVEL")) != NULL)
1763 DebugLevel = atoi(debug);
1764
1765 if ((runtime = getenv("CUPS_MAX_RUN_TIME")) != NULL)
1766 MaxRunTime = atoi(runtime);
1767
1768 /*
1769 * Find the snmp.conf file...
1770 */
1771
1772 if ((cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
1773 cups_serverroot = CUPS_SERVERROOT;
1774
1775 snprintf(filename, sizeof(filename), "%s/snmp.conf", cups_serverroot);
1776
1777 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1778 {
1779 /*
1780 * Read the snmp.conf file...
1781 */
1782
1783 linenum = 0;
1784
1785 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
1786 {
1787 if (!value)
1788 fprintf(stderr, "ERROR: Missing value on line %d of %s!\n", linenum,
1789 filename);
1790 else if (!strcasecmp(line, "Address"))
1791 {
1792 if (!address)
1793 add_array(Addresses, value);
1794 }
1795 else if (!strcasecmp(line, "Community"))
1796 add_array(Communities, value);
1797 else if (!strcasecmp(line, "DebugLevel"))
1798 DebugLevel = atoi(value);
1799 else if (!strcasecmp(line, "DeviceURI"))
1800 {
1801 if (*value != '\"')
1802 fprintf(stderr,
1803 "ERROR: Missing double quote for regular expression on "
1804 "line %d of %s!\n", linenum, filename);
1805 else
1806 add_device_uri(value);
1807 }
1808 else if (!strcasecmp(line, "HostNameLookups"))
1809 HostNameLookups = !strcasecmp(value, "on") ||
1810 !strcasecmp(value, "yes") ||
1811 !strcasecmp(value, "true") ||
1812 !strcasecmp(value, "double");
1813 else if (!strcasecmp(line, "MaxRunTime"))
1814 MaxRunTime = atoi(value);
1815 else
1816 fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n",
1817 line, linenum, filename);
1818 }
1819
1820 cupsFileClose(fp);
1821 }
1822
1823 /*
1824 * Use defaults if parameters are undefined...
1825 */
1826
1827 if (cupsArrayCount(Addresses) == 0)
1828 {
1829 fputs("INFO: Using default SNMP Address @LOCAL\n", stderr);
1830 add_array(Addresses, "@LOCAL");
1831 }
1832
1833 if (cupsArrayCount(Communities) == 0)
1834 {
1835 fputs("INFO: Using default SNMP Community public\n", stderr);
1836 add_array(Communities, "public");
1837 }
1838 }
1839
1840
1841 /*
1842 * 'read_snmp_response()' - Read and parse a SNMP response...
1843 */
1844
1845 static void
1846 read_snmp_response(int fd) /* I - SNMP socket file descriptor */
1847 {
1848 unsigned char buffer[SNMP_MAX_PACKET];/* Data packet */
1849 int bytes; /* Number of bytes received */
1850 http_addr_t addr; /* Source address */
1851 socklen_t addrlen; /* Source address length */
1852 char addrname[256]; /* Source address name */
1853 snmp_packet_t packet; /* Decoded packet */
1854 snmp_cache_t key, /* Search key */
1855 *device; /* Matching device */
1856
1857
1858 /*
1859 * Read the response data...
1860 */
1861
1862 addrlen = sizeof(addr);
1863
1864 if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (void *)&addr,
1865 &addrlen)) < 0)
1866 {
1867 fprintf(stderr, "ERROR: Unable to read data from socket: %s\n",
1868 strerror(errno));
1869 return;
1870 }
1871
1872 if (HostNameLookups)
1873 httpAddrLookup(&addr, addrname, sizeof(addrname));
1874 else
1875 httpAddrString(&addr, addrname, sizeof(addrname));
1876
1877 debug_printf("DEBUG: %.3f Received %d bytes from %s...\n", run_time(),
1878 bytes, addrname);
1879
1880 /*
1881 * Look for the response status code in the SNMP message header...
1882 */
1883
1884 if (asn1_decode_snmp(buffer, bytes, &packet))
1885 {
1886 fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n",
1887 addrname, packet.error);
1888
1889 asn1_debug(buffer, bytes, 0);
1890 hex_debug(buffer, bytes);
1891
1892 return;
1893 }
1894
1895 debug_printf("DEBUG: community=\"%s\"\n", packet.community);
1896 debug_printf("DEBUG: request-id=%d\n", packet.request_id);
1897 debug_printf("DEBUG: error-status=%d\n", packet.error_status);
1898
1899 if (DebugLevel > 1)
1900 asn1_debug(buffer, bytes, 0);
1901
1902 if (DebugLevel > 2)
1903 hex_debug(buffer, bytes);
1904
1905 if (packet.error_status)
1906 return;
1907
1908 /*
1909 * Find a matching device in the cache...
1910 */
1911
1912 key.addrname = addrname;
1913 device = (snmp_cache_t *)cupsArrayFind(Devices, &key);
1914
1915 /*
1916 * Process the message...
1917 */
1918
1919 if (packet.request_id == DeviceTypeRequest)
1920 {
1921 /*
1922 * Got the device type response...
1923 */
1924
1925 if (device)
1926 {
1927 debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
1928 addrname);
1929 return;
1930 }
1931
1932 /*
1933 * Add the device and request the device description...
1934 */
1935
1936 add_cache(&addr, addrname, NULL, NULL, NULL);
1937
1938 send_snmp_query(fd, &addr, SNMP_VERSION_1, packet.community,
1939 DeviceDescRequest, DeviceDescOID);
1940 }
1941 else if (packet.request_id == DeviceDescRequest &&
1942 packet.object_type == ASN1_OCTET_STRING)
1943 {
1944 /*
1945 * Update an existing cache entry...
1946 */
1947
1948 char make_model[256]; /* Make and model */
1949
1950
1951 if (!device)
1952 {
1953 debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
1954 addrname);
1955 return;
1956 }
1957
1958 /*
1959 * Convert the description to a make and model string...
1960 */
1961
1962 if (strchr(packet.object_value.string, ':') &&
1963 strchr(packet.object_value.string, ';'))
1964 {
1965 /*
1966 * Description is the IEEE-1284 device ID...
1967 */
1968
1969 backendGetMakeModel(packet.object_value.string, make_model,
1970 sizeof(make_model));
1971 }
1972 else
1973 {
1974 /*
1975 * Description is plain text...
1976 */
1977
1978 fix_make_model(make_model, packet.object_value.string,
1979 sizeof(make_model));
1980 }
1981
1982 if (device->make_and_model)
1983 free(device->make_and_model);
1984
1985 device->make_and_model = strdup(make_model);
1986 }
1987 }
1988
1989
1990 /*
1991 * 'run_time()' - Return the total running time...
1992 */
1993
1994 static double /* O - Number of seconds */
1995 run_time(void)
1996 {
1997 struct timeval curtime; /* Current time */
1998
1999
2000 gettimeofday(&curtime, NULL);
2001
2002 return (curtime.tv_sec - StartTime.tv_sec +
2003 0.000001 * (curtime.tv_usec - StartTime.tv_usec));
2004 }
2005
2006
2007 /*
2008 * 'scan_devices()' - Scan for devices using SNMP.
2009 */
2010
2011 static void
2012 scan_devices(int fd) /* I - SNMP socket */
2013 {
2014 char *address, /* Current address */
2015 *community; /* Current community */
2016 fd_set input; /* Input set for select() */
2017 struct timeval timeout; /* Timeout for select() */
2018 time_t endtime; /* End time for scan */
2019 http_addrlist_t *addrs, /* List of addresses */
2020 *addr; /* Current address */
2021 snmp_cache_t *device; /* Current device */
2022
2023
2024 /*
2025 * Setup the request IDs...
2026 */
2027
2028 gettimeofday(&StartTime, NULL);
2029
2030 DeviceTypeRequest = StartTime.tv_sec;
2031 DeviceDescRequest = StartTime.tv_sec + 1;
2032
2033 /*
2034 * First send all of the broadcast queries...
2035 */
2036
2037 for (address = (char *)cupsArrayFirst(Addresses);
2038 address;
2039 address = (char *)cupsArrayNext(Addresses))
2040 {
2041 if (!strcmp(address, "@LOCAL"))
2042 addrs = get_interface_addresses(NULL);
2043 else if (!strncmp(address, "@IF(", 4))
2044 {
2045 char ifname[255]; /* Interface name */
2046
2047
2048 strlcpy(ifname, address + 4, sizeof(ifname));
2049 if (ifname[0])
2050 ifname[strlen(ifname) - 1] = '\0';
2051
2052 addrs = get_interface_addresses(ifname);
2053 }
2054 else
2055 addrs = httpAddrGetList(address, AF_INET, NULL);
2056
2057 if (!addrs)
2058 {
2059 fprintf(stderr, "ERROR: Unable to scan \"%s\"!\n", address);
2060 continue;
2061 }
2062
2063 for (community = (char *)cupsArrayFirst(Communities);
2064 community;
2065 community = (char *)cupsArrayNext(Communities))
2066 {
2067 debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n",
2068 community, address);
2069
2070 for (addr = addrs; addr; addr = addr->next)
2071 send_snmp_query(fd, &(addr->addr), SNMP_VERSION_1, community,
2072 DeviceTypeRequest, DeviceTypeOID);
2073 }
2074
2075 httpAddrFreeList(addrs);
2076 }
2077
2078 /*
2079 * Then read any responses that come in over the next 3 seconds...
2080 */
2081
2082 endtime = time(NULL) + 3;
2083
2084 FD_ZERO(&input);
2085
2086 while (time(NULL) < endtime)
2087 {
2088 timeout.tv_sec = 1;
2089 timeout.tv_usec = 0;
2090
2091 FD_SET(fd, &input);
2092 if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
2093 {
2094 fprintf(stderr, "ERROR: %.3f select() for %d failed: %s\n", run_time(),
2095 fd, strerror(errno));
2096 break;
2097 }
2098
2099 if (FD_ISSET(fd, &input))
2100 read_snmp_response(fd);
2101 else
2102 break;
2103 }
2104
2105 /*
2106 * Finally, probe all of the printers we discovered to see how they are
2107 * connected...
2108 */
2109
2110 for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
2111 device;
2112 device = (snmp_cache_t *)cupsArrayNext(Devices))
2113 if (MaxRunTime > 0 && run_time() >= MaxRunTime)
2114 break;
2115 else if (!device->uri)
2116 probe_device(device);
2117
2118 debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
2119 }
2120
2121
2122 /*
2123 * 'send_snmp_query()' - Send an SNMP query packet.
2124 */
2125
2126 static void
2127 send_snmp_query(
2128 int fd, /* I - SNMP socket */
2129 http_addr_t *addr, /* I - Address to send to */
2130 int version, /* I - SNMP version */
2131 const char *community, /* I - Community name */
2132 const unsigned request_id, /* I - Request ID */
2133 const int *oid) /* I - OID */
2134 {
2135 int i; /* Looping var */
2136 snmp_packet_t packet; /* SNMP message packet */
2137 unsigned char buffer[SNMP_MAX_PACKET];/* SNMP message buffer */
2138 int bytes; /* Size of message */
2139 char addrname[32]; /* Address name */
2140
2141
2142 /*
2143 * Create the SNMP message...
2144 */
2145
2146 memset(&packet, 0, sizeof(packet));
2147
2148 packet.version = version;
2149 packet.request_type = ASN1_GET_REQUEST;
2150 packet.request_id = request_id;
2151 packet.object_type = ASN1_NULL_VALUE;
2152
2153 strlcpy(packet.community, community, sizeof(packet.community));
2154
2155 for (i = 0; oid[i]; i ++)
2156 packet.object_name[i] = oid[i];
2157
2158 bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);
2159
2160 if (bytes < 0)
2161 {
2162 fprintf(stderr, "ERROR: Unable to send SNMP query: %s\n",
2163 packet.error);
2164 return;
2165 }
2166
2167 /*
2168 * Send the message...
2169 */
2170
2171 debug_printf("DEBUG: %.3f Sending %d bytes to %s...\n", run_time(),
2172 bytes, httpAddrString(addr, addrname, sizeof(addrname)));
2173 if (DebugLevel > 1)
2174 asn1_debug(buffer, bytes, 0);
2175 if (DebugLevel > 2)
2176 hex_debug(buffer, bytes);
2177
2178 addr->ipv4.sin_port = htons(SNMP_PORT);
2179
2180 if (sendto(fd, buffer, bytes, 0, (void *)addr, sizeof(addr->ipv4)) < bytes)
2181 fprintf(stderr, "ERROR: Unable to send %d bytes to %s: %s\n",
2182 bytes, addrname, strerror(errno));
2183 }
2184
2185
2186 /*
2187 * 'try_connect()' - Try connecting on a port...
2188 */
2189
2190 static int /* O - 0 on success or -1 on error */
2191 try_connect(http_addr_t *addr, /* I - Socket address */
2192 const char *addrname, /* I - Hostname or IP address */
2193 int port) /* I - Port number */
2194 {
2195 int fd; /* Socket */
2196 int status; /* Connection status */
2197
2198
2199 debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(),
2200 port == 515 ? "lpd" : "socket", addrname, port);
2201
2202 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
2203 {
2204 fprintf(stderr, "ERROR: Unable to create socket: %s\n",
2205 strerror(errno));
2206 return (-1);
2207 }
2208
2209 addr->ipv4.sin_port = htons(port);
2210
2211 alarm(1);
2212
2213 status = connect(fd, (void *)addr, httpAddrLength(addr));
2214
2215 close(fd);
2216 alarm(0);
2217
2218 return (status);
2219 }
2220
2221
2222 /*
2223 * 'update_cache()' - Update a cached device...
2224 */
2225
2226 static void
2227 update_cache(snmp_cache_t *device, /* I - Device */
2228 const char *uri, /* I - Device URI */
2229 const char *id, /* I - Device ID */
2230 const char *make_model) /* I - Device make and model */
2231 {
2232 if (device->uri)
2233 free(device->uri);
2234
2235 device->uri = strdup(uri);
2236
2237 if (id)
2238 {
2239 if (device->id)
2240 free(device->id);
2241
2242 device->id = strdup(id);
2243 }
2244
2245 if (make_model)
2246 {
2247 if (device->make_and_model)
2248 free(device->make_and_model);
2249
2250 device->make_and_model = strdup(make_model);
2251 }
2252
2253 list_device(device);
2254 }
2255
2256
2257 /*
2258 * End of "$Id: snmp.c 6495 2007-04-30 21:23:04Z mike $".
2259 */