]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
Merge CUPS 1.4svn-r7524.
[thirdparty/cups.git] / scheduler / dirsvc.c
1 /*
2 * "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $"
3 *
4 * Directory services routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 */
18
19 /*
20 * Include necessary headers...
21 */
22
23 #include "cupsd.h"
24 #include <grp.h>
25
26 #ifdef HAVE_DNSSD
27 # include <dns_sd.h>
28 # ifdef __APPLE__
29 # include <nameser.h>
30 # ifdef HAVE_COREFOUNDATION
31 # include <CoreFoundation/CoreFoundation.h>
32 # endif /* HAVE_COREFOUNDATION */
33 # ifdef HAVE_SYSTEMCONFIGURATION
34 # include <SystemConfiguration/SystemConfiguration.h>
35 # endif /* HAVE_SYSTEMCONFIGURATION */
36 # endif /* __APPLE__ */
37 #endif /* HAVE_DNSSD */
38
39
40 /*
41 * Local functions...
42 */
43
44 static char *dequote(char *d, const char *s, int dlen);
45 #ifdef __APPLE__
46 static int get_hostconfig(const char *name);
47 #endif /* __APPLE__ */
48 static int is_local_queue(const char *uri, char *host, int hostlen,
49 char *resource, int resourcelen);
50 static void process_browse_data(const char *uri, const char *host,
51 const char *resource, cups_ptype_t type,
52 ipp_pstate_t state, const char *location,
53 const char *info, const char *make_model,
54 int num_attrs, cups_option_t *attrs);
55 static void process_implicit_classes(void);
56 static void send_cups_browse(cupsd_printer_t *p);
57 #ifdef HAVE_LDAP
58 static void send_ldap_browse(cupsd_printer_t *p);
59 #endif /* HAVE_LDAP */
60 #ifdef HAVE_LIBSLP
61 static void send_slp_browse(cupsd_printer_t *p);
62 #endif /* HAVE_LIBSLP */
63 static void update_cups_browse(void);
64 static void update_lpd(int onoff);
65 static void update_polling(void);
66 static void update_smb(int onoff);
67
68
69 #ifdef HAVE_DNSSD
70 static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
71 int for_lpd);
72 static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
73 static void dnssdDeregisterPrinter(cupsd_printer_t *p);
74 static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
75 int count);
76 static void dnssdRegisterCallback(DNSServiceRef sdRef,
77 DNSServiceFlags flags,
78 DNSServiceErrorType errorCode,
79 const char *name, const char *regtype,
80 const char *domain, void *context);
81 static void dnssdRegisterPrinter(cupsd_printer_t *p);
82 #endif /* HAVE_DNSSD */
83
84 #ifdef HAVE_OPENLDAP
85 static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
86 {
87 "printerDescription",
88 "printerLocation",
89 "printerMakeAndModel",
90 "printerType",
91 "printerURI",
92 NULL
93 };
94 #endif /* HAVE_OPENLDAP */
95
96 #ifdef HAVE_LIBSLP
97 /*
98 * SLP definitions...
99 */
100
101 /*
102 * SLP service name for CUPS...
103 */
104
105 # define SLP_CUPS_SRVTYPE "service:printer"
106 # define SLP_CUPS_SRVLEN 15
107
108
109 /*
110 * Printer service URL structure
111 */
112
113 typedef struct _slpsrvurl_s /**** SLP URL list ****/
114 {
115 struct _slpsrvurl_s *next; /* Next URL in list */
116 char url[HTTP_MAX_URI];
117 /* URL */
118 } slpsrvurl_t;
119
120
121 /*
122 * Local functions...
123 */
124
125 static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
126 SLPError errcode, void *cookie);
127 static void slp_dereg_printer(cupsd_printer_t *p);
128 static int slp_get_attr(const char *attrlist, const char *tag,
129 char **valbuf);
130 static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
131 void *cookie);
132 static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
133 unsigned short lifetime,
134 SLPError errcode, void *cookie);
135 #endif /* HAVE_LIBSLP */
136
137
138 /*
139 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
140 * local printer and remove any pending
141 * references to remote printers.
142 */
143
144 void
145 cupsdDeregisterPrinter(
146 cupsd_printer_t *p, /* I - Printer to register */
147 int removeit) /* I - Printer being permanently removed */
148 {
149 /*
150 * Only deregister if browsing is enabled and it's a local printer...
151 */
152
153 if (!Browsing || !p->shared ||
154 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
155 return;
156
157 /*
158 * Announce the deletion...
159 */
160
161 if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
162 {
163 cups_ptype_t savedtype = p->type; /* Saved printer type */
164
165 p->type |= CUPS_PRINTER_DELETE;
166
167 send_cups_browse(p);
168
169 p->type = savedtype;
170 }
171
172 #ifdef HAVE_LIBSLP
173 if (BrowseLocalProtocols & BROWSE_SLP)
174 slp_dereg_printer(p);
175 #endif /* HAVE_LIBSLP */
176
177 #ifdef HAVE_DNSSD
178 if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDPort)
179 dnssdDeregisterPrinter(p);
180 #endif /* HAVE_DNSSD */
181 }
182
183
184 /*
185 * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
186 */
187
188 void
189 cupsdLoadRemoteCache(void)
190 {
191 cups_file_t *fp; /* remote.cache file */
192 int linenum; /* Current line number */
193 char line[1024], /* Line from file */
194 *value, /* Pointer to value */
195 *valueptr, /* Pointer into value */
196 scheme[32], /* Scheme portion of URI */
197 username[64], /* Username portion of URI */
198 host[HTTP_MAX_HOST],
199 /* Hostname portion of URI */
200 resource[HTTP_MAX_URI];
201 /* Resource portion of URI */
202 int port; /* Port number */
203 cupsd_printer_t *p; /* Current printer */
204 time_t now; /* Current time */
205
206
207 /*
208 * Don't load the cache if the remote protocols are disabled...
209 */
210
211 if (!Browsing)
212 {
213 cupsdLogMessage(CUPSD_LOG_DEBUG,
214 "cupsdLoadRemoteCache: Not loading remote cache.");
215 return;
216 }
217
218 /*
219 * Open the remote.cache file...
220 */
221
222 snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
223 if ((fp = cupsFileOpen(line, "r")) == NULL)
224 return;
225
226 /*
227 * Read printer configurations until we hit EOF...
228 */
229
230 linenum = 0;
231 p = NULL;
232 now = time(NULL);
233
234 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
235 {
236 /*
237 * Decode the directive...
238 */
239
240 if (!strcasecmp(line, "<Printer") ||
241 !strcasecmp(line, "<DefaultPrinter"))
242 {
243 /*
244 * <Printer name> or <DefaultPrinter name>
245 */
246
247 if (p == NULL && value)
248 {
249 /*
250 * Add the printer and a base file type...
251 */
252
253 cupsdLogMessage(CUPSD_LOG_DEBUG,
254 "cupsdLoadRemoteCache: Loading printer %s...", value);
255
256 if ((p = cupsdFindDest(value)) != NULL)
257 {
258 if (p->type & CUPS_PRINTER_CLASS)
259 {
260 cupsdLogMessage(CUPSD_LOG_WARN,
261 "Cached remote printer \"%s\" conflicts with "
262 "existing class!",
263 value);
264 p = NULL;
265 continue;
266 }
267 }
268 else
269 p = cupsdAddPrinter(value);
270
271 p->accepting = 1;
272 p->state = IPP_PRINTER_IDLE;
273 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
274 p->browse_time = now;
275 p->browse_expire = now + BrowseTimeout;
276
277 /*
278 * Set the default printer as needed...
279 */
280
281 if (!strcasecmp(line, "<DefaultPrinter"))
282 DefaultPrinter = p;
283 }
284 else
285 {
286 cupsdLogMessage(CUPSD_LOG_ERROR,
287 "Syntax error on line %d of remote.cache.", linenum);
288 break;
289 }
290 }
291 else if (!strcasecmp(line, "<Class") ||
292 !strcasecmp(line, "<DefaultClass"))
293 {
294 /*
295 * <Class name> or <DefaultClass name>
296 */
297
298 if (p == NULL && value)
299 {
300 /*
301 * Add the printer and a base file type...
302 */
303
304 cupsdLogMessage(CUPSD_LOG_DEBUG,
305 "cupsdLoadRemoteCache: Loading class %s...", value);
306
307 if ((p = cupsdFindDest(value)) != NULL)
308 p->type = CUPS_PRINTER_CLASS;
309 else
310 p = cupsdAddClass(value);
311
312 p->accepting = 1;
313 p->state = IPP_PRINTER_IDLE;
314 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
315 p->browse_time = now;
316 p->browse_expire = now + BrowseTimeout;
317
318 /*
319 * Set the default printer as needed...
320 */
321
322 if (!strcasecmp(line, "<DefaultClass"))
323 DefaultPrinter = p;
324 }
325 else
326 {
327 cupsdLogMessage(CUPSD_LOG_ERROR,
328 "Syntax error on line %d of remote.cache.", linenum);
329 break;
330 }
331 }
332 else if (!strcasecmp(line, "</Printer>") ||
333 !strcasecmp(line, "</Class>"))
334 {
335 if (p != NULL)
336 {
337 /*
338 * Close out the current printer...
339 */
340
341 cupsdSetPrinterAttrs(p);
342
343 p = NULL;
344 }
345 else
346 {
347 cupsdLogMessage(CUPSD_LOG_ERROR,
348 "Syntax error on line %d of remote.cache.", linenum);
349 break;
350 }
351 }
352 else if (!p)
353 {
354 cupsdLogMessage(CUPSD_LOG_ERROR,
355 "Syntax error on line %d of remote.cache.", linenum);
356 break;
357 }
358 else if (!strcasecmp(line, "Info"))
359 {
360 if (value)
361 cupsdSetString(&p->info, value);
362 }
363 else if (!strcasecmp(line, "MakeModel"))
364 {
365 if (value)
366 cupsdSetString(&p->make_model, value);
367 }
368 else if (!strcasecmp(line, "Location"))
369 {
370 if (value)
371 cupsdSetString(&p->location, value);
372 }
373 else if (!strcasecmp(line, "DeviceURI"))
374 {
375 if (value)
376 {
377 httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
378 username, sizeof(username), host, sizeof(host), &port,
379 resource, sizeof(resource));
380
381 cupsdSetString(&p->hostname, host);
382 cupsdSetString(&p->uri, value);
383 cupsdSetString(&p->device_uri, value);
384 }
385 else
386 {
387 cupsdLogMessage(CUPSD_LOG_ERROR,
388 "Syntax error on line %d of remote.cache.", linenum);
389 break;
390 }
391 }
392 else if (!strcasecmp(line, "Option") && value)
393 {
394 /*
395 * Option name value
396 */
397
398 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
399
400 if (!*valueptr)
401 cupsdLogMessage(CUPSD_LOG_ERROR,
402 "Syntax error on line %d of remote.cache.", linenum);
403 else
404 {
405 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
406
407 p->num_options = cupsAddOption(value, valueptr, p->num_options,
408 &(p->options));
409 }
410 }
411 else if (!strcasecmp(line, "State"))
412 {
413 /*
414 * Set the initial queue state...
415 */
416
417 if (value && !strcasecmp(value, "idle"))
418 p->state = IPP_PRINTER_IDLE;
419 else if (value && !strcasecmp(value, "stopped"))
420 p->state = IPP_PRINTER_STOPPED;
421 else
422 {
423 cupsdLogMessage(CUPSD_LOG_ERROR,
424 "Syntax error on line %d of remote.cache.", linenum);
425 break;
426 }
427 }
428 else if (!strcasecmp(line, "StateMessage"))
429 {
430 /*
431 * Set the initial queue state message...
432 */
433
434 if (value)
435 strlcpy(p->state_message, value, sizeof(p->state_message));
436 }
437 else if (!strcasecmp(line, "Accepting"))
438 {
439 /*
440 * Set the initial accepting state...
441 */
442
443 if (value &&
444 (!strcasecmp(value, "yes") ||
445 !strcasecmp(value, "on") ||
446 !strcasecmp(value, "true")))
447 p->accepting = 1;
448 else if (value &&
449 (!strcasecmp(value, "no") ||
450 !strcasecmp(value, "off") ||
451 !strcasecmp(value, "false")))
452 p->accepting = 0;
453 else
454 {
455 cupsdLogMessage(CUPSD_LOG_ERROR,
456 "Syntax error on line %d of remote.cache.", linenum);
457 break;
458 }
459 }
460 else if (!strcasecmp(line, "Type"))
461 {
462 if (value)
463 p->type = atoi(value);
464 else
465 {
466 cupsdLogMessage(CUPSD_LOG_ERROR,
467 "Syntax error on line %d of remote.cache.", linenum);
468 break;
469 }
470 }
471 else if (!strcasecmp(line, "BrowseTime"))
472 {
473 if (value)
474 {
475 time_t t = atoi(value);
476
477 if (t > p->browse_expire)
478 p->browse_expire = t;
479 }
480 else
481 {
482 cupsdLogMessage(CUPSD_LOG_ERROR,
483 "Syntax error on line %d of remote.cache.", linenum);
484 break;
485 }
486 }
487 else if (!strcasecmp(line, "JobSheets"))
488 {
489 /*
490 * Set the initial job sheets...
491 */
492
493 if (value)
494 {
495 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
496
497 if (*valueptr)
498 *valueptr++ = '\0';
499
500 cupsdSetString(&p->job_sheets[0], value);
501
502 while (isspace(*valueptr & 255))
503 valueptr ++;
504
505 if (*valueptr)
506 {
507 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
508
509 if (*valueptr)
510 *valueptr++ = '\0';
511
512 cupsdSetString(&p->job_sheets[1], value);
513 }
514 }
515 else
516 {
517 cupsdLogMessage(CUPSD_LOG_ERROR,
518 "Syntax error on line %d of remote.cache.", linenum);
519 break;
520 }
521 }
522 else if (!strcasecmp(line, "AllowUser"))
523 {
524 if (value)
525 {
526 p->deny_users = 0;
527 cupsdAddPrinterUser(p, value);
528 }
529 else
530 {
531 cupsdLogMessage(CUPSD_LOG_ERROR,
532 "Syntax error on line %d of remote.cache.", linenum);
533 break;
534 }
535 }
536 else if (!strcasecmp(line, "DenyUser"))
537 {
538 if (value)
539 {
540 p->deny_users = 1;
541 cupsdAddPrinterUser(p, value);
542 }
543 else
544 {
545 cupsdLogMessage(CUPSD_LOG_ERROR,
546 "Syntax error on line %d of remote.cache.", linenum);
547 break;
548 }
549 }
550 else
551 {
552 /*
553 * Something else we don't understand...
554 */
555
556 cupsdLogMessage(CUPSD_LOG_ERROR,
557 "Unknown configuration directive %s on line %d of remote.cache.",
558 line, linenum);
559 }
560 }
561
562 cupsFileClose(fp);
563
564 /*
565 * Do auto-classing if needed...
566 */
567
568 process_implicit_classes();
569 }
570
571
572 /*
573 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
574 * printer or update the broadcast contents.
575 */
576
577 void
578 cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
579 {
580 if (!Browsing || !BrowseLocalProtocols ||
581 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
582 return;
583
584 #ifdef HAVE_LIBSLP
585 /* if (BrowseLocalProtocols & BROWSE_SLP)
586 slpRegisterPrinter(p); */
587 #endif /* HAVE_LIBSLP */
588
589 #ifdef HAVE_DNSSD
590 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDPort)
591 dnssdRegisterPrinter(p);
592 #endif /* HAVE_DNSSD */
593 }
594
595
596 /*
597 * 'cupsdRestartPolling()' - Restart polling servers as needed.
598 */
599
600 void
601 cupsdRestartPolling(void)
602 {
603 int i; /* Looping var */
604 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
605
606
607 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
608 if (pollp->pid)
609 kill(pollp->pid, SIGHUP);
610 }
611
612
613 /*
614 * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
615 */
616
617 void
618 cupsdSaveRemoteCache(void)
619 {
620 int i; /* Looping var */
621 cups_file_t *fp; /* printers.conf file */
622 char temp[1024]; /* Temporary string */
623 cupsd_printer_t *printer; /* Current printer class */
624 time_t curtime; /* Current time */
625 struct tm *curdate; /* Current date */
626 cups_option_t *option; /* Current option */
627
628
629 /*
630 * Create the remote.cache file...
631 */
632
633 snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
634
635 if ((fp = cupsFileOpen(temp, "w")) == NULL)
636 {
637 cupsdLogMessage(CUPSD_LOG_ERROR,
638 "Unable to save remote.cache - %s", strerror(errno));
639 return;
640 }
641 else
642 cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
643
644 /*
645 * Restrict access to the file...
646 */
647
648 fchown(cupsFileNumber(fp), getuid(), Group);
649 fchmod(cupsFileNumber(fp), ConfigFilePerm);
650
651 /*
652 * Write a small header to the file...
653 */
654
655 curtime = time(NULL);
656 curdate = localtime(&curtime);
657 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
658
659 cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
660 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
661
662 /*
663 * Write each local printer known to the system...
664 */
665
666 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
667 printer;
668 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
669 {
670 /*
671 * Skip local destinations...
672 */
673
674 if (!(printer->type & CUPS_PRINTER_DISCOVERED))
675 continue;
676
677 /*
678 * Write printers as needed...
679 */
680
681 if (printer == DefaultPrinter)
682 cupsFilePuts(fp, "<Default");
683 else
684 cupsFilePutChar(fp, '<');
685
686 if (printer->type & CUPS_PRINTER_CLASS)
687 cupsFilePrintf(fp, "Class %s>\n", printer->name);
688 else
689 cupsFilePrintf(fp, "Printer %s>\n", printer->name);
690
691 cupsFilePrintf(fp, "Type %d\n", printer->type);
692
693 cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
694
695 if (printer->info)
696 cupsFilePrintf(fp, "Info %s\n", printer->info);
697
698 if (printer->make_model)
699 cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
700
701 if (printer->location)
702 cupsFilePrintf(fp, "Location %s\n", printer->location);
703
704 if (printer->device_uri)
705 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
706
707 if (printer->state == IPP_PRINTER_STOPPED)
708 {
709 cupsFilePuts(fp, "State Stopped\n");
710 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
711 }
712 else
713 cupsFilePuts(fp, "State Idle\n");
714
715 if (printer->accepting)
716 cupsFilePuts(fp, "Accepting Yes\n");
717 else
718 cupsFilePuts(fp, "Accepting No\n");
719
720 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
721 printer->job_sheets[1]);
722
723 for (i = 0; i < printer->num_users; i ++)
724 cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
725 printer->users[i]);
726
727 for (i = printer->num_options, option = printer->options;
728 i > 0;
729 i --, option ++)
730 cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
731
732 if (printer->type & CUPS_PRINTER_CLASS)
733 cupsFilePuts(fp, "</Class>\n");
734 else
735 cupsFilePuts(fp, "</Printer>\n");
736 }
737
738 cupsFileClose(fp);
739 }
740
741
742 /*
743 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
744 */
745
746 void
747 cupsdSendBrowseList(void)
748 {
749 int count; /* Number of dests to update */
750 cupsd_printer_t *p; /* Current printer */
751 time_t ut, /* Minimum update time */
752 to; /* Timeout time */
753
754
755 if (!Browsing || !BrowseLocalProtocols || !Printers)
756 return;
757
758 /*
759 * Compute the update and timeout times...
760 */
761
762 to = time(NULL);
763 ut = to - BrowseInterval;
764
765 /*
766 * Figure out how many printers need an update...
767 */
768
769 if (BrowseInterval > 0)
770 {
771 int max_count; /* Maximum number to update */
772
773
774 /*
775 * Throttle the number of printers we'll be updating this time
776 * around based on the number of queues that need updating and
777 * the maximum number of queues to update each second...
778 */
779
780 max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
781
782 for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
783 count < max_count && p != NULL;
784 p = (cupsd_printer_t *)cupsArrayNext(Printers))
785 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
786 p->shared && p->browse_time < ut)
787 count ++;
788
789 /*
790 * Loop through all of the printers and send local updates as needed...
791 */
792
793 if (BrowseNext)
794 p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
795 else
796 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
797
798 for (;
799 count > 0;
800 p = (cupsd_printer_t *)cupsArrayNext(Printers))
801 {
802 /*
803 * Check for wraparound...
804 */
805
806 if (!p)
807 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
808
809 if (!p)
810 break;
811 else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
812 !p->shared)
813 continue;
814 else if (p->browse_time < ut)
815 {
816 /*
817 * Need to send an update...
818 */
819
820 count --;
821
822 p->browse_time = time(NULL);
823
824 if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
825 send_cups_browse(p);
826
827 #ifdef HAVE_LIBSLP
828 if (BrowseLocalProtocols & BROWSE_SLP)
829 send_slp_browse(p);
830 #endif /* HAVE_LIBSLP */
831
832 #ifdef HAVE_LDAP
833 if (BrowseLocalProtocols & BROWSE_LDAP)
834 send_ldap_browse(p);
835 #endif /* HAVE_LDAP */
836 }
837 }
838
839 /*
840 * Save where we left off so that all printers get updated...
841 */
842
843 BrowseNext = p;
844 }
845
846 /*
847 * Loop through all of the printers and send local updates as needed...
848 */
849
850 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
851 p;
852 p = (cupsd_printer_t *)cupsArrayNext(Printers))
853 {
854 /*
855 * If this is a remote queue, see if it needs to be timed out...
856 */
857
858 if (p->type & CUPS_PRINTER_DISCOVERED)
859 {
860 if (p->browse_expire < to)
861 {
862 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
863 "%s \'%s\' deleted by directory services (timeout).",
864 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
865 p->name);
866
867 cupsdLogMessage(CUPSD_LOG_DEBUG,
868 "Remote destination \"%s\" has timed out; "
869 "deleting it...",
870 p->name);
871
872 cupsArraySave(Printers);
873 cupsdDeletePrinter(p, 1);
874 cupsArrayRestore(Printers);
875 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
876 }
877 }
878 }
879 }
880
881
882 /*
883 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
884 */
885
886 void
887 cupsdStartBrowsing(void)
888 {
889 int val; /* Socket option value */
890 struct sockaddr_in addr; /* Broadcast address */
891 cupsd_printer_t *p; /* Current printer */
892
893
894 BrowseNext = NULL;
895
896 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
897 return;
898
899 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
900 {
901 if (BrowseSocket < 0)
902 {
903 /*
904 * Create the broadcast socket...
905 */
906
907 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
908 {
909 cupsdLogMessage(CUPSD_LOG_ERROR,
910 "Unable to create broadcast socket - %s.",
911 strerror(errno));
912 BrowseLocalProtocols &= ~BROWSE_CUPS;
913 BrowseRemoteProtocols &= ~BROWSE_CUPS;
914 return;
915 }
916
917 /*
918 * Bind the socket to browse port...
919 */
920
921 memset(&addr, 0, sizeof(addr));
922 addr.sin_addr.s_addr = htonl(INADDR_ANY);
923 addr.sin_family = AF_INET;
924 addr.sin_port = htons(BrowsePort);
925
926 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
927 {
928 cupsdLogMessage(CUPSD_LOG_ERROR,
929 "Unable to bind broadcast socket - %s.",
930 strerror(errno));
931
932 #ifdef WIN32
933 closesocket(BrowseSocket);
934 #else
935 close(BrowseSocket);
936 #endif /* WIN32 */
937
938 BrowseSocket = -1;
939 BrowseLocalProtocols &= ~BROWSE_CUPS;
940 BrowseRemoteProtocols &= ~BROWSE_CUPS;
941 return;
942 }
943 }
944
945 /*
946 * Set the "broadcast" flag...
947 */
948
949 val = 1;
950 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
951 {
952 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
953 strerror(errno));
954
955 #ifdef WIN32
956 closesocket(BrowseSocket);
957 #else
958 close(BrowseSocket);
959 #endif /* WIN32 */
960
961 BrowseSocket = -1;
962 BrowseLocalProtocols &= ~BROWSE_CUPS;
963 BrowseRemoteProtocols &= ~BROWSE_CUPS;
964 return;
965 }
966
967 /*
968 * Close the socket on exec...
969 */
970
971 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
972
973 /*
974 * Finally, add the socket to the input selection set as needed...
975 */
976
977 if (BrowseRemoteProtocols & BROWSE_CUPS)
978 {
979 /*
980 * We only listen if we want remote printers...
981 */
982
983 cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
984 NULL, NULL);
985 }
986 }
987 else
988 BrowseSocket = -1;
989
990 #ifdef HAVE_DNSSD
991 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
992 {
993 DNSServiceErrorType error; /* Error from service creation */
994 cupsd_listener_t *lis; /* Current listening socket */
995
996
997 /*
998 * First create a "master" connection for all registrations...
999 */
1000
1001 if ((error = DNSServiceCreateConnection(&DNSSDRef))
1002 != kDNSServiceErr_NoError)
1003 cupsdLogMessage(CUPSD_LOG_ERROR,
1004 "Unable to create master DNS-SD reference: %d", error);
1005 else
1006 {
1007 /*
1008 * Add the master connection to the select list...
1009 */
1010
1011 cupsdAddSelect(DNSServiceRefSockFD(DNSSDRef),
1012 (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse, NULL, NULL);
1013
1014 /*
1015 * Then get the port we use for registrations. If we are not listening
1016 * on any non-local ports, there is no sense sharing local printers via
1017 * Bonjour...
1018 */
1019
1020 DNSSDPort = 0;
1021
1022 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1023 lis;
1024 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1025 {
1026 if (httpAddrLocalhost(&(lis->address)))
1027 continue;
1028
1029 if (lis->address.addr.sa_family == AF_INET)
1030 {
1031 DNSSDPort = ntohs(lis->address.ipv4.sin_port);
1032 break;
1033 }
1034 else if (lis->address.addr.sa_family == AF_INET6)
1035 {
1036 DNSSDPort = ntohs(lis->address.ipv6.sin6_port);
1037 break;
1038 }
1039 }
1040
1041 /*
1042 * Create an array to track the printers we share...
1043 */
1044
1045 if (BrowseRemoteProtocols & BROWSE_DNSSD)
1046 DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
1047 NULL);
1048
1049 /*
1050 * Set the computer name and register the web interface...
1051 */
1052
1053 cupsdUpdateDNSSDName();
1054 }
1055 }
1056 #endif /* HAVE_DNSSD */
1057
1058 #ifdef HAVE_LIBSLP
1059 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1060 {
1061 /*
1062 * Open SLP handle...
1063 */
1064
1065 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1066 {
1067 cupsdLogMessage(CUPSD_LOG_ERROR,
1068 "Unable to open an SLP handle; disabling SLP browsing!");
1069 BrowseLocalProtocols &= ~BROWSE_SLP;
1070 BrowseRemoteProtocols &= ~BROWSE_SLP;
1071 }
1072
1073 BrowseSLPRefresh = 0;
1074 }
1075 else
1076 BrowseSLPHandle = NULL;
1077 #endif /* HAVE_LIBSLP */
1078
1079 #ifdef HAVE_OPENLDAP
1080 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
1081 {
1082 if (!BrowseLDAPDN)
1083 {
1084 cupsdLogMessage(CUPSD_LOG_ERROR,
1085 "Need to set BrowseLDAPDN to use LDAP browsing!");
1086 BrowseLocalProtocols &= ~BROWSE_LDAP;
1087 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1088 }
1089 else
1090 {
1091 /*
1092 * Open LDAP handle...
1093 */
1094
1095 int rc; /* LDAP API status */
1096 int version = 3; /* LDAP version */
1097 struct berval bv = {0, ""}; /* SASL bind value */
1098
1099
1100 /*
1101 * Set the certificate file to use for encrypted LDAP sessions...
1102 */
1103
1104 if (BrowseLDAPCACertFile)
1105 {
1106 cupsdLogMessage(CUPSD_LOG_DEBUG,
1107 "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
1108 BrowseLDAPCACertFile);
1109
1110 if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
1111 (void *)BrowseLDAPCACertFile))
1112 != LDAP_SUCCESS)
1113 cupsdLogMessage(CUPSD_LOG_ERROR,
1114 "Unable to set CA certificate file for LDAP "
1115 "connections: %d - %s", rc, ldap_err2string(rc));
1116 }
1117
1118 /*
1119 * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
1120 */
1121
1122 if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1123 rc = ldap_initialize(&BrowseLDAPHandle, "ldapi:///");
1124 else
1125 rc = ldap_initialize(&BrowseLDAPHandle, BrowseLDAPServer);
1126
1127 if (rc != LDAP_SUCCESS)
1128 {
1129 cupsdLogMessage(CUPSD_LOG_ERROR,
1130 "Unable to initialize LDAP; disabling LDAP browsing!");
1131 BrowseLocalProtocols &= ~BROWSE_LDAP;
1132 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1133 }
1134 else if (ldap_set_option(BrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
1135 (const void *)&version) != LDAP_SUCCESS)
1136 {
1137 ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
1138 BrowseLDAPHandle = NULL;
1139 cupsdLogMessage(CUPSD_LOG_ERROR,
1140 "Unable to set LDAP protocol version; "
1141 "disabling LDAP browsing!");
1142 BrowseLocalProtocols &= ~BROWSE_LDAP;
1143 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1144 }
1145 else
1146 {
1147 if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1148 rc = ldap_sasl_bind_s(BrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
1149 NULL, NULL);
1150 else
1151 rc = ldap_bind_s(BrowseLDAPHandle, BrowseLDAPBindDN,
1152 BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
1153
1154 if (rc != LDAP_SUCCESS)
1155 {
1156 cupsdLogMessage(CUPSD_LOG_ERROR,
1157 "Unable to bind to LDAP server; "
1158 "disabling LDAP browsing!");
1159 ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
1160 BrowseLocalProtocols &= ~BROWSE_LDAP;
1161 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1162 }
1163 }
1164 }
1165
1166 BrowseLDAPRefresh = 0;
1167 }
1168 #endif /* HAVE_OPENLDAP */
1169
1170 /*
1171 * Enable LPD and SMB printer sharing as needed through external programs...
1172 */
1173
1174 if (BrowseLocalProtocols & BROWSE_LPD)
1175 update_lpd(1);
1176
1177 if (BrowseLocalProtocols & BROWSE_SMB)
1178 update_smb(1);
1179
1180 /*
1181 * Register the individual printers
1182 */
1183
1184 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1185 p;
1186 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1187 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
1188 cupsdRegisterPrinter(p);
1189 }
1190
1191
1192 /*
1193 * 'cupsdStartPolling()' - Start polling servers as needed.
1194 */
1195
1196 void
1197 cupsdStartPolling(void)
1198 {
1199 int i; /* Looping var */
1200 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1201 char polld[1024]; /* Poll daemon path */
1202 char sport[255]; /* Server port */
1203 char bport[255]; /* Browser port */
1204 char interval[255]; /* Poll interval */
1205 int statusfds[2]; /* Status pipe */
1206 char *argv[6]; /* Arguments */
1207 char *envp[100]; /* Environment */
1208
1209
1210 /*
1211 * Don't do anything if we aren't polling...
1212 */
1213
1214 if (NumPolled == 0 || BrowseSocket < 0)
1215 {
1216 PollPipe = -1;
1217 PollStatusBuffer = NULL;
1218 return;
1219 }
1220
1221 /*
1222 * Setup string arguments for polld, port and interval options.
1223 */
1224
1225 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1226
1227 sprintf(bport, "%d", BrowsePort);
1228
1229 if (BrowseInterval)
1230 sprintf(interval, "%d", BrowseInterval);
1231 else
1232 strcpy(interval, "30");
1233
1234 argv[0] = "cups-polld";
1235 argv[2] = sport;
1236 argv[3] = interval;
1237 argv[4] = bport;
1238 argv[5] = NULL;
1239
1240 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1241
1242 /*
1243 * Create a pipe that receives the status messages from each
1244 * polling daemon...
1245 */
1246
1247 if (cupsdOpenPipe(statusfds))
1248 {
1249 cupsdLogMessage(CUPSD_LOG_ERROR,
1250 "Unable to create polling status pipes - %s.",
1251 strerror(errno));
1252 PollPipe = -1;
1253 PollStatusBuffer = NULL;
1254 return;
1255 }
1256
1257 PollPipe = statusfds[0];
1258 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
1259
1260 /*
1261 * Run each polling daemon, redirecting stderr to the polling pipe...
1262 */
1263
1264 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1265 {
1266 sprintf(sport, "%d", pollp->port);
1267
1268 argv[1] = pollp->hostname;
1269
1270 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
1271 0, DefaultProfile, &(pollp->pid)) < 0)
1272 {
1273 cupsdLogMessage(CUPSD_LOG_ERROR,
1274 "cupsdStartPolling: Unable to fork polling daemon - %s",
1275 strerror(errno));
1276 pollp->pid = 0;
1277 break;
1278 }
1279 else
1280 cupsdLogMessage(CUPSD_LOG_DEBUG,
1281 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1282 pollp->hostname, pollp->port, pollp->pid);
1283 }
1284
1285 close(statusfds[1]);
1286
1287 /*
1288 * Finally, add the pipe to the input selection set...
1289 */
1290
1291 cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
1292 }
1293
1294
1295 /*
1296 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
1297 */
1298
1299 void
1300 cupsdStopBrowsing(void)
1301 {
1302 cupsd_printer_t *p; /* Current printer */
1303
1304
1305 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1306 return;
1307
1308 /*
1309 * De-register the individual printers
1310 */
1311
1312 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1313 p;
1314 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1315 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
1316 cupsdDeregisterPrinter(p, 1);
1317
1318 /*
1319 * Shut down browsing sockets...
1320 */
1321
1322 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
1323 BrowseSocket >= 0)
1324 {
1325 /*
1326 * Close the socket and remove it from the input selection set.
1327 */
1328
1329 #ifdef WIN32
1330 closesocket(BrowseSocket);
1331 #else
1332 close(BrowseSocket);
1333 #endif /* WIN32 */
1334
1335 cupsdRemoveSelect(BrowseSocket);
1336 BrowseSocket = -1;
1337 }
1338
1339 #ifdef HAVE_DNSSD
1340 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
1341 {
1342 if (WebIFRef)
1343 {
1344 DNSServiceRefDeallocate(WebIFRef);
1345 WebIFRef = NULL;
1346 }
1347
1348 if (RemoteRef)
1349 {
1350 DNSServiceRefDeallocate(RemoteRef);
1351 RemoteRef = NULL;
1352 }
1353
1354 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
1355
1356 DNSServiceRefDeallocate(DNSSDRef);
1357 DNSSDRef = NULL;
1358
1359 cupsArrayDelete(DNSSDPrinters);
1360 DNSSDPrinters = NULL;
1361 }
1362 #endif /* HAVE_DNSSD */
1363
1364 #ifdef HAVE_LIBSLP
1365 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1366 BrowseSLPHandle)
1367 {
1368 /*
1369 * Close SLP handle...
1370 */
1371
1372 SLPClose(BrowseSLPHandle);
1373 BrowseSLPHandle = NULL;
1374 }
1375 #endif /* HAVE_LIBSLP */
1376
1377 #ifdef HAVE_OPENLDAP
1378 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1379 BrowseLDAPHandle)
1380 {
1381 ldap_unbind(BrowseLDAPHandle);
1382 BrowseLDAPHandle = NULL;
1383 }
1384 #endif /* HAVE_OPENLDAP */
1385
1386 /*
1387 * Disable LPD and SMB printer sharing as needed through external programs...
1388 */
1389
1390 if (BrowseLocalProtocols & BROWSE_LPD)
1391 update_lpd(0);
1392
1393 if (BrowseLocalProtocols & BROWSE_SMB)
1394 update_smb(0);
1395 }
1396
1397
1398 /*
1399 * 'cupsdStopPolling()' - Stop polling servers as needed.
1400 */
1401
1402 void
1403 cupsdStopPolling(void)
1404 {
1405 int i; /* Looping var */
1406 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1407
1408
1409 if (PollPipe >= 0)
1410 {
1411 cupsdStatBufDelete(PollStatusBuffer);
1412 close(PollPipe);
1413
1414 cupsdRemoveSelect(PollPipe);
1415
1416 PollPipe = -1;
1417 PollStatusBuffer = NULL;
1418 }
1419
1420 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1421 if (pollp->pid)
1422 cupsdEndProcess(pollp->pid, 0);
1423 }
1424
1425
1426 #ifdef HAVE_DNSSD
1427 /*
1428 * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
1429 */
1430
1431 void
1432 cupsdUpdateDNSSDBrowse(void)
1433 {
1434 DNSServiceErrorType sdErr; /* Service discovery error */
1435
1436
1437 if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
1438 cupsdLogMessage(CUPSD_LOG_ERROR,
1439 "DNS Service Discovery registration error %d!",
1440 sdErr);
1441 }
1442
1443
1444 /*
1445 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1446 */
1447
1448 void
1449 cupsdUpdateDNSSDName(void)
1450 {
1451 DNSServiceErrorType error; /* Error from service creation */
1452 char webif[1024]; /* Web interface share name */
1453 #ifdef HAVE_COREFOUNDATION_H
1454 CFStringRef nameRef; /* Computer name CFString */
1455 char nameBuffer[1024]; /* C-string buffer */
1456 CFStringEncoding nameEncoding; /* Computer name encoding */
1457 #endif /* HAVE_COREFOUNDATION_H */
1458
1459
1460 /*
1461 * Only share the web interface and printers when non-local listening is
1462 * enabled...
1463 */
1464
1465 if (!DNSSDPort)
1466 return;
1467
1468 /*
1469 * Get the computer name as a c-string...
1470 */
1471
1472 #ifdef HAVE_COREFOUNDATION_H
1473 cupsdClearString(&DNSSDName);
1474
1475 if ((nameRef = SCDynamicStoreCopyComputerName(NULL,
1476 &nameEncoding)) != NULL)
1477 {
1478 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
1479 kCFStringEncodingUTF8))
1480 cupsdSetString(&DNSSDName, nameBuffer);
1481
1482 CFRelease(nameRef);
1483 }
1484
1485 #else
1486 cupsdSetString(&DNSSDName, ServerName);
1487 #endif /* HAVE_COREFOUNDATION_H */
1488
1489 /*
1490 * Then (re)register the web interface...
1491 */
1492
1493 if (DNSSDName)
1494 snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName);
1495 else
1496 strlcpy(webif, "CUPS Web Interface", sizeof(webif));
1497
1498 if (WebIFRef)
1499 DNSServiceRefDeallocate(WebIFRef);
1500
1501 WebIFRef = DNSSDRef;
1502 if ((error = DNSServiceRegister(&WebIFRef,
1503 kDNSServiceFlagsShareConnection,
1504 0, webif, "_http._tcp", NULL,
1505 NULL, htons(DNSSDPort), 7,
1506 "\006path=/", dnssdRegisterCallback,
1507 NULL)) != kDNSServiceErr_NoError)
1508 cupsdLogMessage(CUPSD_LOG_ERROR,
1509 "DNS-SD web interface registration failed: %d", error);
1510 }
1511 #endif /* HAVE_DNSSD */
1512
1513
1514 #ifdef HAVE_OPENLDAP
1515 /*
1516 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
1517 */
1518
1519 void
1520 cupsdUpdateLDAPBrowse(void)
1521 {
1522 char uri[HTTP_MAX_URI], /* Printer URI */
1523 host[HTTP_MAX_URI], /* Hostname */
1524 resource[HTTP_MAX_URI], /* Resource path */
1525 location[1024], /* Printer location */
1526 info[1024], /* Printer information */
1527 make_model[1024], /* Printer make and model */
1528 **value; /* Holds the returned data from LDAP */
1529 int type; /* Printer type */
1530 int rc; /* LDAP status */
1531 int limit; /* Size limit */
1532 LDAPMessage *res, /* LDAP search results */
1533 *e; /* Current entry from search */
1534
1535
1536 /*
1537 * Search for printers...
1538 */
1539
1540 cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
1541
1542 BrowseLDAPRefresh = time(NULL) + BrowseInterval;
1543
1544 rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
1545 "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
1546 if (rc != LDAP_SUCCESS)
1547 {
1548 cupsdLogMessage(CUPSD_LOG_ERROR,
1549 "LDAP search returned error %d: %s", rc,
1550 ldap_err2string(rc));
1551 return;
1552 }
1553
1554 limit = ldap_count_entries(BrowseLDAPHandle, res);
1555 cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
1556 if (limit < 1)
1557 return;
1558
1559 /*
1560 * Loop through the available printers...
1561 */
1562
1563 for (e = ldap_first_entry(BrowseLDAPHandle, res);
1564 e;
1565 e = ldap_next_entry(BrowseLDAPHandle, e))
1566 {
1567 /*
1568 * Get the required values from this entry...
1569 */
1570
1571 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1572 "printerDescription")) == NULL)
1573 continue;
1574
1575 strlcpy(info, *value, sizeof(info));
1576 ldap_value_free(value);
1577
1578 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1579 "printerLocation")) == NULL)
1580 continue;
1581
1582 strlcpy(location, *value, sizeof(location));
1583 ldap_value_free(value);
1584
1585 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1586 "printerMakeAndModel")) == NULL)
1587 continue;
1588
1589 strlcpy(make_model, *value, sizeof(make_model));
1590 ldap_value_free(value);
1591
1592 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1593 "printerType")) == NULL)
1594 continue;
1595
1596 type = atoi(*value);
1597 ldap_value_free(value);
1598
1599 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1600 "printerURI")) == NULL)
1601 continue;
1602
1603 strlcpy(uri, *value, sizeof(uri));
1604 ldap_value_free(value);
1605
1606 /*
1607 * Process the entry as browse data...
1608 */
1609
1610 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
1611 process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
1612 location, info, make_model, 0, NULL);
1613
1614 }
1615 }
1616 #endif /* HAVE_OPENLDAP */
1617
1618
1619 #ifdef HAVE_LIBSLP
1620 /*
1621 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
1622 */
1623
1624 void
1625 cupsdUpdateSLPBrowse(void)
1626 {
1627 slpsrvurl_t *s, /* Temporary list of service URLs */
1628 *next; /* Next service in list */
1629 cupsd_printer_t p; /* Printer information */
1630 const char *uri; /* Pointer to printer URI */
1631 char host[HTTP_MAX_URI], /* Host portion of URI */
1632 resource[HTTP_MAX_URI]; /* Resource portion of URI */
1633
1634
1635 /*
1636 * Reset the refresh time...
1637 */
1638
1639 BrowseSLPRefresh = time(NULL) + BrowseInterval;
1640
1641 /*
1642 * Poll for remote printers using SLP...
1643 */
1644
1645 s = NULL;
1646
1647 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
1648 slp_url_callback, &s);
1649
1650 /*
1651 * Loop through the list of available printers...
1652 */
1653
1654 for (; s; s = next)
1655 {
1656 /*
1657 * Save the "next" pointer...
1658 */
1659
1660 next = s->next;
1661
1662 /*
1663 * Load a cupsd_printer_t structure with the SLP service attributes...
1664 */
1665
1666 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
1667
1668 /*
1669 * Process this printer entry...
1670 */
1671
1672 uri = s->url + SLP_CUPS_SRVLEN + 1;
1673
1674 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
1675 {
1676 /*
1677 * Pull the URI apart to see if this is a local or remote printer...
1678 */
1679
1680 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
1681 process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
1682 p.location, p.info, p.make_model, 0, NULL);
1683 }
1684
1685 /*
1686 * Free this listing...
1687 */
1688
1689 cupsdClearString(&p.info);
1690 cupsdClearString(&p.location);
1691 cupsdClearString(&p.make_model);
1692
1693 free(s);
1694 }
1695 }
1696 #endif /* HAVE_LIBSLP */
1697
1698
1699 /*
1700 * 'dequote()' - Remote quotes from a string.
1701 */
1702
1703 static char * /* O - Dequoted string */
1704 dequote(char *d, /* I - Destination string */
1705 const char *s, /* I - Source string */
1706 int dlen) /* I - Destination length */
1707 {
1708 char *dptr; /* Pointer into destination */
1709
1710
1711 if (s)
1712 {
1713 for (dptr = d, dlen --; *s && dlen > 0; s ++)
1714 if (*s != '\"')
1715 {
1716 *dptr++ = *s;
1717 dlen --;
1718 }
1719
1720 *dptr = '\0';
1721 }
1722 else
1723 *d = '\0';
1724
1725 return (d);
1726 }
1727
1728
1729 #ifdef HAVE_DNSSD
1730 /*
1731 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
1732 */
1733
1734 static char * /* O - TXT record */
1735 dnssdBuildTxtRecord(
1736 int *txt_len, /* O - TXT record length */
1737 cupsd_printer_t *p, /* I - Printer information */
1738 int for_lpd) /* I - 1 = LPD, 0 = IPP */
1739 {
1740 int i, j; /* Looping vars */
1741 char type_str[32], /* Type to string buffer */
1742 state_str[32], /* State to string buffer */
1743 rp_str[1024], /* Queue name string buffer */
1744 air_str[1024], /* auth-info-required string buffer */
1745 *keyvalue[32][2]; /* Table of key/value pairs */
1746
1747
1748 /*
1749 * Load up the key value pairs...
1750 */
1751
1752 i = 0;
1753
1754 keyvalue[i ][0] = "txtvers";
1755 keyvalue[i++][1] = "1";
1756
1757 keyvalue[i ][0] = "qtotal";
1758 keyvalue[i++][1] = "1";
1759
1760 keyvalue[i ][0] = "rp";
1761 keyvalue[i++][1] = rp_str;
1762 if (for_lpd)
1763 strlcpy(rp_str, p->name, sizeof(rp_str));
1764 else
1765 snprintf(rp_str, sizeof(rp_str), "%s/%s",
1766 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
1767
1768 keyvalue[i ][0] = "ty";
1769 keyvalue[i++][1] = p->make_model;
1770
1771 if (p->location && *p->location != '\0')
1772 {
1773 keyvalue[i ][0] = "note";
1774 keyvalue[i++][1] = p->location;
1775 }
1776
1777 keyvalue[i ][0] = "priority";
1778 keyvalue[i++][1] = for_lpd ? "100" : "0";
1779
1780 keyvalue[i ][0] = "product";
1781 keyvalue[i++][1] = p->product ? p->product : "Unknown";
1782
1783 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
1784 snprintf(state_str, sizeof(state_str), "%d", p->state);
1785
1786 keyvalue[i ][0] = "printer-state";
1787 keyvalue[i++][1] = state_str;
1788
1789 keyvalue[i ][0] = "printer-type";
1790 keyvalue[i++][1] = type_str;
1791
1792 keyvalue[i ][0] = "Transparent";
1793 keyvalue[i++][1] = "T";
1794
1795 keyvalue[i ][0] = "Binary";
1796 keyvalue[i++][1] = "T";
1797
1798 if ((p->type & CUPS_PRINTER_FAX))
1799 {
1800 keyvalue[i ][0] = "Fax";
1801 keyvalue[i++][1] = "T";
1802 }
1803
1804 if ((p->type & CUPS_PRINTER_COLOR))
1805 {
1806 keyvalue[i ][0] = "Color";
1807 keyvalue[i++][1] = "T";
1808 }
1809
1810 if ((p->type & CUPS_PRINTER_DUPLEX))
1811 {
1812 keyvalue[i ][0] = "Duplex";
1813 keyvalue[i++][1] = "T";
1814 }
1815
1816 if ((p->type & CUPS_PRINTER_STAPLE))
1817 {
1818 keyvalue[i ][0] = "Staple";
1819 keyvalue[i++][1] = "T";
1820 }
1821
1822 if ((p->type & CUPS_PRINTER_COPIES))
1823 {
1824 keyvalue[i ][0] = "Copies";
1825 keyvalue[i++][1] = "T";
1826 }
1827
1828 if ((p->type & CUPS_PRINTER_COLLATE))
1829 {
1830 keyvalue[i ][0] = "Collate";
1831 keyvalue[i++][1] = "T";
1832 }
1833
1834 if ((p->type & CUPS_PRINTER_PUNCH))
1835 {
1836 keyvalue[i ][0] = "Punch";
1837 keyvalue[i++][1] = "T";
1838 }
1839
1840 if ((p->type & CUPS_PRINTER_BIND))
1841 {
1842 keyvalue[i ][0] = "Bind";
1843 keyvalue[i++][1] = "T";
1844 }
1845
1846 if ((p->type & CUPS_PRINTER_SORT))
1847 {
1848 keyvalue[i ][0] = "Sort";
1849 keyvalue[i++][1] = "T";
1850 }
1851
1852 keyvalue[i ][0] = "pdl";
1853 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
1854
1855 if (p->num_auth_info_required)
1856 {
1857 char *air = air_str; /* Pointer into string */
1858
1859
1860 for (j = 0; j < p->num_auth_info_required; j ++)
1861 {
1862 if (air >= (air_str + sizeof(air_str) - 2))
1863 break;
1864
1865 if (j)
1866 *air++ = ',';
1867
1868 strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
1869 air += strlen(air);
1870 }
1871
1872 keyvalue[i ][0] = "air";
1873 keyvalue[i++][1] = air;
1874 }
1875
1876 /*
1877 * Then pack them into a proper txt record...
1878 */
1879
1880 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
1881 }
1882
1883
1884 /*
1885 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
1886 */
1887
1888 static int /* O - Result of comparison */
1889 dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
1890 cupsd_printer_t *b)/* I - Second printer */
1891 {
1892 return (strcasecmp(a->reg_name, b->reg_name));
1893 }
1894
1895
1896 /*
1897 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
1898 * printer.
1899 */
1900
1901 static void
1902 dnssdDeregisterPrinter(
1903 cupsd_printer_t *p) /* I - Printer */
1904 {
1905 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
1906
1907 /*
1908 * Closing the socket deregisters the service
1909 */
1910
1911 if (p->ipp_ref)
1912 {
1913 DNSServiceRefDeallocate(p->ipp_ref);
1914 p->ipp_ref = NULL;
1915 }
1916
1917 cupsArrayRemove(DNSSDPrinters, p);
1918 cupsdClearString(&p->reg_name);
1919
1920 if (p->ipp_txt)
1921 {
1922 /*
1923 * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
1924 */
1925
1926 free(p->ipp_txt);
1927 p->ipp_txt = NULL;
1928 }
1929 }
1930
1931
1932 /*
1933 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
1934 * TXT record format.
1935 */
1936
1937 static char * /* O - TXT record */
1938 dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
1939 char *keyvalue[][2], /* I - Table of key value pairs */
1940 int count) /* I - Items in table */
1941 {
1942 int i; /* Looping var */
1943 int length; /* Length of TXT record */
1944 int length2; /* Length of value */
1945 char *txtRecord; /* TXT record buffer */
1946 char *cursor; /* Looping pointer */
1947
1948
1949 /*
1950 * Calculate the buffer size
1951 */
1952
1953 for (length = i = 0; i < count; i++)
1954 length += 1 + strlen(keyvalue[i][0]) +
1955 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
1956
1957 /*
1958 * Allocate and fill it
1959 */
1960
1961 txtRecord = malloc(length);
1962 if (txtRecord)
1963 {
1964 *txt_len = length;
1965
1966 for (cursor = txtRecord, i = 0; i < count; i++)
1967 {
1968 /*
1969 * Drop in the p-string style length byte followed by the data
1970 */
1971
1972 length = strlen(keyvalue[i][0]);
1973 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
1974
1975 *cursor++ = (unsigned char)(length + length2);
1976
1977 memcpy(cursor, keyvalue[i][0], length);
1978 cursor += length;
1979
1980 if (length2)
1981 {
1982 length2 --;
1983 *cursor++ = '=';
1984 memcpy(cursor, keyvalue[i][1], length2);
1985 cursor += length2;
1986 }
1987 }
1988 }
1989
1990 return (txtRecord);
1991 }
1992
1993
1994 /*
1995 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
1996 */
1997
1998 static void
1999 dnssdRegisterCallback(
2000 DNSServiceRef sdRef, /* I - DNS Service reference */
2001 DNSServiceFlags flags, /* I - Reserved for future use */
2002 DNSServiceErrorType errorCode, /* I - Error code */
2003 const char *name, /* I - Service name */
2004 const char *regtype, /* I - Service type */
2005 const char *domain, /* I - Domain. ".local" for now */
2006 void *context) /* I - User-defined context */
2007 {
2008 cupsd_printer_t *p = (cupsd_printer_t *)context;
2009 /* Current printer */
2010
2011
2012 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s",
2013 name, regtype, p ? p->name : "Web Interface");
2014
2015 if (errorCode)
2016 {
2017 cupsdLogMessage(CUPSD_LOG_ERROR,
2018 "DNSServiceRegister failed with error %d", (int)errorCode);
2019 return;
2020 }
2021 else if (p && strcasecmp(name, p->reg_name))
2022 {
2023 cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2024 name, p->name);
2025
2026 cupsArrayRemove(DNSSDPrinters, p);
2027 cupsdSetString(&p->reg_name, name);
2028 cupsArrayAdd(DNSSDPrinters, p);
2029
2030 LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2031 }
2032 }
2033
2034
2035 /*
2036 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2037 * or update the broadcast contents.
2038 */
2039
2040 static void
2041 dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2042 {
2043 DNSServiceErrorType se; /* dnssd errors */
2044 char *ipp_txt, /* IPP TXT record buffer */
2045 *printer_txt, /* LPD TXT record buffer */
2046 name[1024], /* Service name */
2047 *nameptr; /* Pointer into name */
2048 int ipp_len, /* IPP TXT record length */
2049 printer_len; /* LPD TXT record length */
2050 char resource[1024]; /* Resource path for printer */
2051 const char *regtype; /* Registration type */
2052 const char *domain; /* Registration domain */
2053 cupsd_location_t *location, /* Printer location */
2054 *policy; /* Operation policy for Print-Job */
2055 unsigned address[4]; /* INADDR_ANY address */
2056
2057
2058 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2059 !p->ipp_ref ? "new" : "update");
2060
2061 /*
2062 * If per-printer sharing was just disabled make sure we're not
2063 * registered before returning.
2064 */
2065
2066 if (!p->shared)
2067 {
2068 dnssdDeregisterPrinter(p);
2069 return;
2070 }
2071
2072 /*
2073 * The registered name takes the form of "<printer-info> @ <computer name>"...
2074 */
2075
2076 if (p->info && strlen(p->info) > 0)
2077 {
2078 if (DNSSDName)
2079 snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName);
2080 else
2081 strlcpy(name, p->info, sizeof(name));
2082 }
2083 else if (DNSSDName)
2084 snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName);
2085 else
2086 strlcpy(name, p->name, sizeof(name));
2087
2088 /*
2089 * If an existing printer was renamed, unregister it and start over...
2090 */
2091
2092 if (p->reg_name && strcmp(p->reg_name, name))
2093 dnssdDeregisterPrinter(p);
2094
2095 if (!p->reg_name)
2096 {
2097 cupsdSetString(&p->reg_name, name);
2098 cupsArrayAdd(DNSSDPrinters, p);
2099 }
2100
2101 /*
2102 * If 'Allow printing from the Internet' is enabled (i.e. from any address)
2103 * let dnssd decide on the domain, otherwise restrict it to ".local".
2104 */
2105
2106 if (p->type & CUPS_PRINTER_CLASS)
2107 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
2108 else
2109 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
2110
2111 address[0] = address[1] = address[2] = address[3] = 0;
2112 location = cupsdFindBest(resource, HTTP_POST);
2113 policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
2114
2115 if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
2116 (policy && !cupsdCheckAccess(address, "", 0, policy)))
2117 domain = "local.";
2118 else
2119 domain = NULL;
2120
2121 /*
2122 * Register IPP and (optionally) LPD...
2123 */
2124
2125 ipp_len = 0; /* anti-compiler-warning-code */
2126 ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
2127
2128 if (!p->ipp_ref)
2129 {
2130 /*
2131 * Initial registration. Use the _fax subtype for fax queues...
2132 */
2133
2134 regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
2135 "_ipp._tcp,_cups";
2136
2137 cupsdLogMessage(CUPSD_LOG_DEBUG,
2138 "Registering DNS-SD printer %s with name \"%s\", "
2139 "type \"%s\", and domain \"%s\"", p->name, name, regtype,
2140 domain ? domain : "(null)");
2141
2142 /*
2143 * Register the queue, dropping characters as needed until we succeed...
2144 */
2145
2146 nameptr = name + strlen(name);
2147
2148 do
2149 {
2150 p->ipp_ref = DNSSDRef;
2151 if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
2152 0, name, regtype, domain, NULL,
2153 htons(DNSSDPort), ipp_len, ipp_txt,
2154 dnssdRegisterCallback,
2155 p)) == kDNSServiceErr_BadParam)
2156 {
2157 /*
2158 * Name is too long, drop trailing characters, taking into account
2159 * UTF-8 encoding...
2160 */
2161
2162 nameptr --;
2163
2164 while (nameptr > name && (*nameptr & 0xc0) == 0x80)
2165 nameptr --;
2166
2167 if (nameptr > name)
2168 *nameptr = '\0';
2169 }
2170 }
2171 while (se == kDNSServiceErr_BadParam && nameptr > name);
2172
2173 if (se == kDNSServiceErr_NoError)
2174 {
2175 p->ipp_txt = ipp_txt;
2176 p->ipp_len = ipp_len;
2177 ipp_txt = NULL;
2178 }
2179 else
2180 cupsdLogMessage(CUPSD_LOG_WARN,
2181 "DNS-SD IPP registration of \"%s\" failed: %d",
2182 p->name, se);
2183 }
2184 else if (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))
2185 {
2186 /*
2187 * Update the existing registration...
2188 */
2189
2190 /* A TTL of 0 means use record's original value (Radar 3176248) */
2191 DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, 0);
2192
2193 if (p->ipp_txt)
2194 free(p->ipp_txt);
2195
2196 p->ipp_txt = ipp_txt;
2197 p->ipp_len = ipp_len;
2198 ipp_txt = NULL;
2199 }
2200
2201 if (ipp_txt)
2202 free(ipp_txt);
2203
2204 if (BrowseLocalProtocols & BROWSE_LPD)
2205 {
2206 printer_len = 0; /* anti-compiler-warning-code */
2207 printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
2208
2209 if (!p->printer_ref)
2210 {
2211 /*
2212 * Initial registration...
2213 */
2214
2215 cupsdLogMessage(CUPSD_LOG_DEBUG,
2216 "Registering DNS-SD printer %s with name \"%s\", "
2217 "type \"_printer._tcp\", and domain \"%s\"", p->name,
2218 name, domain ? domain : "(null)");
2219
2220 p->printer_ref = DNSSDRef;
2221 if ((se = DNSServiceRegister(&p->printer_ref,
2222 kDNSServiceFlagsShareConnection,
2223 0, name, "_printer._tcp", domain, NULL,
2224 htons(515), printer_len, printer_txt,
2225 dnssdRegisterCallback,
2226 p)) == kDNSServiceErr_NoError)
2227 {
2228 p->printer_txt = printer_txt;
2229 p->printer_len = printer_len;
2230 printer_txt = NULL;
2231 }
2232 else
2233 cupsdLogMessage(CUPSD_LOG_WARN,
2234 "DNS-SD LPD registration of \"%s\" failed: %d",
2235 p->name, se);
2236 }
2237 else if (printer_len != p->printer_len ||
2238 memcmp(printer_txt, p->printer_txt, printer_len))
2239 {
2240 /*
2241 * Update the existing registration...
2242 */
2243
2244 /* A TTL of 0 means use record's original value (Radar 3176248) */
2245 DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
2246 printer_txt, 0);
2247
2248 if (p->printer_txt)
2249 free(p->printer_txt);
2250
2251 p->printer_txt = printer_txt;
2252 p->printer_len = printer_len;
2253 printer_txt = NULL;
2254 }
2255
2256 if (printer_txt)
2257 free(printer_txt);
2258 }
2259 }
2260 #endif /* HAVE_DNSSD */
2261
2262
2263 #ifdef __APPLE__
2264 /*
2265 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
2266 */
2267
2268 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
2269 get_hostconfig(const char *name) /* I - Name of service */
2270 {
2271 cups_file_t *fp; /* Hostconfig file */
2272 char line[1024], /* Line from file */
2273 *ptr; /* Pointer to value */
2274 int state = 1; /* State of service */
2275
2276
2277 /*
2278 * Try opening the /etc/hostconfig file; if we can't open it, assume that
2279 * the service is enabled/auto.
2280 */
2281
2282 if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
2283 {
2284 /*
2285 * Read lines from the file until we find the service...
2286 */
2287
2288 while (cupsFileGets(fp, line, sizeof(line)))
2289 {
2290 if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
2291 continue;
2292
2293 *ptr++ = '\0';
2294
2295 if (!strcasecmp(line, name))
2296 {
2297 /*
2298 * Found the service, see if it is set to "-NO-"...
2299 */
2300
2301 if (!strncasecmp(ptr, "-NO-", 4))
2302 state = 0;
2303 break;
2304 }
2305 }
2306
2307 cupsFileClose(fp);
2308 }
2309
2310 return (state);
2311 }
2312 #endif /* __APPLE__ */
2313
2314
2315 /*
2316 * 'is_local_queue()' - Determine whether the URI points at a local queue.
2317 */
2318
2319 static int /* O - 1 = local, 0 = remote, -1 = bad URI */
2320 is_local_queue(const char *uri, /* I - Printer URI */
2321 char *host, /* O - Host string */
2322 int hostlen, /* I - Length of host buffer */
2323 char *resource, /* O - Resource string */
2324 int resourcelen) /* I - Length of resource buffer */
2325 {
2326 char scheme[32], /* Scheme portion of URI */
2327 username[HTTP_MAX_URI]; /* Username portion of URI */
2328 int port; /* Port portion of URI */
2329 cupsd_netif_t *iface; /* Network interface */
2330
2331
2332 /*
2333 * Pull the URI apart to see if this is a local or remote printer...
2334 */
2335
2336 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
2337 username, sizeof(username), host, hostlen, &port,
2338 resource, resourcelen) < HTTP_URI_OK)
2339 return (-1);
2340
2341 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
2342
2343 /*
2344 * Check for local server addresses...
2345 */
2346
2347 if (!strcasecmp(host, ServerName) && port == LocalPort)
2348 return (1);
2349
2350 cupsdNetIFUpdate();
2351
2352 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
2353 iface;
2354 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
2355 if (!strcasecmp(host, iface->hostname) && port == iface->port)
2356 return (1);
2357
2358 /*
2359 * If we get here, the printer is remote...
2360 */
2361
2362 return (0);
2363 }
2364
2365
2366 /*
2367 * 'process_browse_data()' - Process new browse data.
2368 */
2369
2370 static void
2371 process_browse_data(
2372 const char *uri, /* I - URI of printer/class */
2373 const char *host, /* I - Hostname */
2374 const char *resource, /* I - Resource path */
2375 cups_ptype_t type, /* I - Printer type */
2376 ipp_pstate_t state, /* I - Printer state */
2377 const char *location, /* I - Printer location */
2378 const char *info, /* I - Printer information */
2379 const char *make_model, /* I - Printer make and model */
2380 int num_attrs, /* I - Number of attributes */
2381 cups_option_t *attrs) /* I - Attributes */
2382 {
2383 int i; /* Looping var */
2384 int update; /* Update printer attributes? */
2385 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
2386 name[IPP_MAX_NAME], /* Name of printer */
2387 newname[IPP_MAX_NAME], /* New name of printer */
2388 *hptr, /* Pointer into hostname */
2389 *sptr; /* Pointer into ServerName */
2390 char local_make_model[IPP_MAX_NAME];
2391 /* Local make and model */
2392 cupsd_printer_t *p; /* Printer information */
2393 const char *ipp_options, /* ipp-options value */
2394 *lease_duration; /* lease-duration value */
2395
2396
2397 /*
2398 * Determine if the URI contains any illegal characters in it...
2399 */
2400
2401 if (strncmp(uri, "ipp://", 6) || !host[0] ||
2402 (strncmp(resource, "/printers/", 10) &&
2403 strncmp(resource, "/classes/", 9)))
2404 {
2405 cupsdLogMessage(CUPSD_LOG_ERROR,
2406 "process_browse_data: Bad printer URI in browse data: %s",
2407 uri);
2408 return;
2409 }
2410
2411 if (strchr(resource, '?') ||
2412 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
2413 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
2414 {
2415 cupsdLogMessage(CUPSD_LOG_ERROR,
2416 "process_browse_data: Bad resource in browse data: %s",
2417 resource);
2418 return;
2419 }
2420
2421 /*
2422 * OK, this isn't a local printer; add any remote options...
2423 */
2424
2425 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
2426
2427 if (BrowseRemoteOptions)
2428 {
2429 if (BrowseRemoteOptions[0] == '?')
2430 {
2431 /*
2432 * Override server-supplied options...
2433 */
2434
2435 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
2436 }
2437 else if (ipp_options)
2438 {
2439 /*
2440 * Combine the server and local options...
2441 */
2442
2443 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
2444 BrowseRemoteOptions);
2445 }
2446 else
2447 {
2448 /*
2449 * Just use the local options...
2450 */
2451
2452 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
2453 }
2454
2455 uri = finaluri;
2456 }
2457 else if (ipp_options)
2458 {
2459 /*
2460 * Just use the server-supplied options...
2461 */
2462
2463 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
2464 uri = finaluri;
2465 }
2466
2467 /*
2468 * See if we already have it listed in the Printers list, and add it if not...
2469 */
2470
2471 type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
2472 type &= ~CUPS_PRINTER_IMPLICIT;
2473 update = 0;
2474 hptr = strchr(host, '.');
2475 sptr = strchr(ServerName, '.');
2476
2477 if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
2478 {
2479 /*
2480 * Strip the common domain name components...
2481 */
2482
2483 while (hptr != NULL)
2484 {
2485 if (!strcasecmp(hptr, sptr))
2486 {
2487 *hptr = '\0';
2488 break;
2489 }
2490 else
2491 hptr = strchr(hptr + 1, '.');
2492 }
2493 }
2494
2495 if (type & CUPS_PRINTER_CLASS)
2496 {
2497 /*
2498 * Remote destination is a class...
2499 */
2500
2501 if (!strncmp(resource, "/classes/", 9))
2502 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
2503 else
2504 return;
2505
2506 if (hptr && !*hptr)
2507 *hptr = '.'; /* Resource FQDN */
2508
2509 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
2510 {
2511 if ((p = cupsdFindDest(resource + 9)) != NULL)
2512 {
2513 if (p->hostname && strcasecmp(p->hostname, host))
2514 {
2515 /*
2516 * Nope, this isn't the same host; if the hostname isn't the local host,
2517 * add it to the other class and then find a class using the full host
2518 * name...
2519 */
2520
2521 if (p->type & CUPS_PRINTER_REMOTE)
2522 {
2523 cupsdLogMessage(CUPSD_LOG_DEBUG,
2524 "Renamed remote class \"%s\" to \"%s@%s\"...",
2525 p->name, p->name, p->hostname);
2526 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2527 "Class \'%s\' deleted by directory services.",
2528 p->name);
2529
2530 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
2531 cupsdRenamePrinter(p, newname);
2532
2533 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2534 "Class \'%s\' added by directory services.",
2535 p->name);
2536 }
2537
2538 p = NULL;
2539 }
2540 else if (!p->hostname)
2541 {
2542 /*
2543 * Hostname not set, so this must be a cached remote printer
2544 * that was created for a pending print job...
2545 */
2546
2547 cupsdSetString(&p->hostname, host);
2548 cupsdSetString(&p->uri, uri);
2549 cupsdSetString(&p->device_uri, uri);
2550 update = 1;
2551 }
2552 }
2553 else
2554 {
2555 /*
2556 * Use the short name for this shared class.
2557 */
2558
2559 strlcpy(name, resource + 9, sizeof(name));
2560 }
2561 }
2562 else if (p && !p->hostname)
2563 {
2564 /*
2565 * Hostname not set, so this must be a cached remote printer
2566 * that was created for a pending print job...
2567 */
2568
2569 cupsdSetString(&p->hostname, host);
2570 cupsdSetString(&p->uri, uri);
2571 cupsdSetString(&p->device_uri, uri);
2572 update = 1;
2573 }
2574
2575 if (!p)
2576 {
2577 /*
2578 * Class doesn't exist; add it...
2579 */
2580
2581 p = cupsdAddClass(name);
2582
2583 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
2584
2585 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2586 "Class \'%s\' added by directory services.", name);
2587
2588 /*
2589 * Force the URI to point to the real server...
2590 */
2591
2592 p->type = type & ~CUPS_PRINTER_REJECTING;
2593 p->accepting = 1;
2594 cupsdSetString(&p->uri, uri);
2595 cupsdSetString(&p->device_uri, uri);
2596 cupsdSetString(&p->hostname, host);
2597
2598 update = 1;
2599
2600 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2601 }
2602 }
2603 else
2604 {
2605 /*
2606 * Remote destination is a printer...
2607 */
2608
2609 if (!strncmp(resource, "/printers/", 10))
2610 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
2611 else
2612 return;
2613
2614 if (hptr && !*hptr)
2615 *hptr = '.'; /* Resource FQDN */
2616
2617 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
2618 {
2619 if ((p = cupsdFindDest(resource + 10)) != NULL)
2620 {
2621 if (p->hostname && strcasecmp(p->hostname, host))
2622 {
2623 /*
2624 * Nope, this isn't the same host; if the hostname isn't the local host,
2625 * add it to the other printer and then find a printer using the full host
2626 * name...
2627 */
2628
2629 if (p->type & CUPS_PRINTER_REMOTE)
2630 {
2631 cupsdLogMessage(CUPSD_LOG_DEBUG,
2632 "Renamed remote printer \"%s\" to \"%s@%s\"...",
2633 p->name, p->name, p->hostname);
2634 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2635 "Printer \'%s\' deleted by directory services.",
2636 p->name);
2637
2638 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
2639 cupsdRenamePrinter(p, newname);
2640
2641 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2642 "Printer \'%s\' added by directory services.",
2643 p->name);
2644 }
2645
2646 p = NULL;
2647 }
2648 else if (!p->hostname)
2649 {
2650 /*
2651 * Hostname not set, so this must be a cached remote printer
2652 * that was created for a pending print job...
2653 */
2654
2655 cupsdSetString(&p->hostname, host);
2656 cupsdSetString(&p->uri, uri);
2657 cupsdSetString(&p->device_uri, uri);
2658 update = 1;
2659 }
2660 }
2661 else
2662 {
2663 /*
2664 * Use the short name for this shared printer.
2665 */
2666
2667 strlcpy(name, resource + 10, sizeof(name));
2668 }
2669 }
2670 else if (p && !p->hostname)
2671 {
2672 /*
2673 * Hostname not set, so this must be a cached remote printer
2674 * that was created for a pending print job...
2675 */
2676
2677 cupsdSetString(&p->hostname, host);
2678 cupsdSetString(&p->uri, uri);
2679 cupsdSetString(&p->device_uri, uri);
2680 update = 1;
2681 }
2682
2683 if (!p)
2684 {
2685 /*
2686 * Printer doesn't exist; add it...
2687 */
2688
2689 p = cupsdAddPrinter(name);
2690
2691 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2692 "Printer \'%s\' added by directory services.", name);
2693
2694 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
2695
2696 /*
2697 * Force the URI to point to the real server...
2698 */
2699
2700 p->type = type & ~CUPS_PRINTER_REJECTING;
2701 p->accepting = 1;
2702 cupsdSetString(&p->hostname, host);
2703 cupsdSetString(&p->uri, uri);
2704 cupsdSetString(&p->device_uri, uri);
2705
2706 update = 1;
2707
2708 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2709 }
2710 }
2711
2712 /*
2713 * Update the state...
2714 */
2715
2716 p->state = state;
2717 p->browse_time = time(NULL);
2718
2719 if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
2720 attrs)) != NULL)
2721 {
2722 /*
2723 * Grab the lease-duration for the browse data; anything less then 1
2724 * second or more than 1 week gets the default BrowseTimeout...
2725 */
2726
2727 i = atoi(lease_duration);
2728 if (i < 1 || i > 604800)
2729 i = BrowseTimeout;
2730
2731 p->browse_expire = p->browse_time + i;
2732 }
2733 else
2734 p->browse_expire = p->browse_time + BrowseTimeout;
2735
2736 if (type & CUPS_PRINTER_REJECTING)
2737 {
2738 type &= ~CUPS_PRINTER_REJECTING;
2739
2740 if (p->accepting)
2741 {
2742 update = 1;
2743 p->accepting = 0;
2744 }
2745 }
2746 else if (!p->accepting)
2747 {
2748 update = 1;
2749 p->accepting = 1;
2750 }
2751
2752 if (p->type != type)
2753 {
2754 p->type = type;
2755 update = 1;
2756 }
2757
2758 if (location && (!p->location || strcmp(p->location, location)))
2759 {
2760 cupsdSetString(&p->location, location);
2761 update = 1;
2762 }
2763
2764 if (info && (!p->info || strcmp(p->info, info)))
2765 {
2766 cupsdSetString(&p->info, info);
2767 update = 1;
2768
2769 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2770 }
2771
2772 if (!make_model || !make_model[0])
2773 {
2774 if (type & CUPS_PRINTER_CLASS)
2775 snprintf(local_make_model, sizeof(local_make_model),
2776 "Remote Class on %s", host);
2777 else
2778 snprintf(local_make_model, sizeof(local_make_model),
2779 "Remote Printer on %s", host);
2780 }
2781 else
2782 snprintf(local_make_model, sizeof(local_make_model),
2783 "%s on %s", make_model, host);
2784
2785 if (!p->make_model || strcmp(p->make_model, local_make_model))
2786 {
2787 cupsdSetString(&p->make_model, local_make_model);
2788 update = 1;
2789 }
2790
2791 if (p->num_options)
2792 {
2793 if (!update && !(type & CUPS_PRINTER_DELETE))
2794 {
2795 /*
2796 * See if we need to update the attributes...
2797 */
2798
2799 if (p->num_options != num_attrs)
2800 update = 1;
2801 else
2802 {
2803 for (i = 0; i < num_attrs; i ++)
2804 if (strcmp(attrs[i].name, p->options[i].name) ||
2805 (!attrs[i].value != !p->options[i].value) ||
2806 (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
2807 {
2808 update = 1;
2809 break;
2810 }
2811 }
2812 }
2813
2814 /*
2815 * Free the old options...
2816 */
2817
2818 cupsFreeOptions(p->num_options, p->options);
2819 }
2820
2821 p->num_options = num_attrs;
2822 p->options = attrs;
2823
2824 if (type & CUPS_PRINTER_DELETE)
2825 {
2826 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2827 "%s \'%s\' deleted by directory services.",
2828 (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
2829
2830 cupsdExpireSubscriptions(p, NULL);
2831
2832 cupsdDeletePrinter(p, 1);
2833 cupsdUpdateImplicitClasses();
2834 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2835 }
2836 else if (update)
2837 {
2838 cupsdSetPrinterAttrs(p);
2839 cupsdUpdateImplicitClasses();
2840 }
2841
2842 /*
2843 * See if we have a default printer... If not, make the first network
2844 * default printer the default.
2845 */
2846
2847 if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
2848 {
2849 /*
2850 * Find the first network default printer and use it...
2851 */
2852
2853 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2854 p;
2855 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2856 if (p->type & CUPS_PRINTER_DEFAULT)
2857 {
2858 DefaultPrinter = p;
2859 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2860 break;
2861 }
2862 }
2863
2864 /*
2865 * Do auto-classing if needed...
2866 */
2867
2868 process_implicit_classes();
2869 }
2870
2871
2872 /*
2873 * 'process_implicit_classes()' - Create/update implicit classes as needed.
2874 */
2875
2876 static void
2877 process_implicit_classes(void)
2878 {
2879 int i; /* Looping var */
2880 int update; /* Update printer attributes? */
2881 char name[IPP_MAX_NAME], /* Name of printer */
2882 *hptr; /* Pointer into hostname */
2883 cupsd_printer_t *p, /* Printer information */
2884 *pclass, /* Printer class */
2885 *first; /* First printer in class */
2886 int offset, /* Offset of name */
2887 len; /* Length of name */
2888
2889
2890 if (!ImplicitClasses || !Printers)
2891 return;
2892
2893 /*
2894 * Loop through all available printers and create classes as needed...
2895 */
2896
2897 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
2898 update = 0, pclass = NULL, first = NULL;
2899 p != NULL;
2900 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2901 {
2902 /*
2903 * Skip implicit classes...
2904 */
2905
2906 if (p->type & CUPS_PRINTER_IMPLICIT)
2907 {
2908 len = 0;
2909 continue;
2910 }
2911
2912 /*
2913 * If len == 0, get the length of this printer name up to the "@"
2914 * sign (if any).
2915 */
2916
2917 cupsArraySave(Printers);
2918
2919 if (len > 0 &&
2920 !strncasecmp(p->name, name + offset, len) &&
2921 (p->name[len] == '\0' || p->name[len] == '@'))
2922 {
2923 /*
2924 * We have more than one printer with the same name; see if
2925 * we have a class, and if this printer is a member...
2926 */
2927
2928 if (pclass && strcasecmp(pclass->name, name))
2929 {
2930 if (update)
2931 cupsdSetPrinterAttrs(pclass);
2932
2933 update = 0;
2934 pclass = NULL;
2935 }
2936
2937 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
2938 {
2939 /*
2940 * Need to add the class...
2941 */
2942
2943 pclass = cupsdAddPrinter(name);
2944 cupsArrayAdd(ImplicitPrinters, pclass);
2945
2946 pclass->type |= CUPS_PRINTER_IMPLICIT;
2947 pclass->accepting = 1;
2948 pclass->state = IPP_PRINTER_IDLE;
2949
2950 cupsdSetString(&pclass->location, p->location);
2951 cupsdSetString(&pclass->info, p->info);
2952
2953 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
2954 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
2955
2956 update = 1;
2957
2958 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2959
2960 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
2961 name);
2962 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2963 "Implicit class \'%s\' added by directory services.",
2964 name);
2965 }
2966
2967 if (first != NULL)
2968 {
2969 for (i = 0; i < pclass->num_printers; i ++)
2970 if (pclass->printers[i] == first)
2971 break;
2972
2973 if (i >= pclass->num_printers)
2974 {
2975 first->in_implicit_class = 1;
2976 cupsdAddPrinterToClass(pclass, first);
2977 }
2978
2979 first = NULL;
2980 }
2981
2982 for (i = 0; i < pclass->num_printers; i ++)
2983 if (pclass->printers[i] == p)
2984 break;
2985
2986 if (i >= pclass->num_printers)
2987 {
2988 p->in_implicit_class = 1;
2989 cupsdAddPrinterToClass(pclass, p);
2990 update = 1;
2991 }
2992 }
2993 else
2994 {
2995 /*
2996 * First time around; just get name length and mark it as first
2997 * in the list...
2998 */
2999
3000 if ((hptr = strchr(p->name, '@')) != NULL)
3001 len = hptr - p->name;
3002 else
3003 len = strlen(p->name);
3004
3005 strncpy(name, p->name, len);
3006 name[len] = '\0';
3007 offset = 0;
3008
3009 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
3010 !(first->type & CUPS_PRINTER_IMPLICIT))
3011 {
3012 /*
3013 * Can't use same name as a local printer; add "Any" to the
3014 * front of the name, unless we have explicitly disabled
3015 * the "ImplicitAnyClasses"...
3016 */
3017
3018 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
3019 {
3020 /*
3021 * Add "Any" to the class name...
3022 */
3023
3024 strcpy(name, "Any");
3025 strncpy(name + 3, p->name, len);
3026 name[len + 3] = '\0';
3027 offset = 3;
3028 }
3029 else
3030 {
3031 /*
3032 * Don't create an implicit class if we have a local printer
3033 * with the same name...
3034 */
3035
3036 len = 0;
3037 cupsArrayRestore(Printers);
3038 continue;
3039 }
3040 }
3041
3042 first = p;
3043 }
3044
3045 cupsArrayRestore(Printers);
3046 }
3047
3048 /*
3049 * Update the last printer class as needed...
3050 */
3051
3052 if (pclass && update)
3053 cupsdSetPrinterAttrs(pclass);
3054 }
3055
3056
3057 /*
3058 * 'send_cups_browse()' - Send new browsing information using the CUPS
3059 * protocol.
3060 */
3061
3062 static void
3063 send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
3064 {
3065 int i; /* Looping var */
3066 cups_ptype_t type; /* Printer type */
3067 cupsd_dirsvc_addr_t *b; /* Browse address */
3068 int bytes; /* Length of packet */
3069 char packet[1453], /* Browse data packet */
3070 uri[1024], /* Printer URI */
3071 location[1024], /* printer-location */
3072 info[1024], /* printer-info */
3073 make_model[1024];
3074 /* printer-make-and-model */
3075 cupsd_netif_t *iface; /* Network interface */
3076
3077
3078 /*
3079 * Figure out the printer type value...
3080 */
3081
3082 type = p->type | CUPS_PRINTER_REMOTE;
3083
3084 if (!p->accepting)
3085 type |= CUPS_PRINTER_REJECTING;
3086
3087 if (p == DefaultPrinter)
3088 type |= CUPS_PRINTER_DEFAULT;
3089
3090 /*
3091 * Remove quotes from printer-info, printer-location, and
3092 * printer-make-and-model attributes...
3093 */
3094
3095 dequote(location, p->location, sizeof(location));
3096 dequote(info, p->info, sizeof(info));
3097
3098 if (p->make_model)
3099 dequote(make_model, p->make_model, sizeof(make_model));
3100 else if (p->type & CUPS_PRINTER_CLASS)
3101 {
3102 if (p->num_printers > 0 && p->printers[0]->make_model)
3103 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
3104 else
3105 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
3106 }
3107 else if (p->raw)
3108 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
3109 else
3110 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
3111
3112 /*
3113 * Send a packet to each browse address...
3114 */
3115
3116 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
3117 if (b->iface[0])
3118 {
3119 /*
3120 * Send the browse packet to one or more interfaces...
3121 */
3122
3123 if (!strcmp(b->iface, "*"))
3124 {
3125 /*
3126 * Send to all local interfaces...
3127 */
3128
3129 cupsdNetIFUpdate();
3130
3131 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3132 iface;
3133 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3134 {
3135 /*
3136 * Only send to local, IPv4 interfaces...
3137 */
3138
3139 if (!iface->is_local || !iface->port ||
3140 iface->address.addr.sa_family != AF_INET)
3141 continue;
3142
3143 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3144 iface->hostname, iface->port,
3145 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
3146 "/printers/%s",
3147 p->name);
3148 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3149 type, p->state, uri, location, info, make_model,
3150 p->browse_attrs ? p->browse_attrs : "");
3151
3152 bytes = strlen(packet);
3153
3154 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3155 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3156 iface->name, packet);
3157
3158 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3159
3160 sendto(BrowseSocket, packet, bytes, 0,
3161 (struct sockaddr *)&(iface->broadcast),
3162 httpAddrLength(&(iface->broadcast)));
3163 }
3164 }
3165 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
3166 {
3167 /*
3168 * Send to the named interface using the IPv4 address...
3169 */
3170
3171 while (iface)
3172 if (strcmp(b->iface, iface->name))
3173 {
3174 iface = NULL;
3175 break;
3176 }
3177 else if (iface->address.addr.sa_family == AF_INET && iface->port)
3178 break;
3179 else
3180 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
3181
3182 if (iface)
3183 {
3184 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3185 iface->hostname, iface->port,
3186 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
3187 "/printers/%s",
3188 p->name);
3189 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3190 type, p->state, uri, location, info, make_model,
3191 p->browse_attrs ? p->browse_attrs : "");
3192
3193 bytes = strlen(packet);
3194
3195 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3196 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3197 iface->name, packet);
3198
3199 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3200
3201 sendto(BrowseSocket, packet, bytes, 0,
3202 (struct sockaddr *)&(iface->broadcast),
3203 httpAddrLength(&(iface->broadcast)));
3204 }
3205 }
3206 }
3207 else
3208 {
3209 /*
3210 * Send the browse packet to the indicated address using
3211 * the default server name...
3212 */
3213
3214 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3215 type, p->state, p->uri, location, info, make_model,
3216 p->browse_attrs ? p->browse_attrs : "");
3217
3218 bytes = strlen(packet);
3219 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3220 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
3221
3222 if (sendto(BrowseSocket, packet, bytes, 0,
3223 (struct sockaddr *)&(b->to),
3224 httpAddrLength(&(b->to))) <= 0)
3225 {
3226 /*
3227 * Unable to send browse packet, so remove this address from the
3228 * list...
3229 */
3230
3231 cupsdLogMessage(CUPSD_LOG_ERROR,
3232 "cupsdSendBrowseList: sendto failed for browser "
3233 "%d - %s.",
3234 (int)(b - Browsers + 1), strerror(errno));
3235
3236 if (i > 1)
3237 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
3238
3239 b --;
3240 NumBrowsers --;
3241 }
3242 }
3243 }
3244
3245
3246 #ifdef HAVE_OPENLDAP
3247 /*
3248 * 'send_ldap_browse()' - Send LDAP printer registrations.
3249 */
3250
3251 static void
3252 send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
3253 {
3254 int i; /* Looping var... */
3255 LDAPMod mods[7]; /* The 7 attributes we will be adding */
3256 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
3257 LDAPMessage *res; /* Search result token */
3258 char *cn_value[2], /* Change records */
3259 *uri[2],
3260 *info[2],
3261 *location[2],
3262 *make_model[2],
3263 *type[2],
3264 typestring[255], /* String to hold printer-type */
3265 filter[256], /* Search filter for possible UPDATEs */
3266 dn[1024]; /* DN of the printer we are adding */
3267 int rc; /* LDAP status */
3268 static const char * const objectClass_values[] =
3269 { /* The 3 objectClass's we use in */
3270 "top", /* our LDAP entries */
3271 "device",
3272 "cupsPrinter",
3273 NULL
3274 };
3275
3276 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
3277
3278 /*
3279 * Everything in ldap is ** so we fudge around it...
3280 */
3281
3282 sprintf(typestring, "%u", p->type);
3283
3284 cn_value[0] = p->name;
3285 cn_value[1] = NULL;
3286 info[0] = p->info ? p->info : "Unknown";
3287 info[1] = NULL;
3288 location[0] = p->location ? p->location : "Unknown";
3289 location[1] = NULL;
3290 make_model[0] = p->make_model ? p->make_model : "Unknown";
3291 make_model[1] = NULL;
3292 type[0] = typestring;
3293 type[1] = NULL;
3294 uri[0] = p->uri;
3295 uri[1] = NULL;
3296
3297 snprintf(filter, sizeof(filter),
3298 "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
3299
3300 ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
3301 filter, (char **)ldap_attrs, 0, &res);
3302 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
3303 filter);
3304
3305 mods[0].mod_type = "cn";
3306 mods[0].mod_values = cn_value;
3307 mods[1].mod_type = "printerDescription";
3308 mods[1].mod_values = info;
3309 mods[2].mod_type = "printerURI";
3310 mods[2].mod_values = uri;
3311 mods[3].mod_type = "printerLocation";
3312 mods[3].mod_values = location;
3313 mods[4].mod_type = "printerMakeAndModel";
3314 mods[4].mod_values = make_model;
3315 mods[5].mod_type = "printerType";
3316 mods[5].mod_values = type;
3317 mods[6].mod_type = "objectClass";
3318 mods[6].mod_values = (char **)objectClass_values;
3319
3320 snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
3321 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
3322
3323 if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
3324 {
3325 /*
3326 * Printer has already been registered, modify the current
3327 * registration...
3328 */
3329
3330 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3331 "send_ldap_browse: Replacing entry...");
3332
3333 for (i = 0; i < 7; i ++)
3334 {
3335 pmods[i] = mods + i;
3336 pmods[i]->mod_op = LDAP_MOD_REPLACE;
3337 }
3338 pmods[i] = NULL;
3339
3340 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3341 cupsdLogMessage(CUPSD_LOG_ERROR,
3342 "LDAP modify for %s failed with status %d: %s",
3343 p->name, rc, ldap_err2string(rc));
3344 }
3345 else
3346 {
3347 /*
3348 * Printer has never been registered, add the current
3349 * registration...
3350 */
3351
3352 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3353 "send_ldap_browse: Adding entry...");
3354
3355 for (i = 0; i < 7; i ++)
3356 {
3357 pmods[i] = mods + i;
3358 pmods[i]->mod_op = LDAP_MOD_ADD;
3359 }
3360 pmods[i] = NULL;
3361
3362 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3363 cupsdLogMessage(CUPSD_LOG_ERROR,
3364 "LDAP add for %s failed with status %d: %s",
3365 p->name, rc, ldap_err2string(rc));
3366 }
3367 }
3368 #endif /* HAVE_OPENLDAP */
3369
3370
3371 #ifdef HAVE_LIBSLP
3372 /*
3373 * 'send_slp_browse()' - Register the specified printer with SLP.
3374 */
3375
3376 static void
3377 send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
3378 {
3379 char srvurl[HTTP_MAX_URI], /* Printer service URI */
3380 attrs[8192], /* Printer attributes */
3381 finishings[1024], /* Finishings to support */
3382 make_model[IPP_MAX_NAME * 2],
3383 /* Make and model, quoted */
3384 location[IPP_MAX_NAME * 2],
3385 /* Location, quoted */
3386 info[IPP_MAX_NAME * 2], /* Info, quoted */
3387 *src, /* Pointer to original string */
3388 *dst; /* Pointer to destination string */
3389 ipp_attribute_t *authentication; /* uri-authentication-supported value */
3390 SLPError error; /* SLP error, if any */
3391
3392
3393 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
3394 p->name);
3395
3396 /*
3397 * Make the SLP service URL that conforms to the IANA
3398 * 'printer:' template.
3399 */
3400
3401 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3402
3403 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
3404
3405 /*
3406 * Figure out the finishings string...
3407 */
3408
3409 if (p->type & CUPS_PRINTER_STAPLE)
3410 strcpy(finishings, "staple");
3411 else
3412 finishings[0] = '\0';
3413
3414 if (p->type & CUPS_PRINTER_BIND)
3415 {
3416 if (finishings[0])
3417 strlcat(finishings, ",bind", sizeof(finishings));
3418 else
3419 strcpy(finishings, "bind");
3420 }
3421
3422 if (p->type & CUPS_PRINTER_PUNCH)
3423 {
3424 if (finishings[0])
3425 strlcat(finishings, ",punch", sizeof(finishings));
3426 else
3427 strcpy(finishings, "punch");
3428 }
3429
3430 if (p->type & CUPS_PRINTER_COVER)
3431 {
3432 if (finishings[0])
3433 strlcat(finishings, ",cover", sizeof(finishings));
3434 else
3435 strcpy(finishings, "cover");
3436 }
3437
3438 if (p->type & CUPS_PRINTER_SORT)
3439 {
3440 if (finishings[0])
3441 strlcat(finishings, ",sort", sizeof(finishings));
3442 else
3443 strcpy(finishings, "sort");
3444 }
3445
3446 if (!finishings[0])
3447 strcpy(finishings, "none");
3448
3449 /*
3450 * Quote any commas in the make and model, location, and info strings...
3451 */
3452
3453 for (src = p->make_model, dst = make_model;
3454 src && *src && dst < (make_model + sizeof(make_model) - 2);)
3455 {
3456 if (*src == ',' || *src == '\\' || *src == ')')
3457 *dst++ = '\\';
3458
3459 *dst++ = *src++;
3460 }
3461
3462 *dst = '\0';
3463
3464 if (!make_model[0])
3465 strcpy(make_model, "Unknown");
3466
3467 for (src = p->location, dst = location;
3468 src && *src && dst < (location + sizeof(location) - 2);)
3469 {
3470 if (*src == ',' || *src == '\\' || *src == ')')
3471 *dst++ = '\\';
3472
3473 *dst++ = *src++;
3474 }
3475
3476 *dst = '\0';
3477
3478 if (!location[0])
3479 strcpy(location, "Unknown");
3480
3481 for (src = p->info, dst = info;
3482 src && *src && dst < (info + sizeof(info) - 2);)
3483 {
3484 if (*src == ',' || *src == '\\' || *src == ')')
3485 *dst++ = '\\';
3486
3487 *dst++ = *src++;
3488 }
3489
3490 *dst = '\0';
3491
3492 if (!info[0])
3493 strcpy(info, "Unknown");
3494
3495 /*
3496 * Get the authentication value...
3497 */
3498
3499 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
3500 IPP_TAG_KEYWORD);
3501
3502 /*
3503 * Make the SLP attribute string list that conforms to
3504 * the IANA 'printer:' template.
3505 */
3506
3507 snprintf(attrs, sizeof(attrs),
3508 "(printer-uri-supported=%s),"
3509 "(uri-authentication-supported=%s>),"
3510 #ifdef HAVE_SSL
3511 "(uri-security-supported=tls>),"
3512 #else
3513 "(uri-security-supported=none>),"
3514 #endif /* HAVE_SSL */
3515 "(printer-name=%s),"
3516 "(printer-location=%s),"
3517 "(printer-info=%s),"
3518 "(printer-more-info=%s),"
3519 "(printer-make-and-model=%s),"
3520 "(printer-type=%d),"
3521 "(charset-supported=utf-8),"
3522 "(natural-language-configured=%s),"
3523 "(natural-language-supported=de,en,es,fr,it),"
3524 "(color-supported=%s),"
3525 "(finishings-supported=%s),"
3526 "(sides-supported=one-sided%s),"
3527 "(multiple-document-jobs-supported=true)"
3528 "(ipp-versions-supported=1.0,1.1)",
3529 p->uri, authentication->values[0].string.text, p->name, location,
3530 info, p->uri, make_model, p->type, DefaultLanguage,
3531 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
3532 finishings,
3533 p->type & CUPS_PRINTER_DUPLEX ?
3534 ",two-sided-long-edge,two-sided-short-edge" : "");
3535
3536 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
3537
3538 /*
3539 * Register the printer with the SLP server...
3540 */
3541
3542 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
3543 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
3544
3545 if (error != SLP_OK)
3546 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
3547 error);
3548 }
3549
3550
3551 /*
3552 * 'slp_attr_callback()' - SLP attribute callback
3553 */
3554
3555 static SLPBoolean /* O - SLP_TRUE for success */
3556 slp_attr_callback(
3557 SLPHandle hslp, /* I - SLP handle */
3558 const char *attrlist, /* I - Attribute list */
3559 SLPError errcode, /* I - Parsing status for this attr */
3560 void *cookie) /* I - Current printer */
3561 {
3562 char *tmp = 0; /* Temporary string */
3563 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
3564 /* Current printer */
3565
3566
3567 (void)hslp; /* anti-compiler-warning-code */
3568
3569 /*
3570 * Bail if there was an error
3571 */
3572
3573 if (errcode != SLP_OK)
3574 return (SLP_TRUE);
3575
3576 /*
3577 * Parse the attrlist to obtain things needed to build CUPS browse packet
3578 */
3579
3580 memset(p, 0, sizeof(cupsd_printer_t));
3581
3582 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
3583 return (SLP_FALSE);
3584 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
3585 return (SLP_FALSE);
3586 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
3587 return (SLP_FALSE);
3588 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
3589 p->type = atoi(tmp);
3590 else
3591 p->type = CUPS_PRINTER_REMOTE;
3592
3593 cupsdClearString(&tmp);
3594
3595 return (SLP_TRUE);
3596 }
3597
3598
3599 /*
3600 * 'slp_dereg_printer()' - SLPDereg() the specified printer
3601 */
3602
3603 static void
3604 slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
3605 {
3606 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
3607
3608
3609 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
3610
3611 if (!(p->type & CUPS_PRINTER_REMOTE))
3612 {
3613 /*
3614 * Make the SLP service URL that conforms to the IANA
3615 * 'printer:' template.
3616 */
3617
3618 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3619
3620 /*
3621 * Deregister the printer...
3622 */
3623
3624 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
3625 }
3626 }
3627
3628
3629 /*
3630 * 'slp_get_attr()' - Get an attribute from an SLP registration.
3631 */
3632
3633 static int /* O - 0 on success */
3634 slp_get_attr(const char *attrlist, /* I - Attribute list string */
3635 const char *tag, /* I - Name of attribute */
3636 char **valbuf) /* O - Value */
3637 {
3638 char *ptr1, /* Pointer into string */
3639 *ptr2; /* ... */
3640
3641
3642 cupsdClearString(valbuf);
3643
3644 if ((ptr1 = strstr(attrlist, tag)) != NULL)
3645 {
3646 ptr1 += strlen(tag);
3647
3648 if ((ptr2 = strchr(ptr1,')')) != NULL)
3649 {
3650 /*
3651 * Copy the value...
3652 */
3653
3654 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
3655 strncpy(*valbuf, ptr1, ptr2 - ptr1);
3656
3657 /*
3658 * Dequote the value...
3659 */
3660
3661 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
3662 if (*ptr1 == '\\' && ptr1[1])
3663 _cups_strcpy(ptr1, ptr1 + 1);
3664
3665 return (0);
3666 }
3667 }
3668
3669 return (-1);
3670 }
3671
3672
3673 /*
3674 * 'slp_reg_callback()' - Empty SLPRegReport.
3675 */
3676
3677 static void
3678 slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
3679 SLPError errcode, /* I - Error code, if any */
3680 void *cookie) /* I - App data */
3681 {
3682 (void)hslp;
3683 (void)errcode;
3684 (void)cookie;
3685
3686 return;
3687 }
3688
3689
3690 /*
3691 * 'slp_url_callback()' - SLP service url callback
3692 */
3693
3694 static SLPBoolean /* O - TRUE = OK, FALSE = error */
3695 slp_url_callback(
3696 SLPHandle hslp, /* I - SLP handle */
3697 const char *srvurl, /* I - URL of service */
3698 unsigned short lifetime, /* I - Life of service */
3699 SLPError errcode, /* I - Existing error code */
3700 void *cookie) /* I - Pointer to service list */
3701 {
3702 slpsrvurl_t *s, /* New service entry */
3703 **head; /* Pointer to head of entry */
3704
3705
3706 /*
3707 * Let the compiler know we won't be using these vars...
3708 */
3709
3710 (void)hslp;
3711 (void)lifetime;
3712
3713 /*
3714 * Bail if there was an error
3715 */
3716
3717 if (errcode != SLP_OK)
3718 return (SLP_TRUE);
3719
3720 /*
3721 * Grab the head of the list...
3722 */
3723
3724 head = (slpsrvurl_t**)cookie;
3725
3726 /*
3727 * Allocate a *temporary* slpsrvurl_t to hold this entry.
3728 */
3729
3730 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
3731 return (SLP_FALSE);
3732
3733 /*
3734 * Copy the SLP service URL...
3735 */
3736
3737 strlcpy(s->url, srvurl, sizeof(s->url));
3738
3739 /*
3740 * Link the SLP service URL into the head of the list
3741 */
3742
3743 if (*head)
3744 s->next = *head;
3745
3746 *head = s;
3747
3748 return (SLP_TRUE);
3749 }
3750 #endif /* HAVE_LIBSLP */
3751
3752
3753 /*
3754 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
3755 */
3756
3757 static void
3758 update_cups_browse(void)
3759 {
3760 int i; /* Looping var */
3761 int auth; /* Authorization status */
3762 int len; /* Length of name string */
3763 int bytes; /* Number of bytes left */
3764 char packet[1541], /* Broadcast packet */
3765 *pptr; /* Pointer into packet */
3766 socklen_t srclen; /* Length of source address */
3767 http_addr_t srcaddr; /* Source address */
3768 char srcname[1024]; /* Source hostname */
3769 unsigned address[4]; /* Source address */
3770 unsigned type; /* Printer type */
3771 unsigned state; /* Printer state */
3772 char uri[HTTP_MAX_URI], /* Printer URI */
3773 host[HTTP_MAX_URI], /* Host portion of URI */
3774 resource[HTTP_MAX_URI], /* Resource portion of URI */
3775 info[IPP_MAX_NAME], /* Information string */
3776 location[IPP_MAX_NAME], /* Location string */
3777 make_model[IPP_MAX_NAME];/* Make and model string */
3778 int num_attrs; /* Number of attributes */
3779 cups_option_t *attrs; /* Attributes */
3780
3781
3782 /*
3783 * Read a packet from the browse socket...
3784 */
3785
3786 srclen = sizeof(srcaddr);
3787 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
3788 (struct sockaddr *)&srcaddr, &srclen)) < 0)
3789 {
3790 /*
3791 * "Connection refused" is returned under Linux if the destination port
3792 * or address is unreachable from a previous sendto(); check for the
3793 * error here and ignore it for now...
3794 */
3795
3796 if (errno != ECONNREFUSED && errno != EAGAIN)
3797 {
3798 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
3799 strerror(errno));
3800 cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
3801
3802 #ifdef WIN32
3803 closesocket(BrowseSocket);
3804 #else
3805 close(BrowseSocket);
3806 #endif /* WIN32 */
3807
3808 cupsdRemoveSelect(BrowseSocket);
3809 BrowseSocket = -1;
3810
3811 BrowseLocalProtocols &= ~BROWSE_CUPS;
3812 BrowseRemoteProtocols &= ~BROWSE_CUPS;
3813 }
3814
3815 return;
3816 }
3817
3818 packet[bytes] = '\0';
3819
3820 /*
3821 * If we're about to sleep, ignore incoming browse packets.
3822 */
3823
3824 if (Sleeping)
3825 return;
3826
3827 /*
3828 * Figure out where it came from...
3829 */
3830
3831 #ifdef AF_INET6
3832 if (srcaddr.addr.sa_family == AF_INET6)
3833 {
3834 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
3835 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
3836 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
3837 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
3838 }
3839 else
3840 #endif /* AF_INET6 */
3841 {
3842 address[0] = 0;
3843 address[1] = 0;
3844 address[2] = 0;
3845 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
3846 }
3847
3848 if (HostNameLookups)
3849 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
3850 else
3851 httpAddrString(&srcaddr, srcname, sizeof(srcname));
3852
3853 len = strlen(srcname);
3854
3855 /*
3856 * Do ACL stuff...
3857 */
3858
3859 if (BrowseACL)
3860 {
3861 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
3862 {
3863 /*
3864 * Access from localhost (127.0.0.1) is always allowed...
3865 */
3866
3867 auth = CUPSD_AUTH_ALLOW;
3868 }
3869 else
3870 {
3871 /*
3872 * Do authorization checks on the domain/address...
3873 */
3874
3875 switch (BrowseACL->order_type)
3876 {
3877 default :
3878 auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
3879 break;
3880
3881 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
3882 auth = CUPSD_AUTH_ALLOW;
3883
3884 if (cupsdCheckAuth(address, srcname, len,
3885 BrowseACL->num_deny, BrowseACL->deny))
3886 auth = CUPSD_AUTH_DENY;
3887
3888 if (cupsdCheckAuth(address, srcname, len,
3889 BrowseACL->num_allow, BrowseACL->allow))
3890 auth = CUPSD_AUTH_ALLOW;
3891 break;
3892
3893 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
3894 auth = CUPSD_AUTH_DENY;
3895
3896 if (cupsdCheckAuth(address, srcname, len,
3897 BrowseACL->num_allow, BrowseACL->allow))
3898 auth = CUPSD_AUTH_ALLOW;
3899
3900 if (cupsdCheckAuth(address, srcname, len,
3901 BrowseACL->num_deny, BrowseACL->deny))
3902 auth = CUPSD_AUTH_DENY;
3903 break;
3904 }
3905 }
3906 }
3907 else
3908 auth = CUPSD_AUTH_ALLOW;
3909
3910 if (auth == CUPSD_AUTH_DENY)
3911 {
3912 cupsdLogMessage(CUPSD_LOG_DEBUG,
3913 "update_cups_browse: Refused %d bytes from %s", bytes,
3914 srcname);
3915 return;
3916 }
3917
3918 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3919 "update_cups_browse: (%d bytes from %s) %s", bytes,
3920 srcname, packet);
3921
3922 /*
3923 * Parse packet...
3924 */
3925
3926 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
3927 {
3928 cupsdLogMessage(CUPSD_LOG_WARN,
3929 "update_cups_browse: Garbled browse packet - %s", packet);
3930 return;
3931 }
3932
3933 strcpy(location, "Location Unknown");
3934 strcpy(info, "No Information Available");
3935 make_model[0] = '\0';
3936 num_attrs = 0;
3937 attrs = NULL;
3938
3939 if ((pptr = strchr(packet, '\"')) != NULL)
3940 {
3941 /*
3942 * Have extended information; can't use sscanf for it because not all
3943 * sscanf's allow empty strings with %[^\"]...
3944 */
3945
3946 for (i = 0, pptr ++;
3947 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
3948 i ++, pptr ++)
3949 location[i] = *pptr;
3950
3951 if (i)
3952 location[i] = '\0';
3953
3954 if (*pptr == '\"')
3955 pptr ++;
3956
3957 while (*pptr && isspace(*pptr & 255))
3958 pptr ++;
3959
3960 if (*pptr == '\"')
3961 {
3962 for (i = 0, pptr ++;
3963 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
3964 i ++, pptr ++)
3965 info[i] = *pptr;
3966
3967 info[i] = '\0';
3968
3969 if (*pptr == '\"')
3970 pptr ++;
3971
3972 while (*pptr && isspace(*pptr & 255))
3973 pptr ++;
3974
3975 if (*pptr == '\"')
3976 {
3977 for (i = 0, pptr ++;
3978 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
3979 i ++, pptr ++)
3980 make_model[i] = *pptr;
3981
3982 if (*pptr == '\"')
3983 pptr ++;
3984
3985 make_model[i] = '\0';
3986
3987 if (*pptr)
3988 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
3989 }
3990 }
3991 }
3992
3993 DEBUG_puts(packet);
3994 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
3995 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
3996 type, state, uri, location, info, make_model));
3997
3998 /*
3999 * Pull the URI apart to see if this is a local or remote printer...
4000 */
4001
4002 if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
4003 {
4004 cupsFreeOptions(num_attrs, attrs);
4005 return;
4006 }
4007
4008 /*
4009 * Do relaying...
4010 */
4011
4012 for (i = 0; i < NumRelays; i ++)
4013 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
4014 if (sendto(BrowseSocket, packet, bytes, 0,
4015 (struct sockaddr *)&(Relays[i].to),
4016 httpAddrLength(&(Relays[i].to))) <= 0)
4017 {
4018 cupsdLogMessage(CUPSD_LOG_ERROR,
4019 "update_cups_browse: sendto failed for relay %d - %s.",
4020 i + 1, strerror(errno));
4021 cupsFreeOptions(num_attrs, attrs);
4022 return;
4023 }
4024
4025 /*
4026 * Process the browse data...
4027 */
4028
4029 process_browse_data(uri, host, resource, (cups_ptype_t)type,
4030 (ipp_pstate_t)state, location, info, make_model,
4031 num_attrs, attrs);
4032 }
4033
4034
4035 /*
4036 * 'update_lpd()' - Update the LPD configuration as needed.
4037 */
4038
4039 static void
4040 update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
4041 {
4042 if (!LPDConfigFile)
4043 return;
4044
4045 #ifdef __APPLE__
4046 /*
4047 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
4048 * setting for backwards-compatibility.
4049 */
4050
4051 if (onoff && !get_hostconfig("CUPS_LPD"))
4052 onoff = 0;
4053 #endif /* __APPLE__ */
4054
4055 if (!strncmp(LPDConfigFile, "xinetd:///", 10))
4056 {
4057 /*
4058 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
4059 */
4060
4061 char newfile[1024]; /* New cups-lpd.N file */
4062 cups_file_t *ofp, /* Original file pointer */
4063 *nfp; /* New file pointer */
4064 char line[1024]; /* Line from file */
4065
4066
4067 snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
4068
4069 if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
4070 {
4071 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
4072 LPDConfigFile + 9, strerror(errno));
4073 return;
4074 }
4075
4076 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
4077 {
4078 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
4079 newfile, strerror(errno));
4080 cupsFileClose(ofp);
4081 return;
4082 }
4083
4084 /*
4085 * Copy all of the lines from the cups-lpd file...
4086 */
4087
4088 while (cupsFileGets(ofp, line, sizeof(line)))
4089 {
4090 if (line[0] == '{')
4091 {
4092 cupsFilePrintf(nfp, "%s\n", line);
4093 snprintf(line, sizeof(line), "\tdisable = %s",
4094 onoff ? "no" : "yes");
4095 }
4096 else if (!strstr(line, "disable ="))
4097 cupsFilePrintf(nfp, "%s\n", line);
4098 }
4099
4100 cupsFileClose(nfp);
4101 cupsFileClose(ofp);
4102 rename(newfile, LPDConfigFile + 9);
4103 }
4104 #ifdef __APPLE__
4105 else if (!strncmp(LPDConfigFile, "launchd:///", 11))
4106 {
4107 /*
4108 * Enable/disable LPD via the launchctl command...
4109 */
4110
4111 char *argv[5], /* Arguments for command */
4112 *envp[MAX_ENV]; /* Environment for command */
4113 int pid; /* Process ID */
4114
4115
4116 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
4117 argv[0] = (char *)"launchctl";
4118 argv[1] = (char *)(onoff ? "load" : "unload");
4119 argv[2] = (char *)"-w";
4120 argv[3] = LPDConfigFile + 10;
4121 argv[4] = NULL;
4122
4123 cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
4124 NULL, &pid);
4125 }
4126 #endif /* __APPLE__ */
4127 else
4128 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
4129 }
4130
4131
4132 /*
4133 * 'update_polling()' - Read status messages from the poll daemons.
4134 */
4135
4136 static void
4137 update_polling(void)
4138 {
4139 char *ptr, /* Pointer to end of line in buffer */
4140 message[1024]; /* Pointer to message text */
4141 int loglevel; /* Log level for message */
4142
4143
4144 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
4145 message, sizeof(message))) != NULL)
4146 if (!strchr(PollStatusBuffer->buffer, '\n'))
4147 break;
4148
4149 if (ptr == NULL && !PollStatusBuffer->bufused)
4150 {
4151 /*
4152 * All polling processes have died; stop polling...
4153 */
4154
4155 cupsdLogMessage(CUPSD_LOG_ERROR,
4156 "update_polling: all polling processes have exited!");
4157 cupsdStopPolling();
4158 }
4159 }
4160
4161
4162 /*
4163 * 'update_smb()' - Update the SMB configuration as needed.
4164 */
4165
4166 static void
4167 update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
4168 {
4169 if (!SMBConfigFile)
4170 return;
4171
4172 if (!strncmp(SMBConfigFile, "samba:///", 9))
4173 {
4174 /*
4175 * Enable/disable SMB via the specified smb.conf config file...
4176 */
4177
4178 char newfile[1024]; /* New smb.conf.N file */
4179 cups_file_t *ofp, /* Original file pointer */
4180 *nfp; /* New file pointer */
4181 char line[1024]; /* Line from file */
4182 int in_printers; /* In [printers] section? */
4183
4184
4185 snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
4186
4187 if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
4188 {
4189 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
4190 SMBConfigFile + 8, strerror(errno));
4191 return;
4192 }
4193
4194 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
4195 {
4196 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
4197 newfile, strerror(errno));
4198 cupsFileClose(ofp);
4199 return;
4200 }
4201
4202 /*
4203 * Copy all of the lines from the smb.conf file...
4204 */
4205
4206 in_printers = 0;
4207
4208 while (cupsFileGets(ofp, line, sizeof(line)))
4209 {
4210 if (in_printers && strstr(line, "printable ="))
4211 snprintf(line, sizeof(line), " printable = %s",
4212 onoff ? "yes" : "no");
4213
4214 cupsFilePrintf(nfp, "%s\n", line);
4215
4216 if (line[0] == '[')
4217 in_printers = !strcmp(line, "[printers]");
4218 }
4219
4220 cupsFileClose(nfp);
4221 cupsFileClose(ofp);
4222 rename(newfile, SMBConfigFile + 8);
4223 }
4224 else
4225 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
4226 }
4227
4228
4229 /*
4230 * End of "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $".
4231 */