]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
Merge changes from CUPS 1.4svn-r7547.
[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) && DNSSDPort)
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) && DNSSDPort)
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 #endif /* HAVE_DNSSD */
1412
1413 #ifdef HAVE_LIBSLP
1414 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1415 BrowseSLPHandle)
1416 {
1417 /*
1418 * Close SLP handle...
1419 */
1420
1421 SLPClose(BrowseSLPHandle);
1422 BrowseSLPHandle = NULL;
1423 }
1424 #endif /* HAVE_LIBSLP */
1425
1426 #ifdef HAVE_OPENLDAP
1427 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1428 BrowseLDAPHandle)
1429 {
1430 ldap_unbind(BrowseLDAPHandle);
1431 BrowseLDAPHandle = NULL;
1432 }
1433 #endif /* HAVE_OPENLDAP */
1434
1435 /*
1436 * Disable LPD and SMB printer sharing as needed through external programs...
1437 */
1438
1439 if (BrowseLocalProtocols & BROWSE_LPD)
1440 update_lpd(0);
1441
1442 if (BrowseLocalProtocols & BROWSE_SMB)
1443 update_smb(0);
1444 }
1445
1446
1447 /*
1448 * 'cupsdStopPolling()' - Stop polling servers as needed.
1449 */
1450
1451 void
1452 cupsdStopPolling(void)
1453 {
1454 int i; /* Looping var */
1455 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1456
1457
1458 if (PollPipe >= 0)
1459 {
1460 cupsdStatBufDelete(PollStatusBuffer);
1461 close(PollPipe);
1462
1463 cupsdRemoveSelect(PollPipe);
1464
1465 PollPipe = -1;
1466 PollStatusBuffer = NULL;
1467 }
1468
1469 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1470 if (pollp->pid)
1471 cupsdEndProcess(pollp->pid, 0);
1472 }
1473
1474
1475 #ifdef HAVE_DNSSD
1476 /*
1477 * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
1478 */
1479
1480 void
1481 cupsdUpdateDNSSDBrowse(void)
1482 {
1483 DNSServiceErrorType sdErr; /* Service discovery error */
1484
1485
1486 if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
1487 cupsdLogMessage(CUPSD_LOG_ERROR,
1488 "DNS Service Discovery registration error %d!",
1489 sdErr);
1490 }
1491
1492
1493 /*
1494 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1495 */
1496
1497 void
1498 cupsdUpdateDNSSDName(void)
1499 {
1500 DNSServiceErrorType error; /* Error from service creation */
1501 char webif[1024]; /* Web interface share name */
1502 #ifdef HAVE_COREFOUNDATION_H
1503 CFStringRef nameRef; /* Computer name CFString */
1504 char nameBuffer[1024]; /* C-string buffer */
1505 CFStringEncoding nameEncoding; /* Computer name encoding */
1506 #endif /* HAVE_COREFOUNDATION_H */
1507
1508
1509 /*
1510 * Only share the web interface and printers when non-local listening is
1511 * enabled...
1512 */
1513
1514 if (!DNSSDPort)
1515 return;
1516
1517 /*
1518 * Get the computer name as a c-string...
1519 */
1520
1521 #ifdef HAVE_COREFOUNDATION_H
1522 cupsdClearString(&DNSSDName);
1523
1524 if ((nameRef = SCDynamicStoreCopyComputerName(NULL,
1525 &nameEncoding)) != NULL)
1526 {
1527 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
1528 kCFStringEncodingUTF8))
1529 cupsdSetString(&DNSSDName, nameBuffer);
1530
1531 CFRelease(nameRef);
1532 }
1533
1534 #else
1535 cupsdSetString(&DNSSDName, ServerName);
1536 #endif /* HAVE_COREFOUNDATION_H */
1537
1538 /*
1539 * Then (re)register the web interface...
1540 */
1541
1542 if (DNSSDName)
1543 snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName);
1544 else
1545 strlcpy(webif, "CUPS Web Interface", sizeof(webif));
1546
1547 if (WebIFRef)
1548 DNSServiceRefDeallocate(WebIFRef);
1549
1550 WebIFRef = DNSSDRef;
1551 if ((error = DNSServiceRegister(&WebIFRef,
1552 kDNSServiceFlagsShareConnection,
1553 0, webif, "_http._tcp", NULL,
1554 NULL, htons(DNSSDPort), 7,
1555 "\006path=/", dnssdRegisterCallback,
1556 NULL)) != kDNSServiceErr_NoError)
1557 cupsdLogMessage(CUPSD_LOG_ERROR,
1558 "DNS-SD web interface registration failed: %d", error);
1559 }
1560 #endif /* HAVE_DNSSD */
1561
1562
1563 #ifdef HAVE_OPENLDAP
1564 /*
1565 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
1566 */
1567
1568 void
1569 cupsdUpdateLDAPBrowse(void)
1570 {
1571 char uri[HTTP_MAX_URI], /* Printer URI */
1572 host[HTTP_MAX_URI], /* Hostname */
1573 resource[HTTP_MAX_URI], /* Resource path */
1574 location[1024], /* Printer location */
1575 info[1024], /* Printer information */
1576 make_model[1024], /* Printer make and model */
1577 **value; /* Holds the returned data from LDAP */
1578 int type; /* Printer type */
1579 int rc; /* LDAP status */
1580 int limit; /* Size limit */
1581 LDAPMessage *res, /* LDAP search results */
1582 *e; /* Current entry from search */
1583
1584
1585 /*
1586 * Search for printers...
1587 */
1588
1589 cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
1590
1591 BrowseLDAPRefresh = time(NULL) + BrowseInterval;
1592
1593 rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
1594 "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
1595 if (rc != LDAP_SUCCESS)
1596 {
1597 cupsdLogMessage(CUPSD_LOG_ERROR,
1598 "LDAP search returned error %d: %s", rc,
1599 ldap_err2string(rc));
1600 return;
1601 }
1602
1603 limit = ldap_count_entries(BrowseLDAPHandle, res);
1604 cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
1605 if (limit < 1)
1606 return;
1607
1608 /*
1609 * Loop through the available printers...
1610 */
1611
1612 for (e = ldap_first_entry(BrowseLDAPHandle, res);
1613 e;
1614 e = ldap_next_entry(BrowseLDAPHandle, e))
1615 {
1616 /*
1617 * Get the required values from this entry...
1618 */
1619
1620 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1621 "printerDescription")) == NULL)
1622 continue;
1623
1624 strlcpy(info, *value, sizeof(info));
1625 ldap_value_free(value);
1626
1627 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1628 "printerLocation")) == NULL)
1629 continue;
1630
1631 strlcpy(location, *value, sizeof(location));
1632 ldap_value_free(value);
1633
1634 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1635 "printerMakeAndModel")) == NULL)
1636 continue;
1637
1638 strlcpy(make_model, *value, sizeof(make_model));
1639 ldap_value_free(value);
1640
1641 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1642 "printerType")) == NULL)
1643 continue;
1644
1645 type = atoi(*value);
1646 ldap_value_free(value);
1647
1648 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1649 "printerURI")) == NULL)
1650 continue;
1651
1652 strlcpy(uri, *value, sizeof(uri));
1653 ldap_value_free(value);
1654
1655 /*
1656 * Process the entry as browse data...
1657 */
1658
1659 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
1660 process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
1661 location, info, make_model, 0, NULL);
1662
1663 }
1664 }
1665 #endif /* HAVE_OPENLDAP */
1666
1667
1668 #ifdef HAVE_LIBSLP
1669 /*
1670 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
1671 */
1672
1673 void
1674 cupsdUpdateSLPBrowse(void)
1675 {
1676 slpsrvurl_t *s, /* Temporary list of service URLs */
1677 *next; /* Next service in list */
1678 cupsd_printer_t p; /* Printer information */
1679 const char *uri; /* Pointer to printer URI */
1680 char host[HTTP_MAX_URI], /* Host portion of URI */
1681 resource[HTTP_MAX_URI]; /* Resource portion of URI */
1682
1683
1684 /*
1685 * Reset the refresh time...
1686 */
1687
1688 BrowseSLPRefresh = time(NULL) + BrowseInterval;
1689
1690 /*
1691 * Poll for remote printers using SLP...
1692 */
1693
1694 s = NULL;
1695
1696 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
1697 slp_url_callback, &s);
1698
1699 /*
1700 * Loop through the list of available printers...
1701 */
1702
1703 for (; s; s = next)
1704 {
1705 /*
1706 * Save the "next" pointer...
1707 */
1708
1709 next = s->next;
1710
1711 /*
1712 * Load a cupsd_printer_t structure with the SLP service attributes...
1713 */
1714
1715 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
1716
1717 /*
1718 * Process this printer entry...
1719 */
1720
1721 uri = s->url + SLP_CUPS_SRVLEN + 1;
1722
1723 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
1724 {
1725 /*
1726 * Pull the URI apart to see if this is a local or remote printer...
1727 */
1728
1729 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
1730 process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
1731 p.location, p.info, p.make_model, 0, NULL);
1732 }
1733
1734 /*
1735 * Free this listing...
1736 */
1737
1738 cupsdClearString(&p.info);
1739 cupsdClearString(&p.location);
1740 cupsdClearString(&p.make_model);
1741
1742 free(s);
1743 }
1744 }
1745 #endif /* HAVE_LIBSLP */
1746
1747
1748 /*
1749 * 'dequote()' - Remote quotes from a string.
1750 */
1751
1752 static char * /* O - Dequoted string */
1753 dequote(char *d, /* I - Destination string */
1754 const char *s, /* I - Source string */
1755 int dlen) /* I - Destination length */
1756 {
1757 char *dptr; /* Pointer into destination */
1758
1759
1760 if (s)
1761 {
1762 for (dptr = d, dlen --; *s && dlen > 0; s ++)
1763 if (*s != '\"')
1764 {
1765 *dptr++ = *s;
1766 dlen --;
1767 }
1768
1769 *dptr = '\0';
1770 }
1771 else
1772 *d = '\0';
1773
1774 return (d);
1775 }
1776
1777
1778 #ifdef HAVE_DNSSD
1779 /*
1780 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
1781 */
1782
1783 static char * /* O - TXT record */
1784 dnssdBuildTxtRecord(
1785 int *txt_len, /* O - TXT record length */
1786 cupsd_printer_t *p, /* I - Printer information */
1787 int for_lpd) /* I - 1 = LPD, 0 = IPP */
1788 {
1789 int i, j; /* Looping vars */
1790 char type_str[32], /* Type to string buffer */
1791 state_str[32], /* State to string buffer */
1792 rp_str[1024], /* Queue name string buffer */
1793 air_str[1024], /* auth-info-required string buffer */
1794 *keyvalue[32][2]; /* Table of key/value pairs */
1795
1796
1797 /*
1798 * Load up the key value pairs...
1799 */
1800
1801 i = 0;
1802
1803 keyvalue[i ][0] = "txtvers";
1804 keyvalue[i++][1] = "1";
1805
1806 keyvalue[i ][0] = "qtotal";
1807 keyvalue[i++][1] = "1";
1808
1809 keyvalue[i ][0] = "rp";
1810 keyvalue[i++][1] = rp_str;
1811 if (for_lpd)
1812 strlcpy(rp_str, p->name, sizeof(rp_str));
1813 else
1814 snprintf(rp_str, sizeof(rp_str), "%s/%s",
1815 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
1816
1817 keyvalue[i ][0] = "ty";
1818 keyvalue[i++][1] = p->make_model;
1819
1820 if (p->location && *p->location != '\0')
1821 {
1822 keyvalue[i ][0] = "note";
1823 keyvalue[i++][1] = p->location;
1824 }
1825
1826 keyvalue[i ][0] = "priority";
1827 keyvalue[i++][1] = for_lpd ? "100" : "0";
1828
1829 keyvalue[i ][0] = "product";
1830 keyvalue[i++][1] = p->product ? p->product : "Unknown";
1831
1832 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
1833 snprintf(state_str, sizeof(state_str), "%d", p->state);
1834
1835 keyvalue[i ][0] = "printer-state";
1836 keyvalue[i++][1] = state_str;
1837
1838 keyvalue[i ][0] = "printer-type";
1839 keyvalue[i++][1] = type_str;
1840
1841 keyvalue[i ][0] = "Transparent";
1842 keyvalue[i++][1] = "T";
1843
1844 keyvalue[i ][0] = "Binary";
1845 keyvalue[i++][1] = "T";
1846
1847 if ((p->type & CUPS_PRINTER_FAX))
1848 {
1849 keyvalue[i ][0] = "Fax";
1850 keyvalue[i++][1] = "T";
1851 }
1852
1853 if ((p->type & CUPS_PRINTER_COLOR))
1854 {
1855 keyvalue[i ][0] = "Color";
1856 keyvalue[i++][1] = "T";
1857 }
1858
1859 if ((p->type & CUPS_PRINTER_DUPLEX))
1860 {
1861 keyvalue[i ][0] = "Duplex";
1862 keyvalue[i++][1] = "T";
1863 }
1864
1865 if ((p->type & CUPS_PRINTER_STAPLE))
1866 {
1867 keyvalue[i ][0] = "Staple";
1868 keyvalue[i++][1] = "T";
1869 }
1870
1871 if ((p->type & CUPS_PRINTER_COPIES))
1872 {
1873 keyvalue[i ][0] = "Copies";
1874 keyvalue[i++][1] = "T";
1875 }
1876
1877 if ((p->type & CUPS_PRINTER_COLLATE))
1878 {
1879 keyvalue[i ][0] = "Collate";
1880 keyvalue[i++][1] = "T";
1881 }
1882
1883 if ((p->type & CUPS_PRINTER_PUNCH))
1884 {
1885 keyvalue[i ][0] = "Punch";
1886 keyvalue[i++][1] = "T";
1887 }
1888
1889 if ((p->type & CUPS_PRINTER_BIND))
1890 {
1891 keyvalue[i ][0] = "Bind";
1892 keyvalue[i++][1] = "T";
1893 }
1894
1895 if ((p->type & CUPS_PRINTER_SORT))
1896 {
1897 keyvalue[i ][0] = "Sort";
1898 keyvalue[i++][1] = "T";
1899 }
1900
1901 keyvalue[i ][0] = "pdl";
1902 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
1903
1904 if (p->num_auth_info_required)
1905 {
1906 char *air = air_str; /* Pointer into string */
1907
1908
1909 for (j = 0; j < p->num_auth_info_required; j ++)
1910 {
1911 if (air >= (air_str + sizeof(air_str) - 2))
1912 break;
1913
1914 if (j)
1915 *air++ = ',';
1916
1917 strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
1918 air += strlen(air);
1919 }
1920
1921 keyvalue[i ][0] = "air";
1922 keyvalue[i++][1] = air;
1923 }
1924
1925 /*
1926 * Then pack them into a proper txt record...
1927 */
1928
1929 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
1930 }
1931
1932
1933 /*
1934 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
1935 */
1936
1937 static int /* O - Result of comparison */
1938 dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
1939 cupsd_printer_t *b)/* I - Second printer */
1940 {
1941 return (strcasecmp(a->reg_name, b->reg_name));
1942 }
1943
1944
1945 /*
1946 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
1947 * printer.
1948 */
1949
1950 static void
1951 dnssdDeregisterPrinter(
1952 cupsd_printer_t *p) /* I - Printer */
1953 {
1954 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
1955
1956 /*
1957 * Closing the socket deregisters the service
1958 */
1959
1960 if (p->ipp_ref)
1961 {
1962 DNSServiceRefDeallocate(p->ipp_ref);
1963 p->ipp_ref = NULL;
1964 }
1965
1966 cupsArrayRemove(DNSSDPrinters, p);
1967 cupsdClearString(&p->reg_name);
1968
1969 if (p->ipp_txt)
1970 {
1971 /*
1972 * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
1973 */
1974
1975 free(p->ipp_txt);
1976 p->ipp_txt = NULL;
1977 }
1978 }
1979
1980
1981 /*
1982 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
1983 * TXT record format.
1984 */
1985
1986 static char * /* O - TXT record */
1987 dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
1988 char *keyvalue[][2], /* I - Table of key value pairs */
1989 int count) /* I - Items in table */
1990 {
1991 int i; /* Looping var */
1992 int length; /* Length of TXT record */
1993 int length2; /* Length of value */
1994 char *txtRecord; /* TXT record buffer */
1995 char *cursor; /* Looping pointer */
1996
1997
1998 /*
1999 * Calculate the buffer size
2000 */
2001
2002 for (length = i = 0; i < count; i++)
2003 length += 1 + strlen(keyvalue[i][0]) +
2004 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2005
2006 /*
2007 * Allocate and fill it
2008 */
2009
2010 txtRecord = malloc(length);
2011 if (txtRecord)
2012 {
2013 *txt_len = length;
2014
2015 for (cursor = txtRecord, i = 0; i < count; i++)
2016 {
2017 /*
2018 * Drop in the p-string style length byte followed by the data
2019 */
2020
2021 length = strlen(keyvalue[i][0]);
2022 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2023
2024 *cursor++ = (unsigned char)(length + length2);
2025
2026 memcpy(cursor, keyvalue[i][0], length);
2027 cursor += length;
2028
2029 if (length2)
2030 {
2031 length2 --;
2032 *cursor++ = '=';
2033 memcpy(cursor, keyvalue[i][1], length2);
2034 cursor += length2;
2035 }
2036 }
2037 }
2038
2039 return (txtRecord);
2040 }
2041
2042
2043 /*
2044 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2045 */
2046
2047 static void
2048 dnssdRegisterCallback(
2049 DNSServiceRef sdRef, /* I - DNS Service reference */
2050 DNSServiceFlags flags, /* I - Reserved for future use */
2051 DNSServiceErrorType errorCode, /* I - Error code */
2052 const char *name, /* I - Service name */
2053 const char *regtype, /* I - Service type */
2054 const char *domain, /* I - Domain. ".local" for now */
2055 void *context) /* I - User-defined context */
2056 {
2057 cupsd_printer_t *p = (cupsd_printer_t *)context;
2058 /* Current printer */
2059
2060
2061 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s",
2062 name, regtype, p ? p->name : "Web Interface");
2063
2064 if (errorCode)
2065 {
2066 cupsdLogMessage(CUPSD_LOG_ERROR,
2067 "DNSServiceRegister failed with error %d", (int)errorCode);
2068 return;
2069 }
2070 else if (p && strcasecmp(name, p->reg_name))
2071 {
2072 cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2073 name, p->name);
2074
2075 cupsArrayRemove(DNSSDPrinters, p);
2076 cupsdSetString(&p->reg_name, name);
2077 cupsArrayAdd(DNSSDPrinters, p);
2078
2079 LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2080 }
2081 }
2082
2083
2084 /*
2085 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2086 * or update the broadcast contents.
2087 */
2088
2089 static void
2090 dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2091 {
2092 DNSServiceErrorType se; /* dnssd errors */
2093 char *ipp_txt, /* IPP TXT record buffer */
2094 *printer_txt, /* LPD TXT record buffer */
2095 name[1024], /* Service name */
2096 *nameptr; /* Pointer into name */
2097 int ipp_len, /* IPP TXT record length */
2098 printer_len; /* LPD TXT record length */
2099 char resource[1024]; /* Resource path for printer */
2100 const char *regtype; /* Registration type */
2101 const char *domain; /* Registration domain */
2102 cupsd_location_t *location, /* Printer location */
2103 *policy; /* Operation policy for Print-Job */
2104 unsigned address[4]; /* INADDR_ANY address */
2105
2106
2107 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2108 !p->ipp_ref ? "new" : "update");
2109
2110 /*
2111 * If per-printer sharing was just disabled make sure we're not
2112 * registered before returning.
2113 */
2114
2115 if (!p->shared)
2116 {
2117 dnssdDeregisterPrinter(p);
2118 return;
2119 }
2120
2121 /*
2122 * The registered name takes the form of "<printer-info> @ <computer name>"...
2123 */
2124
2125 if (p->info && strlen(p->info) > 0)
2126 {
2127 if (DNSSDName)
2128 snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName);
2129 else
2130 strlcpy(name, p->info, sizeof(name));
2131 }
2132 else if (DNSSDName)
2133 snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName);
2134 else
2135 strlcpy(name, p->name, sizeof(name));
2136
2137 /*
2138 * If an existing printer was renamed, unregister it and start over...
2139 */
2140
2141 if (p->reg_name && strcmp(p->reg_name, name))
2142 dnssdDeregisterPrinter(p);
2143
2144 if (!p->reg_name)
2145 {
2146 cupsdSetString(&p->reg_name, name);
2147 cupsArrayAdd(DNSSDPrinters, p);
2148 }
2149
2150 /*
2151 * If 'Allow printing from the Internet' is enabled (i.e. from any address)
2152 * let dnssd decide on the domain, otherwise restrict it to ".local".
2153 */
2154
2155 if (p->type & CUPS_PRINTER_CLASS)
2156 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
2157 else
2158 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
2159
2160 address[0] = address[1] = address[2] = address[3] = 0;
2161 location = cupsdFindBest(resource, HTTP_POST);
2162 policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
2163
2164 if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
2165 (policy && !cupsdCheckAccess(address, "", 0, policy)))
2166 domain = "local.";
2167 else
2168 domain = NULL;
2169
2170 /*
2171 * Register IPP and (optionally) LPD...
2172 */
2173
2174 ipp_len = 0; /* anti-compiler-warning-code */
2175 ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
2176
2177 if (!p->ipp_ref)
2178 {
2179 /*
2180 * Initial registration. Use the _fax subtype for fax queues...
2181 */
2182
2183 regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
2184 "_ipp._tcp,_cups";
2185
2186 cupsdLogMessage(CUPSD_LOG_DEBUG,
2187 "Registering DNS-SD printer %s with name \"%s\", "
2188 "type \"%s\", and domain \"%s\"", p->name, name, regtype,
2189 domain ? domain : "(null)");
2190
2191 /*
2192 * Register the queue, dropping characters as needed until we succeed...
2193 */
2194
2195 nameptr = name + strlen(name);
2196
2197 do
2198 {
2199 p->ipp_ref = DNSSDRef;
2200 if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
2201 0, name, regtype, domain, NULL,
2202 htons(DNSSDPort), ipp_len, ipp_txt,
2203 dnssdRegisterCallback,
2204 p)) == kDNSServiceErr_BadParam)
2205 {
2206 /*
2207 * Name is too long, drop trailing characters, taking into account
2208 * UTF-8 encoding...
2209 */
2210
2211 nameptr --;
2212
2213 while (nameptr > name && (*nameptr & 0xc0) == 0x80)
2214 nameptr --;
2215
2216 if (nameptr > name)
2217 *nameptr = '\0';
2218 }
2219 }
2220 while (se == kDNSServiceErr_BadParam && nameptr > name);
2221
2222 if (se == kDNSServiceErr_NoError)
2223 {
2224 p->ipp_txt = ipp_txt;
2225 p->ipp_len = ipp_len;
2226 ipp_txt = NULL;
2227 }
2228 else
2229 cupsdLogMessage(CUPSD_LOG_WARN,
2230 "DNS-SD IPP registration of \"%s\" failed: %d",
2231 p->name, se);
2232 }
2233 else if (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))
2234 {
2235 /*
2236 * Update the existing registration...
2237 */
2238
2239 /* A TTL of 0 means use record's original value (Radar 3176248) */
2240 DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, 0);
2241
2242 if (p->ipp_txt)
2243 free(p->ipp_txt);
2244
2245 p->ipp_txt = ipp_txt;
2246 p->ipp_len = ipp_len;
2247 ipp_txt = NULL;
2248 }
2249
2250 if (ipp_txt)
2251 free(ipp_txt);
2252
2253 if (BrowseLocalProtocols & BROWSE_LPD)
2254 {
2255 printer_len = 0; /* anti-compiler-warning-code */
2256 printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
2257
2258 if (!p->printer_ref)
2259 {
2260 /*
2261 * Initial registration...
2262 */
2263
2264 cupsdLogMessage(CUPSD_LOG_DEBUG,
2265 "Registering DNS-SD printer %s with name \"%s\", "
2266 "type \"_printer._tcp\", and domain \"%s\"", p->name,
2267 name, domain ? domain : "(null)");
2268
2269 p->printer_ref = DNSSDRef;
2270 if ((se = DNSServiceRegister(&p->printer_ref,
2271 kDNSServiceFlagsShareConnection,
2272 0, name, "_printer._tcp", domain, NULL,
2273 htons(515), printer_len, printer_txt,
2274 dnssdRegisterCallback,
2275 p)) == kDNSServiceErr_NoError)
2276 {
2277 p->printer_txt = printer_txt;
2278 p->printer_len = printer_len;
2279 printer_txt = NULL;
2280 }
2281 else
2282 cupsdLogMessage(CUPSD_LOG_WARN,
2283 "DNS-SD LPD registration of \"%s\" failed: %d",
2284 p->name, se);
2285 }
2286 else if (printer_len != p->printer_len ||
2287 memcmp(printer_txt, p->printer_txt, printer_len))
2288 {
2289 /*
2290 * Update the existing registration...
2291 */
2292
2293 /* A TTL of 0 means use record's original value (Radar 3176248) */
2294 DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
2295 printer_txt, 0);
2296
2297 if (p->printer_txt)
2298 free(p->printer_txt);
2299
2300 p->printer_txt = printer_txt;
2301 p->printer_len = printer_len;
2302 printer_txt = NULL;
2303 }
2304
2305 if (printer_txt)
2306 free(printer_txt);
2307 }
2308 }
2309 #endif /* HAVE_DNSSD */
2310
2311
2312 #ifdef __APPLE__
2313 /*
2314 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
2315 */
2316
2317 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
2318 get_hostconfig(const char *name) /* I - Name of service */
2319 {
2320 cups_file_t *fp; /* Hostconfig file */
2321 char line[1024], /* Line from file */
2322 *ptr; /* Pointer to value */
2323 int state = 1; /* State of service */
2324
2325
2326 /*
2327 * Try opening the /etc/hostconfig file; if we can't open it, assume that
2328 * the service is enabled/auto.
2329 */
2330
2331 if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
2332 {
2333 /*
2334 * Read lines from the file until we find the service...
2335 */
2336
2337 while (cupsFileGets(fp, line, sizeof(line)))
2338 {
2339 if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
2340 continue;
2341
2342 *ptr++ = '\0';
2343
2344 if (!strcasecmp(line, name))
2345 {
2346 /*
2347 * Found the service, see if it is set to "-NO-"...
2348 */
2349
2350 if (!strncasecmp(ptr, "-NO-", 4))
2351 state = 0;
2352 break;
2353 }
2354 }
2355
2356 cupsFileClose(fp);
2357 }
2358
2359 return (state);
2360 }
2361 #endif /* __APPLE__ */
2362
2363
2364 /*
2365 * 'is_local_queue()' - Determine whether the URI points at a local queue.
2366 */
2367
2368 static int /* O - 1 = local, 0 = remote, -1 = bad URI */
2369 is_local_queue(const char *uri, /* I - Printer URI */
2370 char *host, /* O - Host string */
2371 int hostlen, /* I - Length of host buffer */
2372 char *resource, /* O - Resource string */
2373 int resourcelen) /* I - Length of resource buffer */
2374 {
2375 char scheme[32], /* Scheme portion of URI */
2376 username[HTTP_MAX_URI]; /* Username portion of URI */
2377 int port; /* Port portion of URI */
2378 cupsd_netif_t *iface; /* Network interface */
2379
2380
2381 /*
2382 * Pull the URI apart to see if this is a local or remote printer...
2383 */
2384
2385 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
2386 username, sizeof(username), host, hostlen, &port,
2387 resource, resourcelen) < HTTP_URI_OK)
2388 return (-1);
2389
2390 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
2391
2392 /*
2393 * Check for local server addresses...
2394 */
2395
2396 if (!strcasecmp(host, ServerName) && port == LocalPort)
2397 return (1);
2398
2399 cupsdNetIFUpdate();
2400
2401 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
2402 iface;
2403 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
2404 if (!strcasecmp(host, iface->hostname) && port == iface->port)
2405 return (1);
2406
2407 /*
2408 * If we get here, the printer is remote...
2409 */
2410
2411 return (0);
2412 }
2413
2414
2415 /*
2416 * 'process_browse_data()' - Process new browse data.
2417 */
2418
2419 static void
2420 process_browse_data(
2421 const char *uri, /* I - URI of printer/class */
2422 const char *host, /* I - Hostname */
2423 const char *resource, /* I - Resource path */
2424 cups_ptype_t type, /* I - Printer type */
2425 ipp_pstate_t state, /* I - Printer state */
2426 const char *location, /* I - Printer location */
2427 const char *info, /* I - Printer information */
2428 const char *make_model, /* I - Printer make and model */
2429 int num_attrs, /* I - Number of attributes */
2430 cups_option_t *attrs) /* I - Attributes */
2431 {
2432 int i; /* Looping var */
2433 int update; /* Update printer attributes? */
2434 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
2435 name[IPP_MAX_NAME], /* Name of printer */
2436 newname[IPP_MAX_NAME], /* New name of printer */
2437 *hptr, /* Pointer into hostname */
2438 *sptr; /* Pointer into ServerName */
2439 char local_make_model[IPP_MAX_NAME];
2440 /* Local make and model */
2441 cupsd_printer_t *p; /* Printer information */
2442 const char *ipp_options, /* ipp-options value */
2443 *lease_duration; /* lease-duration value */
2444
2445
2446 /*
2447 * Determine if the URI contains any illegal characters in it...
2448 */
2449
2450 if (strncmp(uri, "ipp://", 6) || !host[0] ||
2451 (strncmp(resource, "/printers/", 10) &&
2452 strncmp(resource, "/classes/", 9)))
2453 {
2454 cupsdLogMessage(CUPSD_LOG_ERROR,
2455 "process_browse_data: Bad printer URI in browse data: %s",
2456 uri);
2457 return;
2458 }
2459
2460 if (strchr(resource, '?') ||
2461 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
2462 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
2463 {
2464 cupsdLogMessage(CUPSD_LOG_ERROR,
2465 "process_browse_data: Bad resource in browse data: %s",
2466 resource);
2467 return;
2468 }
2469
2470 /*
2471 * OK, this isn't a local printer; add any remote options...
2472 */
2473
2474 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
2475
2476 if (BrowseRemoteOptions)
2477 {
2478 if (BrowseRemoteOptions[0] == '?')
2479 {
2480 /*
2481 * Override server-supplied options...
2482 */
2483
2484 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
2485 }
2486 else if (ipp_options)
2487 {
2488 /*
2489 * Combine the server and local options...
2490 */
2491
2492 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
2493 BrowseRemoteOptions);
2494 }
2495 else
2496 {
2497 /*
2498 * Just use the local options...
2499 */
2500
2501 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
2502 }
2503
2504 uri = finaluri;
2505 }
2506 else if (ipp_options)
2507 {
2508 /*
2509 * Just use the server-supplied options...
2510 */
2511
2512 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
2513 uri = finaluri;
2514 }
2515
2516 /*
2517 * See if we already have it listed in the Printers list, and add it if not...
2518 */
2519
2520 type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
2521 type &= ~CUPS_PRINTER_IMPLICIT;
2522 update = 0;
2523 hptr = strchr(host, '.');
2524 sptr = strchr(ServerName, '.');
2525
2526 if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
2527 {
2528 /*
2529 * Strip the common domain name components...
2530 */
2531
2532 while (hptr != NULL)
2533 {
2534 if (!strcasecmp(hptr, sptr))
2535 {
2536 *hptr = '\0';
2537 break;
2538 }
2539 else
2540 hptr = strchr(hptr + 1, '.');
2541 }
2542 }
2543
2544 if (type & CUPS_PRINTER_CLASS)
2545 {
2546 /*
2547 * Remote destination is a class...
2548 */
2549
2550 if (!strncmp(resource, "/classes/", 9))
2551 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
2552 else
2553 return;
2554
2555 if (hptr && !*hptr)
2556 *hptr = '.'; /* Resource FQDN */
2557
2558 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
2559 {
2560 if ((p = cupsdFindDest(resource + 9)) != NULL)
2561 {
2562 if (p->hostname && strcasecmp(p->hostname, host))
2563 {
2564 /*
2565 * Nope, this isn't the same host; if the hostname isn't the local host,
2566 * add it to the other class and then find a class using the full host
2567 * name...
2568 */
2569
2570 if (p->type & CUPS_PRINTER_REMOTE)
2571 {
2572 cupsdLogMessage(CUPSD_LOG_DEBUG,
2573 "Renamed remote class \"%s\" to \"%s@%s\"...",
2574 p->name, p->name, p->hostname);
2575 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2576 "Class \'%s\' deleted by directory services.",
2577 p->name);
2578
2579 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
2580 cupsdRenamePrinter(p, newname);
2581
2582 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2583 "Class \'%s\' added by directory services.",
2584 p->name);
2585 }
2586
2587 p = NULL;
2588 }
2589 else if (!p->hostname)
2590 {
2591 /*
2592 * Hostname not set, so this must be a cached remote printer
2593 * that was created for a pending print job...
2594 */
2595
2596 cupsdSetString(&p->hostname, host);
2597 cupsdSetString(&p->uri, uri);
2598 cupsdSetString(&p->device_uri, uri);
2599 update = 1;
2600 }
2601 }
2602 else
2603 {
2604 /*
2605 * Use the short name for this shared class.
2606 */
2607
2608 strlcpy(name, resource + 9, sizeof(name));
2609 }
2610 }
2611 else if (p && !p->hostname)
2612 {
2613 /*
2614 * Hostname not set, so this must be a cached remote printer
2615 * that was created for a pending print job...
2616 */
2617
2618 cupsdSetString(&p->hostname, host);
2619 cupsdSetString(&p->uri, uri);
2620 cupsdSetString(&p->device_uri, uri);
2621 update = 1;
2622 }
2623
2624 if (!p)
2625 {
2626 /*
2627 * Class doesn't exist; add it...
2628 */
2629
2630 p = cupsdAddClass(name);
2631
2632 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
2633
2634 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2635 "Class \'%s\' added by directory services.", name);
2636
2637 /*
2638 * Force the URI to point to the real server...
2639 */
2640
2641 p->type = type & ~CUPS_PRINTER_REJECTING;
2642 p->accepting = 1;
2643 cupsdSetString(&p->uri, uri);
2644 cupsdSetString(&p->device_uri, uri);
2645 cupsdSetString(&p->hostname, host);
2646
2647 update = 1;
2648
2649 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2650 }
2651 }
2652 else
2653 {
2654 /*
2655 * Remote destination is a printer...
2656 */
2657
2658 if (!strncmp(resource, "/printers/", 10))
2659 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
2660 else
2661 return;
2662
2663 if (hptr && !*hptr)
2664 *hptr = '.'; /* Resource FQDN */
2665
2666 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
2667 {
2668 if ((p = cupsdFindDest(resource + 10)) != NULL)
2669 {
2670 if (p->hostname && strcasecmp(p->hostname, host))
2671 {
2672 /*
2673 * Nope, this isn't the same host; if the hostname isn't the local host,
2674 * add it to the other printer and then find a printer using the full host
2675 * name...
2676 */
2677
2678 if (p->type & CUPS_PRINTER_REMOTE)
2679 {
2680 cupsdLogMessage(CUPSD_LOG_DEBUG,
2681 "Renamed remote printer \"%s\" to \"%s@%s\"...",
2682 p->name, p->name, p->hostname);
2683 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2684 "Printer \'%s\' deleted by directory services.",
2685 p->name);
2686
2687 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
2688 cupsdRenamePrinter(p, newname);
2689
2690 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2691 "Printer \'%s\' added by directory services.",
2692 p->name);
2693 }
2694
2695 p = NULL;
2696 }
2697 else if (!p->hostname)
2698 {
2699 /*
2700 * Hostname not set, so this must be a cached remote printer
2701 * that was created for a pending print job...
2702 */
2703
2704 cupsdSetString(&p->hostname, host);
2705 cupsdSetString(&p->uri, uri);
2706 cupsdSetString(&p->device_uri, uri);
2707 update = 1;
2708 }
2709 }
2710 else
2711 {
2712 /*
2713 * Use the short name for this shared printer.
2714 */
2715
2716 strlcpy(name, resource + 10, sizeof(name));
2717 }
2718 }
2719 else if (p && !p->hostname)
2720 {
2721 /*
2722 * Hostname not set, so this must be a cached remote printer
2723 * that was created for a pending print job...
2724 */
2725
2726 cupsdSetString(&p->hostname, host);
2727 cupsdSetString(&p->uri, uri);
2728 cupsdSetString(&p->device_uri, uri);
2729 update = 1;
2730 }
2731
2732 if (!p)
2733 {
2734 /*
2735 * Printer doesn't exist; add it...
2736 */
2737
2738 p = cupsdAddPrinter(name);
2739
2740 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2741 "Printer \'%s\' added by directory services.", name);
2742
2743 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
2744
2745 /*
2746 * Force the URI to point to the real server...
2747 */
2748
2749 p->type = type & ~CUPS_PRINTER_REJECTING;
2750 p->accepting = 1;
2751 cupsdSetString(&p->hostname, host);
2752 cupsdSetString(&p->uri, uri);
2753 cupsdSetString(&p->device_uri, uri);
2754
2755 update = 1;
2756
2757 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2758 }
2759 }
2760
2761 /*
2762 * Update the state...
2763 */
2764
2765 p->state = state;
2766 p->browse_time = time(NULL);
2767
2768 if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
2769 attrs)) != NULL)
2770 {
2771 /*
2772 * Grab the lease-duration for the browse data; anything less then 1
2773 * second or more than 1 week gets the default BrowseTimeout...
2774 */
2775
2776 i = atoi(lease_duration);
2777 if (i < 1 || i > 604800)
2778 i = BrowseTimeout;
2779
2780 p->browse_expire = p->browse_time + i;
2781 }
2782 else
2783 p->browse_expire = p->browse_time + BrowseTimeout;
2784
2785 if (type & CUPS_PRINTER_REJECTING)
2786 {
2787 type &= ~CUPS_PRINTER_REJECTING;
2788
2789 if (p->accepting)
2790 {
2791 update = 1;
2792 p->accepting = 0;
2793 }
2794 }
2795 else if (!p->accepting)
2796 {
2797 update = 1;
2798 p->accepting = 1;
2799 }
2800
2801 if (p->type != type)
2802 {
2803 p->type = type;
2804 update = 1;
2805 }
2806
2807 if (location && (!p->location || strcmp(p->location, location)))
2808 {
2809 cupsdSetString(&p->location, location);
2810 update = 1;
2811 }
2812
2813 if (info && (!p->info || strcmp(p->info, info)))
2814 {
2815 cupsdSetString(&p->info, info);
2816 update = 1;
2817
2818 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2819 }
2820
2821 if (!make_model || !make_model[0])
2822 {
2823 if (type & CUPS_PRINTER_CLASS)
2824 snprintf(local_make_model, sizeof(local_make_model),
2825 "Remote Class on %s", host);
2826 else
2827 snprintf(local_make_model, sizeof(local_make_model),
2828 "Remote Printer on %s", host);
2829 }
2830 else
2831 snprintf(local_make_model, sizeof(local_make_model),
2832 "%s on %s", make_model, host);
2833
2834 if (!p->make_model || strcmp(p->make_model, local_make_model))
2835 {
2836 cupsdSetString(&p->make_model, local_make_model);
2837 update = 1;
2838 }
2839
2840 if (p->num_options)
2841 {
2842 if (!update && !(type & CUPS_PRINTER_DELETE))
2843 {
2844 /*
2845 * See if we need to update the attributes...
2846 */
2847
2848 if (p->num_options != num_attrs)
2849 update = 1;
2850 else
2851 {
2852 for (i = 0; i < num_attrs; i ++)
2853 if (strcmp(attrs[i].name, p->options[i].name) ||
2854 (!attrs[i].value != !p->options[i].value) ||
2855 (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
2856 {
2857 update = 1;
2858 break;
2859 }
2860 }
2861 }
2862
2863 /*
2864 * Free the old options...
2865 */
2866
2867 cupsFreeOptions(p->num_options, p->options);
2868 }
2869
2870 p->num_options = num_attrs;
2871 p->options = attrs;
2872
2873 if (type & CUPS_PRINTER_DELETE)
2874 {
2875 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2876 "%s \'%s\' deleted by directory services.",
2877 (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
2878
2879 cupsdExpireSubscriptions(p, NULL);
2880
2881 cupsdDeletePrinter(p, 1);
2882 cupsdUpdateImplicitClasses();
2883 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2884 }
2885 else if (update)
2886 {
2887 cupsdSetPrinterAttrs(p);
2888 cupsdUpdateImplicitClasses();
2889 }
2890
2891 /*
2892 * See if we have a default printer... If not, make the first network
2893 * default printer the default.
2894 */
2895
2896 if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
2897 {
2898 /*
2899 * Find the first network default printer and use it...
2900 */
2901
2902 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2903 p;
2904 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2905 if (p->type & CUPS_PRINTER_DEFAULT)
2906 {
2907 DefaultPrinter = p;
2908 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
2909 break;
2910 }
2911 }
2912
2913 /*
2914 * Do auto-classing if needed...
2915 */
2916
2917 process_implicit_classes();
2918 }
2919
2920
2921 /*
2922 * 'process_implicit_classes()' - Create/update implicit classes as needed.
2923 */
2924
2925 static void
2926 process_implicit_classes(void)
2927 {
2928 int i; /* Looping var */
2929 int update; /* Update printer attributes? */
2930 char name[IPP_MAX_NAME], /* Name of printer */
2931 *hptr; /* Pointer into hostname */
2932 cupsd_printer_t *p, /* Printer information */
2933 *pclass, /* Printer class */
2934 *first; /* First printer in class */
2935 int offset, /* Offset of name */
2936 len; /* Length of name */
2937
2938
2939 if (!ImplicitClasses || !Printers)
2940 return;
2941
2942 /*
2943 * Loop through all available printers and create classes as needed...
2944 */
2945
2946 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
2947 update = 0, pclass = NULL, first = NULL;
2948 p != NULL;
2949 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2950 {
2951 /*
2952 * Skip implicit classes...
2953 */
2954
2955 if (p->type & CUPS_PRINTER_IMPLICIT)
2956 {
2957 len = 0;
2958 continue;
2959 }
2960
2961 /*
2962 * If len == 0, get the length of this printer name up to the "@"
2963 * sign (if any).
2964 */
2965
2966 cupsArraySave(Printers);
2967
2968 if (len > 0 &&
2969 !strncasecmp(p->name, name + offset, len) &&
2970 (p->name[len] == '\0' || p->name[len] == '@'))
2971 {
2972 /*
2973 * We have more than one printer with the same name; see if
2974 * we have a class, and if this printer is a member...
2975 */
2976
2977 if (pclass && strcasecmp(pclass->name, name))
2978 {
2979 if (update)
2980 cupsdSetPrinterAttrs(pclass);
2981
2982 update = 0;
2983 pclass = NULL;
2984 }
2985
2986 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
2987 {
2988 /*
2989 * Need to add the class...
2990 */
2991
2992 pclass = cupsdAddPrinter(name);
2993 cupsArrayAdd(ImplicitPrinters, pclass);
2994
2995 pclass->type |= CUPS_PRINTER_IMPLICIT;
2996 pclass->accepting = 1;
2997 pclass->state = IPP_PRINTER_IDLE;
2998
2999 cupsdSetString(&pclass->location, p->location);
3000 cupsdSetString(&pclass->info, p->info);
3001
3002 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
3003 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
3004
3005 update = 1;
3006
3007 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3008
3009 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
3010 name);
3011 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3012 "Implicit class \'%s\' added by directory services.",
3013 name);
3014 }
3015
3016 if (first != NULL)
3017 {
3018 for (i = 0; i < pclass->num_printers; i ++)
3019 if (pclass->printers[i] == first)
3020 break;
3021
3022 if (i >= pclass->num_printers)
3023 {
3024 first->in_implicit_class = 1;
3025 cupsdAddPrinterToClass(pclass, first);
3026 }
3027
3028 first = NULL;
3029 }
3030
3031 for (i = 0; i < pclass->num_printers; i ++)
3032 if (pclass->printers[i] == p)
3033 break;
3034
3035 if (i >= pclass->num_printers)
3036 {
3037 p->in_implicit_class = 1;
3038 cupsdAddPrinterToClass(pclass, p);
3039 update = 1;
3040 }
3041 }
3042 else
3043 {
3044 /*
3045 * First time around; just get name length and mark it as first
3046 * in the list...
3047 */
3048
3049 if ((hptr = strchr(p->name, '@')) != NULL)
3050 len = hptr - p->name;
3051 else
3052 len = strlen(p->name);
3053
3054 strncpy(name, p->name, len);
3055 name[len] = '\0';
3056 offset = 0;
3057
3058 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
3059 !(first->type & CUPS_PRINTER_IMPLICIT))
3060 {
3061 /*
3062 * Can't use same name as a local printer; add "Any" to the
3063 * front of the name, unless we have explicitly disabled
3064 * the "ImplicitAnyClasses"...
3065 */
3066
3067 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
3068 {
3069 /*
3070 * Add "Any" to the class name...
3071 */
3072
3073 strcpy(name, "Any");
3074 strncpy(name + 3, p->name, len);
3075 name[len + 3] = '\0';
3076 offset = 3;
3077 }
3078 else
3079 {
3080 /*
3081 * Don't create an implicit class if we have a local printer
3082 * with the same name...
3083 */
3084
3085 len = 0;
3086 cupsArrayRestore(Printers);
3087 continue;
3088 }
3089 }
3090
3091 first = p;
3092 }
3093
3094 cupsArrayRestore(Printers);
3095 }
3096
3097 /*
3098 * Update the last printer class as needed...
3099 */
3100
3101 if (pclass && update)
3102 cupsdSetPrinterAttrs(pclass);
3103 }
3104
3105
3106 /*
3107 * 'send_cups_browse()' - Send new browsing information using the CUPS
3108 * protocol.
3109 */
3110
3111 static void
3112 send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
3113 {
3114 int i; /* Looping var */
3115 cups_ptype_t type; /* Printer type */
3116 cupsd_dirsvc_addr_t *b; /* Browse address */
3117 int bytes; /* Length of packet */
3118 char packet[1453], /* Browse data packet */
3119 uri[1024], /* Printer URI */
3120 location[1024], /* printer-location */
3121 info[1024], /* printer-info */
3122 make_model[1024];
3123 /* printer-make-and-model */
3124 cupsd_netif_t *iface; /* Network interface */
3125
3126
3127 /*
3128 * Figure out the printer type value...
3129 */
3130
3131 type = p->type | CUPS_PRINTER_REMOTE;
3132
3133 if (!p->accepting)
3134 type |= CUPS_PRINTER_REJECTING;
3135
3136 if (p == DefaultPrinter)
3137 type |= CUPS_PRINTER_DEFAULT;
3138
3139 /*
3140 * Remove quotes from printer-info, printer-location, and
3141 * printer-make-and-model attributes...
3142 */
3143
3144 dequote(location, p->location, sizeof(location));
3145 dequote(info, p->info, sizeof(info));
3146
3147 if (p->make_model)
3148 dequote(make_model, p->make_model, sizeof(make_model));
3149 else if (p->type & CUPS_PRINTER_CLASS)
3150 {
3151 if (p->num_printers > 0 && p->printers[0]->make_model)
3152 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
3153 else
3154 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
3155 }
3156 else if (p->raw)
3157 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
3158 else
3159 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
3160
3161 /*
3162 * Send a packet to each browse address...
3163 */
3164
3165 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
3166 if (b->iface[0])
3167 {
3168 /*
3169 * Send the browse packet to one or more interfaces...
3170 */
3171
3172 if (!strcmp(b->iface, "*"))
3173 {
3174 /*
3175 * Send to all local interfaces...
3176 */
3177
3178 cupsdNetIFUpdate();
3179
3180 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3181 iface;
3182 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3183 {
3184 /*
3185 * Only send to local, IPv4 interfaces...
3186 */
3187
3188 if (!iface->is_local || !iface->port ||
3189 iface->address.addr.sa_family != AF_INET)
3190 continue;
3191
3192 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3193 iface->hostname, iface->port,
3194 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
3195 "/printers/%s",
3196 p->name);
3197 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3198 type, p->state, uri, location, info, make_model,
3199 p->browse_attrs ? p->browse_attrs : "");
3200
3201 bytes = strlen(packet);
3202
3203 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3204 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3205 iface->name, packet);
3206
3207 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3208
3209 sendto(BrowseSocket, packet, bytes, 0,
3210 (struct sockaddr *)&(iface->broadcast),
3211 httpAddrLength(&(iface->broadcast)));
3212 }
3213 }
3214 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
3215 {
3216 /*
3217 * Send to the named interface using the IPv4 address...
3218 */
3219
3220 while (iface)
3221 if (strcmp(b->iface, iface->name))
3222 {
3223 iface = NULL;
3224 break;
3225 }
3226 else if (iface->address.addr.sa_family == AF_INET && iface->port)
3227 break;
3228 else
3229 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
3230
3231 if (iface)
3232 {
3233 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3234 iface->hostname, iface->port,
3235 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
3236 "/printers/%s",
3237 p->name);
3238 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3239 type, p->state, uri, location, info, make_model,
3240 p->browse_attrs ? p->browse_attrs : "");
3241
3242 bytes = strlen(packet);
3243
3244 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3245 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3246 iface->name, packet);
3247
3248 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3249
3250 sendto(BrowseSocket, packet, bytes, 0,
3251 (struct sockaddr *)&(iface->broadcast),
3252 httpAddrLength(&(iface->broadcast)));
3253 }
3254 }
3255 }
3256 else
3257 {
3258 /*
3259 * Send the browse packet to the indicated address using
3260 * the default server name...
3261 */
3262
3263 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3264 type, p->state, p->uri, location, info, make_model,
3265 p->browse_attrs ? p->browse_attrs : "");
3266
3267 bytes = strlen(packet);
3268 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3269 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
3270
3271 if (sendto(BrowseSocket, packet, bytes, 0,
3272 (struct sockaddr *)&(b->to),
3273 httpAddrLength(&(b->to))) <= 0)
3274 {
3275 /*
3276 * Unable to send browse packet, so remove this address from the
3277 * list...
3278 */
3279
3280 cupsdLogMessage(CUPSD_LOG_ERROR,
3281 "cupsdSendBrowseList: sendto failed for browser "
3282 "%d - %s.",
3283 (int)(b - Browsers + 1), strerror(errno));
3284
3285 if (i > 1)
3286 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
3287
3288 b --;
3289 NumBrowsers --;
3290 }
3291 }
3292 }
3293
3294
3295 #ifdef HAVE_OPENLDAP
3296 /*
3297 * 'send_ldap_browse()' - Send LDAP printer registrations.
3298 */
3299
3300 static void
3301 send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
3302 {
3303 int i; /* Looping var... */
3304 LDAPMod mods[7]; /* The 7 attributes we will be adding */
3305 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
3306 LDAPMessage *res; /* Search result token */
3307 char *cn_value[2], /* Change records */
3308 *uri[2],
3309 *info[2],
3310 *location[2],
3311 *make_model[2],
3312 *type[2],
3313 typestring[255], /* String to hold printer-type */
3314 filter[256], /* Search filter for possible UPDATEs */
3315 dn[1024]; /* DN of the printer we are adding */
3316 int rc; /* LDAP status */
3317 static const char * const objectClass_values[] =
3318 { /* The 3 objectClass's we use in */
3319 "top", /* our LDAP entries */
3320 "device",
3321 "cupsPrinter",
3322 NULL
3323 };
3324
3325 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
3326
3327 /*
3328 * Everything in ldap is ** so we fudge around it...
3329 */
3330
3331 sprintf(typestring, "%u", p->type);
3332
3333 cn_value[0] = p->name;
3334 cn_value[1] = NULL;
3335 info[0] = p->info ? p->info : "Unknown";
3336 info[1] = NULL;
3337 location[0] = p->location ? p->location : "Unknown";
3338 location[1] = NULL;
3339 make_model[0] = p->make_model ? p->make_model : "Unknown";
3340 make_model[1] = NULL;
3341 type[0] = typestring;
3342 type[1] = NULL;
3343 uri[0] = p->uri;
3344 uri[1] = NULL;
3345
3346 snprintf(filter, sizeof(filter),
3347 "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
3348
3349 ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
3350 filter, (char **)ldap_attrs, 0, &res);
3351 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
3352 filter);
3353
3354 mods[0].mod_type = "cn";
3355 mods[0].mod_values = cn_value;
3356 mods[1].mod_type = "printerDescription";
3357 mods[1].mod_values = info;
3358 mods[2].mod_type = "printerURI";
3359 mods[2].mod_values = uri;
3360 mods[3].mod_type = "printerLocation";
3361 mods[3].mod_values = location;
3362 mods[4].mod_type = "printerMakeAndModel";
3363 mods[4].mod_values = make_model;
3364 mods[5].mod_type = "printerType";
3365 mods[5].mod_values = type;
3366 mods[6].mod_type = "objectClass";
3367 mods[6].mod_values = (char **)objectClass_values;
3368
3369 snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
3370 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
3371
3372 if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
3373 {
3374 /*
3375 * Printer has already been registered, modify the current
3376 * registration...
3377 */
3378
3379 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3380 "send_ldap_browse: Replacing entry...");
3381
3382 for (i = 0; i < 7; i ++)
3383 {
3384 pmods[i] = mods + i;
3385 pmods[i]->mod_op = LDAP_MOD_REPLACE;
3386 }
3387 pmods[i] = NULL;
3388
3389 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3390 cupsdLogMessage(CUPSD_LOG_ERROR,
3391 "LDAP modify for %s failed with status %d: %s",
3392 p->name, rc, ldap_err2string(rc));
3393 }
3394 else
3395 {
3396 /*
3397 * Printer has never been registered, add the current
3398 * registration...
3399 */
3400
3401 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3402 "send_ldap_browse: Adding entry...");
3403
3404 for (i = 0; i < 7; i ++)
3405 {
3406 pmods[i] = mods + i;
3407 pmods[i]->mod_op = LDAP_MOD_ADD;
3408 }
3409 pmods[i] = NULL;
3410
3411 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3412 cupsdLogMessage(CUPSD_LOG_ERROR,
3413 "LDAP add for %s failed with status %d: %s",
3414 p->name, rc, ldap_err2string(rc));
3415 }
3416 }
3417 #endif /* HAVE_OPENLDAP */
3418
3419
3420 #ifdef HAVE_LIBSLP
3421 /*
3422 * 'send_slp_browse()' - Register the specified printer with SLP.
3423 */
3424
3425 static void
3426 send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
3427 {
3428 char srvurl[HTTP_MAX_URI], /* Printer service URI */
3429 attrs[8192], /* Printer attributes */
3430 finishings[1024], /* Finishings to support */
3431 make_model[IPP_MAX_NAME * 2],
3432 /* Make and model, quoted */
3433 location[IPP_MAX_NAME * 2],
3434 /* Location, quoted */
3435 info[IPP_MAX_NAME * 2], /* Info, quoted */
3436 *src, /* Pointer to original string */
3437 *dst; /* Pointer to destination string */
3438 ipp_attribute_t *authentication; /* uri-authentication-supported value */
3439 SLPError error; /* SLP error, if any */
3440
3441
3442 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
3443 p->name);
3444
3445 /*
3446 * Make the SLP service URL that conforms to the IANA
3447 * 'printer:' template.
3448 */
3449
3450 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3451
3452 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
3453
3454 /*
3455 * Figure out the finishings string...
3456 */
3457
3458 if (p->type & CUPS_PRINTER_STAPLE)
3459 strcpy(finishings, "staple");
3460 else
3461 finishings[0] = '\0';
3462
3463 if (p->type & CUPS_PRINTER_BIND)
3464 {
3465 if (finishings[0])
3466 strlcat(finishings, ",bind", sizeof(finishings));
3467 else
3468 strcpy(finishings, "bind");
3469 }
3470
3471 if (p->type & CUPS_PRINTER_PUNCH)
3472 {
3473 if (finishings[0])
3474 strlcat(finishings, ",punch", sizeof(finishings));
3475 else
3476 strcpy(finishings, "punch");
3477 }
3478
3479 if (p->type & CUPS_PRINTER_COVER)
3480 {
3481 if (finishings[0])
3482 strlcat(finishings, ",cover", sizeof(finishings));
3483 else
3484 strcpy(finishings, "cover");
3485 }
3486
3487 if (p->type & CUPS_PRINTER_SORT)
3488 {
3489 if (finishings[0])
3490 strlcat(finishings, ",sort", sizeof(finishings));
3491 else
3492 strcpy(finishings, "sort");
3493 }
3494
3495 if (!finishings[0])
3496 strcpy(finishings, "none");
3497
3498 /*
3499 * Quote any commas in the make and model, location, and info strings...
3500 */
3501
3502 for (src = p->make_model, dst = make_model;
3503 src && *src && dst < (make_model + sizeof(make_model) - 2);)
3504 {
3505 if (*src == ',' || *src == '\\' || *src == ')')
3506 *dst++ = '\\';
3507
3508 *dst++ = *src++;
3509 }
3510
3511 *dst = '\0';
3512
3513 if (!make_model[0])
3514 strcpy(make_model, "Unknown");
3515
3516 for (src = p->location, dst = location;
3517 src && *src && dst < (location + sizeof(location) - 2);)
3518 {
3519 if (*src == ',' || *src == '\\' || *src == ')')
3520 *dst++ = '\\';
3521
3522 *dst++ = *src++;
3523 }
3524
3525 *dst = '\0';
3526
3527 if (!location[0])
3528 strcpy(location, "Unknown");
3529
3530 for (src = p->info, dst = info;
3531 src && *src && dst < (info + sizeof(info) - 2);)
3532 {
3533 if (*src == ',' || *src == '\\' || *src == ')')
3534 *dst++ = '\\';
3535
3536 *dst++ = *src++;
3537 }
3538
3539 *dst = '\0';
3540
3541 if (!info[0])
3542 strcpy(info, "Unknown");
3543
3544 /*
3545 * Get the authentication value...
3546 */
3547
3548 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
3549 IPP_TAG_KEYWORD);
3550
3551 /*
3552 * Make the SLP attribute string list that conforms to
3553 * the IANA 'printer:' template.
3554 */
3555
3556 snprintf(attrs, sizeof(attrs),
3557 "(printer-uri-supported=%s),"
3558 "(uri-authentication-supported=%s>),"
3559 #ifdef HAVE_SSL
3560 "(uri-security-supported=tls>),"
3561 #else
3562 "(uri-security-supported=none>),"
3563 #endif /* HAVE_SSL */
3564 "(printer-name=%s),"
3565 "(printer-location=%s),"
3566 "(printer-info=%s),"
3567 "(printer-more-info=%s),"
3568 "(printer-make-and-model=%s),"
3569 "(printer-type=%d),"
3570 "(charset-supported=utf-8),"
3571 "(natural-language-configured=%s),"
3572 "(natural-language-supported=de,en,es,fr,it),"
3573 "(color-supported=%s),"
3574 "(finishings-supported=%s),"
3575 "(sides-supported=one-sided%s),"
3576 "(multiple-document-jobs-supported=true)"
3577 "(ipp-versions-supported=1.0,1.1)",
3578 p->uri, authentication->values[0].string.text, p->name, location,
3579 info, p->uri, make_model, p->type, DefaultLanguage,
3580 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
3581 finishings,
3582 p->type & CUPS_PRINTER_DUPLEX ?
3583 ",two-sided-long-edge,two-sided-short-edge" : "");
3584
3585 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
3586
3587 /*
3588 * Register the printer with the SLP server...
3589 */
3590
3591 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
3592 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
3593
3594 if (error != SLP_OK)
3595 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
3596 error);
3597 }
3598
3599
3600 /*
3601 * 'slp_attr_callback()' - SLP attribute callback
3602 */
3603
3604 static SLPBoolean /* O - SLP_TRUE for success */
3605 slp_attr_callback(
3606 SLPHandle hslp, /* I - SLP handle */
3607 const char *attrlist, /* I - Attribute list */
3608 SLPError errcode, /* I - Parsing status for this attr */
3609 void *cookie) /* I - Current printer */
3610 {
3611 char *tmp = 0; /* Temporary string */
3612 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
3613 /* Current printer */
3614
3615
3616 (void)hslp; /* anti-compiler-warning-code */
3617
3618 /*
3619 * Bail if there was an error
3620 */
3621
3622 if (errcode != SLP_OK)
3623 return (SLP_TRUE);
3624
3625 /*
3626 * Parse the attrlist to obtain things needed to build CUPS browse packet
3627 */
3628
3629 memset(p, 0, sizeof(cupsd_printer_t));
3630
3631 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
3632 return (SLP_FALSE);
3633 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
3634 return (SLP_FALSE);
3635 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
3636 return (SLP_FALSE);
3637 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
3638 p->type = atoi(tmp);
3639 else
3640 p->type = CUPS_PRINTER_REMOTE;
3641
3642 cupsdClearString(&tmp);
3643
3644 return (SLP_TRUE);
3645 }
3646
3647
3648 /*
3649 * 'slp_dereg_printer()' - SLPDereg() the specified printer
3650 */
3651
3652 static void
3653 slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
3654 {
3655 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
3656
3657
3658 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
3659
3660 if (!(p->type & CUPS_PRINTER_REMOTE))
3661 {
3662 /*
3663 * Make the SLP service URL that conforms to the IANA
3664 * 'printer:' template.
3665 */
3666
3667 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3668
3669 /*
3670 * Deregister the printer...
3671 */
3672
3673 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
3674 }
3675 }
3676
3677
3678 /*
3679 * 'slp_get_attr()' - Get an attribute from an SLP registration.
3680 */
3681
3682 static int /* O - 0 on success */
3683 slp_get_attr(const char *attrlist, /* I - Attribute list string */
3684 const char *tag, /* I - Name of attribute */
3685 char **valbuf) /* O - Value */
3686 {
3687 char *ptr1, /* Pointer into string */
3688 *ptr2; /* ... */
3689
3690
3691 cupsdClearString(valbuf);
3692
3693 if ((ptr1 = strstr(attrlist, tag)) != NULL)
3694 {
3695 ptr1 += strlen(tag);
3696
3697 if ((ptr2 = strchr(ptr1,')')) != NULL)
3698 {
3699 /*
3700 * Copy the value...
3701 */
3702
3703 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
3704 strncpy(*valbuf, ptr1, ptr2 - ptr1);
3705
3706 /*
3707 * Dequote the value...
3708 */
3709
3710 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
3711 if (*ptr1 == '\\' && ptr1[1])
3712 _cups_strcpy(ptr1, ptr1 + 1);
3713
3714 return (0);
3715 }
3716 }
3717
3718 return (-1);
3719 }
3720
3721
3722 /*
3723 * 'slp_reg_callback()' - Empty SLPRegReport.
3724 */
3725
3726 static void
3727 slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
3728 SLPError errcode, /* I - Error code, if any */
3729 void *cookie) /* I - App data */
3730 {
3731 (void)hslp;
3732 (void)errcode;
3733 (void)cookie;
3734
3735 return;
3736 }
3737
3738
3739 /*
3740 * 'slp_url_callback()' - SLP service url callback
3741 */
3742
3743 static SLPBoolean /* O - TRUE = OK, FALSE = error */
3744 slp_url_callback(
3745 SLPHandle hslp, /* I - SLP handle */
3746 const char *srvurl, /* I - URL of service */
3747 unsigned short lifetime, /* I - Life of service */
3748 SLPError errcode, /* I - Existing error code */
3749 void *cookie) /* I - Pointer to service list */
3750 {
3751 slpsrvurl_t *s, /* New service entry */
3752 **head; /* Pointer to head of entry */
3753
3754
3755 /*
3756 * Let the compiler know we won't be using these vars...
3757 */
3758
3759 (void)hslp;
3760 (void)lifetime;
3761
3762 /*
3763 * Bail if there was an error
3764 */
3765
3766 if (errcode != SLP_OK)
3767 return (SLP_TRUE);
3768
3769 /*
3770 * Grab the head of the list...
3771 */
3772
3773 head = (slpsrvurl_t**)cookie;
3774
3775 /*
3776 * Allocate a *temporary* slpsrvurl_t to hold this entry.
3777 */
3778
3779 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
3780 return (SLP_FALSE);
3781
3782 /*
3783 * Copy the SLP service URL...
3784 */
3785
3786 strlcpy(s->url, srvurl, sizeof(s->url));
3787
3788 /*
3789 * Link the SLP service URL into the head of the list
3790 */
3791
3792 if (*head)
3793 s->next = *head;
3794
3795 *head = s;
3796
3797 return (SLP_TRUE);
3798 }
3799 #endif /* HAVE_LIBSLP */
3800
3801
3802 /*
3803 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
3804 */
3805
3806 static void
3807 update_cups_browse(void)
3808 {
3809 int i; /* Looping var */
3810 int auth; /* Authorization status */
3811 int len; /* Length of name string */
3812 int bytes; /* Number of bytes left */
3813 char packet[1541], /* Broadcast packet */
3814 *pptr; /* Pointer into packet */
3815 socklen_t srclen; /* Length of source address */
3816 http_addr_t srcaddr; /* Source address */
3817 char srcname[1024]; /* Source hostname */
3818 unsigned address[4]; /* Source address */
3819 unsigned type; /* Printer type */
3820 unsigned state; /* Printer state */
3821 char uri[HTTP_MAX_URI], /* Printer URI */
3822 host[HTTP_MAX_URI], /* Host portion of URI */
3823 resource[HTTP_MAX_URI], /* Resource portion of URI */
3824 info[IPP_MAX_NAME], /* Information string */
3825 location[IPP_MAX_NAME], /* Location string */
3826 make_model[IPP_MAX_NAME];/* Make and model string */
3827 int num_attrs; /* Number of attributes */
3828 cups_option_t *attrs; /* Attributes */
3829
3830
3831 /*
3832 * Read a packet from the browse socket...
3833 */
3834
3835 srclen = sizeof(srcaddr);
3836 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
3837 (struct sockaddr *)&srcaddr, &srclen)) < 0)
3838 {
3839 /*
3840 * "Connection refused" is returned under Linux if the destination port
3841 * or address is unreachable from a previous sendto(); check for the
3842 * error here and ignore it for now...
3843 */
3844
3845 if (errno != ECONNREFUSED && errno != EAGAIN)
3846 {
3847 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
3848 strerror(errno));
3849 cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
3850
3851 #ifdef WIN32
3852 closesocket(BrowseSocket);
3853 #else
3854 close(BrowseSocket);
3855 #endif /* WIN32 */
3856
3857 cupsdRemoveSelect(BrowseSocket);
3858 BrowseSocket = -1;
3859
3860 BrowseLocalProtocols &= ~BROWSE_CUPS;
3861 BrowseRemoteProtocols &= ~BROWSE_CUPS;
3862 }
3863
3864 return;
3865 }
3866
3867 packet[bytes] = '\0';
3868
3869 /*
3870 * If we're about to sleep, ignore incoming browse packets.
3871 */
3872
3873 if (Sleeping)
3874 return;
3875
3876 /*
3877 * Figure out where it came from...
3878 */
3879
3880 #ifdef AF_INET6
3881 if (srcaddr.addr.sa_family == AF_INET6)
3882 {
3883 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
3884 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
3885 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
3886 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
3887 }
3888 else
3889 #endif /* AF_INET6 */
3890 {
3891 address[0] = 0;
3892 address[1] = 0;
3893 address[2] = 0;
3894 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
3895 }
3896
3897 if (HostNameLookups)
3898 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
3899 else
3900 httpAddrString(&srcaddr, srcname, sizeof(srcname));
3901
3902 len = strlen(srcname);
3903
3904 /*
3905 * Do ACL stuff...
3906 */
3907
3908 if (BrowseACL)
3909 {
3910 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
3911 {
3912 /*
3913 * Access from localhost (127.0.0.1) is always allowed...
3914 */
3915
3916 auth = CUPSD_AUTH_ALLOW;
3917 }
3918 else
3919 {
3920 /*
3921 * Do authorization checks on the domain/address...
3922 */
3923
3924 switch (BrowseACL->order_type)
3925 {
3926 default :
3927 auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
3928 break;
3929
3930 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
3931 auth = CUPSD_AUTH_ALLOW;
3932
3933 if (cupsdCheckAuth(address, srcname, len,
3934 BrowseACL->num_deny, BrowseACL->deny))
3935 auth = CUPSD_AUTH_DENY;
3936
3937 if (cupsdCheckAuth(address, srcname, len,
3938 BrowseACL->num_allow, BrowseACL->allow))
3939 auth = CUPSD_AUTH_ALLOW;
3940 break;
3941
3942 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
3943 auth = CUPSD_AUTH_DENY;
3944
3945 if (cupsdCheckAuth(address, srcname, len,
3946 BrowseACL->num_allow, BrowseACL->allow))
3947 auth = CUPSD_AUTH_ALLOW;
3948
3949 if (cupsdCheckAuth(address, srcname, len,
3950 BrowseACL->num_deny, BrowseACL->deny))
3951 auth = CUPSD_AUTH_DENY;
3952 break;
3953 }
3954 }
3955 }
3956 else
3957 auth = CUPSD_AUTH_ALLOW;
3958
3959 if (auth == CUPSD_AUTH_DENY)
3960 {
3961 cupsdLogMessage(CUPSD_LOG_DEBUG,
3962 "update_cups_browse: Refused %d bytes from %s", bytes,
3963 srcname);
3964 return;
3965 }
3966
3967 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3968 "update_cups_browse: (%d bytes from %s) %s", bytes,
3969 srcname, packet);
3970
3971 /*
3972 * Parse packet...
3973 */
3974
3975 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
3976 {
3977 cupsdLogMessage(CUPSD_LOG_WARN,
3978 "update_cups_browse: Garbled browse packet - %s", packet);
3979 return;
3980 }
3981
3982 strcpy(location, "Location Unknown");
3983 strcpy(info, "No Information Available");
3984 make_model[0] = '\0';
3985 num_attrs = 0;
3986 attrs = NULL;
3987
3988 if ((pptr = strchr(packet, '\"')) != NULL)
3989 {
3990 /*
3991 * Have extended information; can't use sscanf for it because not all
3992 * sscanf's allow empty strings with %[^\"]...
3993 */
3994
3995 for (i = 0, pptr ++;
3996 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
3997 i ++, pptr ++)
3998 location[i] = *pptr;
3999
4000 if (i)
4001 location[i] = '\0';
4002
4003 if (*pptr == '\"')
4004 pptr ++;
4005
4006 while (*pptr && isspace(*pptr & 255))
4007 pptr ++;
4008
4009 if (*pptr == '\"')
4010 {
4011 for (i = 0, pptr ++;
4012 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
4013 i ++, pptr ++)
4014 info[i] = *pptr;
4015
4016 info[i] = '\0';
4017
4018 if (*pptr == '\"')
4019 pptr ++;
4020
4021 while (*pptr && isspace(*pptr & 255))
4022 pptr ++;
4023
4024 if (*pptr == '\"')
4025 {
4026 for (i = 0, pptr ++;
4027 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
4028 i ++, pptr ++)
4029 make_model[i] = *pptr;
4030
4031 if (*pptr == '\"')
4032 pptr ++;
4033
4034 make_model[i] = '\0';
4035
4036 if (*pptr)
4037 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
4038 }
4039 }
4040 }
4041
4042 DEBUG_puts(packet);
4043 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
4044 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
4045 type, state, uri, location, info, make_model));
4046
4047 /*
4048 * Pull the URI apart to see if this is a local or remote printer...
4049 */
4050
4051 if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
4052 {
4053 cupsFreeOptions(num_attrs, attrs);
4054 return;
4055 }
4056
4057 /*
4058 * Do relaying...
4059 */
4060
4061 for (i = 0; i < NumRelays; i ++)
4062 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
4063 if (sendto(BrowseSocket, packet, bytes, 0,
4064 (struct sockaddr *)&(Relays[i].to),
4065 httpAddrLength(&(Relays[i].to))) <= 0)
4066 {
4067 cupsdLogMessage(CUPSD_LOG_ERROR,
4068 "update_cups_browse: sendto failed for relay %d - %s.",
4069 i + 1, strerror(errno));
4070 cupsFreeOptions(num_attrs, attrs);
4071 return;
4072 }
4073
4074 /*
4075 * Process the browse data...
4076 */
4077
4078 process_browse_data(uri, host, resource, (cups_ptype_t)type,
4079 (ipp_pstate_t)state, location, info, make_model,
4080 num_attrs, attrs);
4081 }
4082
4083
4084 /*
4085 * 'update_lpd()' - Update the LPD configuration as needed.
4086 */
4087
4088 static void
4089 update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
4090 {
4091 if (!LPDConfigFile)
4092 return;
4093
4094 #ifdef __APPLE__
4095 /*
4096 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
4097 * setting for backwards-compatibility.
4098 */
4099
4100 if (onoff && !get_hostconfig("CUPS_LPD"))
4101 onoff = 0;
4102 #endif /* __APPLE__ */
4103
4104 if (!strncmp(LPDConfigFile, "xinetd:///", 10))
4105 {
4106 /*
4107 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
4108 */
4109
4110 char newfile[1024]; /* New cups-lpd.N file */
4111 cups_file_t *ofp, /* Original file pointer */
4112 *nfp; /* New file pointer */
4113 char line[1024]; /* Line from file */
4114
4115
4116 snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
4117
4118 if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
4119 {
4120 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
4121 LPDConfigFile + 9, strerror(errno));
4122 return;
4123 }
4124
4125 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
4126 {
4127 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
4128 newfile, strerror(errno));
4129 cupsFileClose(ofp);
4130 return;
4131 }
4132
4133 /*
4134 * Copy all of the lines from the cups-lpd file...
4135 */
4136
4137 while (cupsFileGets(ofp, line, sizeof(line)))
4138 {
4139 if (line[0] == '{')
4140 {
4141 cupsFilePrintf(nfp, "%s\n", line);
4142 snprintf(line, sizeof(line), "\tdisable = %s",
4143 onoff ? "no" : "yes");
4144 }
4145 else if (!strstr(line, "disable ="))
4146 cupsFilePrintf(nfp, "%s\n", line);
4147 }
4148
4149 cupsFileClose(nfp);
4150 cupsFileClose(ofp);
4151 rename(newfile, LPDConfigFile + 9);
4152 }
4153 #ifdef __APPLE__
4154 else if (!strncmp(LPDConfigFile, "launchd:///", 11))
4155 {
4156 /*
4157 * Enable/disable LPD via the launchctl command...
4158 */
4159
4160 char *argv[5], /* Arguments for command */
4161 *envp[MAX_ENV]; /* Environment for command */
4162 int pid; /* Process ID */
4163
4164
4165 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
4166 argv[0] = (char *)"launchctl";
4167 argv[1] = (char *)(onoff ? "load" : "unload");
4168 argv[2] = (char *)"-w";
4169 argv[3] = LPDConfigFile + 10;
4170 argv[4] = NULL;
4171
4172 cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
4173 NULL, &pid);
4174 }
4175 #endif /* __APPLE__ */
4176 else
4177 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
4178 }
4179
4180
4181 /*
4182 * 'update_polling()' - Read status messages from the poll daemons.
4183 */
4184
4185 static void
4186 update_polling(void)
4187 {
4188 char *ptr, /* Pointer to end of line in buffer */
4189 message[1024]; /* Pointer to message text */
4190 int loglevel; /* Log level for message */
4191
4192
4193 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
4194 message, sizeof(message))) != NULL)
4195 if (!strchr(PollStatusBuffer->buffer, '\n'))
4196 break;
4197
4198 if (ptr == NULL && !PollStatusBuffer->bufused)
4199 {
4200 /*
4201 * All polling processes have died; stop polling...
4202 */
4203
4204 cupsdLogMessage(CUPSD_LOG_ERROR,
4205 "update_polling: all polling processes have exited!");
4206 cupsdStopPolling();
4207 }
4208 }
4209
4210
4211 /*
4212 * 'update_smb()' - Update the SMB configuration as needed.
4213 */
4214
4215 static void
4216 update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
4217 {
4218 if (!SMBConfigFile)
4219 return;
4220
4221 if (!strncmp(SMBConfigFile, "samba:///", 9))
4222 {
4223 /*
4224 * Enable/disable SMB via the specified smb.conf config file...
4225 */
4226
4227 char newfile[1024]; /* New smb.conf.N file */
4228 cups_file_t *ofp, /* Original file pointer */
4229 *nfp; /* New file pointer */
4230 char line[1024]; /* Line from file */
4231 int in_printers; /* In [printers] section? */
4232
4233
4234 snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
4235
4236 if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
4237 {
4238 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
4239 SMBConfigFile + 8, strerror(errno));
4240 return;
4241 }
4242
4243 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
4244 {
4245 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
4246 newfile, strerror(errno));
4247 cupsFileClose(ofp);
4248 return;
4249 }
4250
4251 /*
4252 * Copy all of the lines from the smb.conf file...
4253 */
4254
4255 in_printers = 0;
4256
4257 while (cupsFileGets(ofp, line, sizeof(line)))
4258 {
4259 if (in_printers && strstr(line, "printable ="))
4260 snprintf(line, sizeof(line), " printable = %s",
4261 onoff ? "yes" : "no");
4262
4263 cupsFilePrintf(nfp, "%s\n", line);
4264
4265 if (line[0] == '[')
4266 in_printers = !strcmp(line, "[printers]");
4267 }
4268
4269 cupsFileClose(nfp);
4270 cupsFileClose(ofp);
4271 rename(newfile, SMBConfigFile + 8);
4272 }
4273 else
4274 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
4275 }
4276
4277
4278 /*
4279 * End of "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $".
4280 */