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