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