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