]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
Try another fix for Avahi crash (Issue #5268)
[thirdparty/cups.git] / scheduler / dirsvc.c
1 /*
2 * Directory services routines for the CUPS scheduler.
3 *
4 * Copyright 2007-2018 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include "cupsd.h"
15 #include <grp.h>
16
17 #if defined(HAVE_DNSSD) && defined(__APPLE__)
18 # include <nameser.h>
19 # include <CoreFoundation/CoreFoundation.h>
20 # include <SystemConfiguration/SystemConfiguration.h>
21 #endif /* HAVE_DNSSD && __APPLE__ */
22
23
24 /*
25 * Local globals...
26 */
27
28 #ifdef HAVE_AVAHI
29 static int avahi_running = 0;
30 #endif /* HAVE_AVAHI */
31
32
33 /*
34 * Local functions...
35 */
36
37 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
38 static char *get_auth_info_required(cupsd_printer_t *p,
39 char *buffer, size_t bufsize);
40 #endif /* HAVE_DNSSD || HAVE_AVAHI */
41 #ifdef __APPLE__
42 static int get_hostconfig(const char *name);
43 #endif /* __APPLE__ */
44 static void update_lpd(int onoff);
45 static void update_smb(int onoff);
46
47
48 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
49 # ifdef __APPLE__
50 static void dnssdAddAlias(const void *key, const void *value,
51 void *context);
52 # endif /* __APPLE__ */
53 static cupsd_txt_t dnssdBuildTxtRecord(cupsd_printer_t *p, int for_lpd);
54 # ifdef HAVE_AVAHI
55 static void dnssdClientCallback(AvahiClient *c, AvahiClientState state, void *userdata);
56 # endif /* HAVE_AVAHI */
57 static void dnssdDeregisterAllPrinters(int from_callback);
58 static void dnssdDeregisterInstance(cupsd_srv_t *srv, int from_callback);
59 static void dnssdDeregisterPrinter(cupsd_printer_t *p, int clear_name, int from_callback);
60 static const char *dnssdErrorString(int error);
61 static void dnssdFreeTxtRecord(cupsd_txt_t *txt);
62 static void dnssdRegisterAllPrinters(int from_callback);
63 # ifdef HAVE_DNSSD
64 static void dnssdRegisterCallback(DNSServiceRef sdRef,
65 DNSServiceFlags flags,
66 DNSServiceErrorType errorCode,
67 const char *name,
68 const char *regtype,
69 const char *domain,
70 void *context);
71 # else
72 static void dnssdRegisterCallback(AvahiEntryGroup *p,
73 AvahiEntryGroupState state,
74 void *context);
75 # endif /* HAVE_DNSSD */
76 static int dnssdRegisterInstance(cupsd_srv_t *srv, cupsd_printer_t *p, char *name, const char *type, const char *subtypes, int port, cupsd_txt_t *txt, int commit, int from_callback);
77 static void dnssdRegisterPrinter(cupsd_printer_t *p, int from_callback);
78 static void dnssdStop(void);
79 # ifdef HAVE_DNSSD
80 static void dnssdUpdate(void);
81 # endif /* HAVE_DNSSD */
82 static void dnssdUpdateDNSSDName(int from_callback);
83 #endif /* HAVE_DNSSD || HAVE_AVAHI */
84
85
86 /*
87 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
88 * local printer and remove any pending
89 * references to remote printers.
90 */
91
92 void
93 cupsdDeregisterPrinter(
94 cupsd_printer_t *p, /* I - Printer to register */
95 int removeit) /* I - Printer being permanently removed */
96 {
97 /*
98 * Only deregister if browsing is enabled and it's a local printer...
99 */
100
101 cupsdLogMessage(CUPSD_LOG_DEBUG,
102 "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
103 removeit);
104
105 if (!Browsing || !p->shared ||
106 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
107 return;
108
109 /*
110 * Announce the deletion...
111 */
112
113 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
114 if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
115 dnssdDeregisterPrinter(p, 1, 0);
116 #endif /* HAVE_DNSSD || HAVE_AVAHI */
117 }
118
119
120 /*
121 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
122 * printer or update the broadcast contents.
123 */
124
125 void
126 cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
127 {
128 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
129 p->name);
130
131 if (!Browsing || !BrowseLocalProtocols ||
132 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
133 return;
134
135 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
136 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
137 dnssdRegisterPrinter(p, 0);
138 #endif /* HAVE_DNSSD || HAVE_AVAHI */
139 }
140
141
142 /*
143 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
144 */
145
146 void
147 cupsdStartBrowsing(void)
148 {
149 if (!Browsing || !BrowseLocalProtocols)
150 return;
151
152 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
153 if (BrowseLocalProtocols & BROWSE_DNSSD)
154 {
155 # ifdef HAVE_DNSSD
156 DNSServiceErrorType error; /* Error from service creation */
157
158 /*
159 * First create a "master" connection for all registrations...
160 */
161
162 if ((error = DNSServiceCreateConnection(&DNSSDMaster))
163 != kDNSServiceErr_NoError)
164 {
165 cupsdLogMessage(CUPSD_LOG_ERROR,
166 "Unable to create master DNS-SD reference: %d", error);
167
168 if (FatalErrors & CUPSD_FATAL_BROWSE)
169 cupsdEndProcess(getpid(), 0);
170 }
171 else
172 {
173 /*
174 * Add the master connection to the select list...
175 */
176
177 int fd = DNSServiceRefSockFD(DNSSDMaster);
178
179 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
180
181 cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
182 }
183
184 /*
185 * Set the computer name and register the web interface...
186 */
187
188 DNSSDPort = 0;
189 cupsdUpdateDNSSDName();
190
191 # else /* HAVE_AVAHI */
192 if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL)
193 {
194 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create DNS-SD thread.");
195
196 if (FatalErrors & CUPSD_FATAL_BROWSE)
197 cupsdEndProcess(getpid(), 0);
198 }
199 else
200 {
201 int error; /* Error code, if any */
202
203 DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
204
205 if (DNSSDClient == NULL)
206 {
207 cupsdLogMessage(CUPSD_LOG_ERROR,
208 "Unable to communicate with avahi-daemon: %s",
209 dnssdErrorString(error));
210
211 if (FatalErrors & CUPSD_FATAL_BROWSE)
212 cupsdEndProcess(getpid(), 0);
213
214 avahi_threaded_poll_free(DNSSDMaster);
215 DNSSDMaster = NULL;
216 }
217 else
218 avahi_threaded_poll_start(DNSSDMaster);
219 }
220 # endif /* HAVE_DNSSD */
221 }
222 #endif /* HAVE_DNSSD || HAVE_AVAHI */
223
224 /*
225 * Enable LPD and SMB printer sharing as needed through external programs...
226 */
227
228 if (BrowseLocalProtocols & BROWSE_LPD)
229 update_lpd(1);
230
231 if (BrowseLocalProtocols & BROWSE_SMB)
232 update_smb(1);
233
234 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
235 /*
236 * Register the individual printers
237 */
238
239 dnssdRegisterAllPrinters(0);
240 #endif /* HAVE_DNSSD || HAVE_AVAHI */
241 }
242
243
244 /*
245 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
246 */
247
248 void
249 cupsdStopBrowsing(void)
250 {
251 if (!Browsing || !BrowseLocalProtocols)
252 return;
253
254 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
255 /*
256 * De-register the individual printers
257 */
258
259 dnssdDeregisterAllPrinters(0);
260
261 /*
262 * Shut down browsing sockets...
263 */
264
265 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
266 dnssdStop();
267 #endif /* HAVE_DNSSD || HAVE_AVAHI */
268
269 /*
270 * Disable LPD and SMB printer sharing as needed through external programs...
271 */
272
273 if (BrowseLocalProtocols & BROWSE_LPD)
274 update_lpd(0);
275
276 if (BrowseLocalProtocols & BROWSE_SMB)
277 update_smb(0);
278 }
279
280
281 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
282 /*
283 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
284 */
285
286 void
287 cupsdUpdateDNSSDName(void)
288 {
289 dnssdUpdateDNSSDName(0);
290 }
291
292
293 # ifdef __APPLE__
294 /*
295 * 'dnssdAddAlias()' - Add a DNS-SD alias name.
296 */
297
298 static void
299 dnssdAddAlias(const void *key, /* I - Key */
300 const void *value, /* I - Value (domain) */
301 void *context) /* I - Unused */
302 {
303 char valueStr[1024], /* Domain string */
304 hostname[1024], /* Complete hostname */
305 *hostptr; /* Pointer into hostname */
306
307
308 (void)key;
309 (void)context;
310
311 if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
312 CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
313 kCFStringEncodingUTF8))
314 {
315 snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
316 hostptr = hostname + strlen(hostname) - 1;
317 if (*hostptr == '.')
318 *hostptr = '\0'; /* Strip trailing dot */
319
320 if (!DNSSDAlias)
321 DNSSDAlias = cupsArrayNew(NULL, NULL);
322
323 cupsdAddAlias(DNSSDAlias, hostname);
324 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
325 hostname);
326 }
327 else
328 cupsdLogMessage(CUPSD_LOG_ERROR,
329 "Bad Back to My Mac domain in dynamic store!");
330 }
331 # endif /* __APPLE__ */
332
333
334 /*
335 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
336 */
337
338 static cupsd_txt_t /* O - TXT record */
339 dnssdBuildTxtRecord(
340 cupsd_printer_t *p, /* I - Printer information */
341 int for_lpd) /* I - 1 = LPD, 0 = IPP */
342 {
343 int i, /* Looping var */
344 count; /* Count of key/value pairs */
345 char admin_hostname[256], /* Hostname for admin page */
346 adminurl_str[256], /* URL for the admin page */
347 type_str[32], /* Type to string buffer */
348 state_str[32], /* State to string buffer */
349 rp_str[1024], /* Queue name string buffer */
350 air_str[1024], /* auth-info-required string buffer */
351 *keyvalue[32][2], /* Table of key/value pairs */
352 *ptr; /* Pointer in string */
353 cupsd_txt_t txt; /* TXT record */
354 cupsd_listener_t *lis; /* Current listener */
355 const char *admin_scheme = "http"; /* Admin page URL scheme */
356
357
358 /*
359 * Load up the key value pairs...
360 */
361
362 count = 0;
363
364 if (!for_lpd || (BrowseLocalProtocols & BROWSE_LPD))
365 {
366 keyvalue[count ][0] = "txtvers";
367 keyvalue[count++][1] = "1";
368
369 keyvalue[count ][0] = "qtotal";
370 keyvalue[count++][1] = "1";
371
372 keyvalue[count ][0] = "rp";
373 keyvalue[count++][1] = rp_str;
374 if (for_lpd)
375 strlcpy(rp_str, p->name, sizeof(rp_str));
376 else
377 snprintf(rp_str, sizeof(rp_str), "%s/%s",
378 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
379 p->name);
380
381 keyvalue[count ][0] = "ty";
382 keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown";
383
384 /*
385 * Get the hostname for the admin page...
386 */
387
388 if (strchr(DNSSDHostName, '.'))
389 {
390 /*
391 * Use the provided hostname, but make sure it ends with a period...
392 */
393
394 if ((ptr = DNSSDHostName + strlen(DNSSDHostName) - 1) >= DNSSDHostName && *ptr == '.')
395 strlcpy(admin_hostname, DNSSDHostName, sizeof(admin_hostname));
396 else
397 snprintf(admin_hostname, sizeof(admin_hostname), "%s.", DNSSDHostName);
398 }
399 else
400 {
401 /*
402 * Unqualified hostname gets ".local." added to it...
403 */
404
405 snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
406 }
407
408 /*
409 * Get the URL scheme for the admin page...
410 */
411
412 # ifdef HAVE_SSL
413 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
414 {
415 if (lis->encryption != HTTP_ENCRYPTION_NEVER)
416 {
417 admin_scheme = "https";
418 break;
419 }
420 }
421 # endif /* HAVE_SSL */
422
423 httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), admin_scheme, NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
424 keyvalue[count ][0] = "adminurl";
425 keyvalue[count++][1] = adminurl_str;
426
427 if (p->location)
428 {
429 keyvalue[count ][0] = "note";
430 keyvalue[count++][1] = p->location;
431 }
432
433 keyvalue[count ][0] = "priority";
434 keyvalue[count++][1] = for_lpd ? "100" : "0";
435
436 keyvalue[count ][0] = "product";
437 keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";
438
439 keyvalue[count ][0] = "pdl";
440 keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript";
441
442 if (get_auth_info_required(p, air_str, sizeof(air_str)))
443 {
444 keyvalue[count ][0] = "air";
445 keyvalue[count++][1] = air_str;
446 }
447
448 keyvalue[count ][0] = "UUID";
449 keyvalue[count++][1] = p->uuid + 9;
450
451 #ifdef HAVE_SSL
452 keyvalue[count ][0] = "TLS";
453 keyvalue[count++][1] = "1.2";
454 #endif /* HAVE_SSL */
455
456 if (p->type & CUPS_PRINTER_FAX)
457 {
458 keyvalue[count ][0] = "Fax";
459 keyvalue[count++][1] = "T";
460 keyvalue[count ][0] = "rfo";
461 keyvalue[count++][1] = rp_str;
462 }
463
464 if (p->type & CUPS_PRINTER_COLOR)
465 {
466 keyvalue[count ][0] = "Color";
467 keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
468 }
469
470 if (p->type & CUPS_PRINTER_DUPLEX)
471 {
472 keyvalue[count ][0] = "Duplex";
473 keyvalue[count++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
474 }
475
476 if (p->type & CUPS_PRINTER_STAPLE)
477 {
478 keyvalue[count ][0] = "Staple";
479 keyvalue[count++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
480 }
481
482 if (p->type & CUPS_PRINTER_COPIES)
483 {
484 keyvalue[count ][0] = "Copies";
485 keyvalue[count++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
486 }
487
488 if (p->type & CUPS_PRINTER_COLLATE)
489 {
490 keyvalue[count ][0] = "Collate";
491 keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
492 }
493
494 if (p->type & CUPS_PRINTER_PUNCH)
495 {
496 keyvalue[count ][0] = "Punch";
497 keyvalue[count++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
498 }
499
500 if (p->type & CUPS_PRINTER_BIND)
501 {
502 keyvalue[count ][0] = "Bind";
503 keyvalue[count++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
504 }
505
506 if (p->type & CUPS_PRINTER_SORT)
507 {
508 keyvalue[count ][0] = "Sort";
509 keyvalue[count++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
510 }
511
512 if (p->type & CUPS_PRINTER_MFP)
513 {
514 keyvalue[count ][0] = "Scan";
515 keyvalue[count++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
516 }
517
518 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
519 snprintf(state_str, sizeof(state_str), "%d", p->state);
520
521 keyvalue[count ][0] = "printer-state";
522 keyvalue[count++][1] = state_str;
523
524 keyvalue[count ][0] = "printer-type";
525 keyvalue[count++][1] = type_str;
526 }
527
528 /*
529 * Then pack them into a proper txt record...
530 */
531
532 # ifdef HAVE_DNSSD
533 TXTRecordCreate(&txt, 0, NULL);
534
535 for (i = 0; i < count; i ++)
536 {
537 size_t len = strlen(keyvalue[i][1]);
538
539 if (len < 256)
540 TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]);
541 }
542
543 # else
544 for (i = 0, txt = NULL; i < count; i ++)
545 txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0],
546 keyvalue[i][1]);
547 # endif /* HAVE_DNSSD */
548
549 return (txt);
550 }
551
552
553 # ifdef HAVE_AVAHI
554 /*
555 * 'dnssdClientCallback()' - Client callback for Avahi.
556 *
557 * Called whenever the client or server state changes...
558 */
559
560 static void
561 dnssdClientCallback(
562 AvahiClient *c, /* I - Client */
563 AvahiClientState state, /* I - Current state */
564 void *userdata) /* I - User data (unused) */
565 {
566 int error; /* Error code, if any */
567
568
569 (void)userdata;
570
571 if (!c)
572 return;
573
574 /*
575 * Make sure DNSSDClient is already set also if this callback function is
576 * already running before avahi_client_new() in dnssdStartBrowsing()
577 * finishes.
578 */
579
580 if (!DNSSDClient)
581 DNSSDClient = c;
582
583 switch (state)
584 {
585 case AVAHI_CLIENT_S_REGISTERING:
586 case AVAHI_CLIENT_S_RUNNING:
587 case AVAHI_CLIENT_S_COLLISION:
588 cupsdLogMessage(CUPSD_LOG_DEBUG, "Avahi server connection now available, registering printers for Bonjour broadcasting.");
589
590 /*
591 * Mark that Avahi server is running...
592 */
593
594 avahi_running = 1;
595
596 /*
597 * Set the computer name and register the web interface...
598 */
599
600 DNSSDPort = 0;
601 dnssdUpdateDNSSDName(1);
602
603 /*
604 * Register the individual printers
605 */
606
607 dnssdRegisterAllPrinters(1);
608 break;
609
610 case AVAHI_CLIENT_FAILURE:
611 if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED)
612 {
613 cupsdLogMessage(CUPSD_LOG_DEBUG, "Avahi server disappeared, unregistering printers for Bonjour broadcasting.");
614
615 /*
616 * Unregister everything and close the client...
617 */
618
619 dnssdDeregisterAllPrinters(1);
620 dnssdDeregisterInstance(&WebIFSrv, 1);
621 avahi_client_free(DNSSDClient);
622 DNSSDClient = NULL;
623
624 /*
625 * Mark that Avahi server is not running...
626 */
627
628 avahi_running = 0;
629
630 /*
631 * Renew Avahi client...
632 */
633
634 DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
635
636 if (!DNSSDClient)
637 {
638 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to communicate with avahi-daemon: %s", dnssdErrorString(error));
639 if (FatalErrors & CUPSD_FATAL_BROWSE)
640 cupsdEndProcess(getpid(), 0);
641 }
642 }
643 else
644 {
645 cupsdLogMessage(CUPSD_LOG_ERROR, "Communication with avahi-daemon has failed: %s", avahi_strerror(avahi_client_errno(c)));
646 if (FatalErrors & CUPSD_FATAL_BROWSE)
647 cupsdEndProcess(getpid(), 0);
648 }
649 break;
650
651 default:
652 break;
653 }
654 }
655 # endif /* HAVE_AVAHI */
656
657
658 /*
659 * 'dnssdDeregisterAllPrinters()' - Deregister all printers.
660 */
661
662 static void
663 dnssdDeregisterAllPrinters(
664 int from_callback) /* I - Deregistering because of callback? */
665 {
666 cupsd_printer_t *p; /* Current printer */
667
668
669 if (!DNSSDMaster)
670 return;
671
672 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
673 p;
674 p = (cupsd_printer_t *)cupsArrayNext(Printers))
675 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
676 dnssdDeregisterPrinter(p, 1, from_callback);
677 }
678
679
680 /*
681 * 'dnssdDeregisterInstance()' - Deregister a DNS-SD service instance.
682 */
683
684 static void
685 dnssdDeregisterInstance(
686 cupsd_srv_t *srv, /* I - Service */
687 int from_callback) /* I - Called from callback? */
688 {
689 if (!srv || !*srv)
690 return;
691
692 # ifdef HAVE_DNSSD
693 (void)from_callback;
694
695 DNSServiceRefDeallocate(*srv);
696
697 # else /* HAVE_AVAHI */
698 if (!from_callback)
699 avahi_threaded_poll_lock(DNSSDMaster);
700
701 if (*srv)
702 avahi_entry_group_free(*srv);
703
704 if (!from_callback)
705 avahi_threaded_poll_unlock(DNSSDMaster);
706 # endif /* HAVE_DNSSD */
707
708 *srv = NULL;
709 }
710
711
712 /*
713 * 'dnssdDeregisterPrinter()' - Deregister all services for a printer.
714 */
715
716 static void
717 dnssdDeregisterPrinter(
718 cupsd_printer_t *p, /* I - Printer */
719 int clear_name, /* I - Clear the name? */
720 int from_callback) /* I - Called from callback? */
721
722 {
723 cupsdLogMessage(CUPSD_LOG_DEBUG2,
724 "dnssdDeregisterPrinter(p=%p(%s), clear_name=%d)", p, p->name,
725 clear_name);
726
727 if (p->ipp_srv)
728 {
729 dnssdDeregisterInstance(&p->ipp_srv, from_callback);
730
731 # ifdef HAVE_DNSSD
732 # ifdef HAVE_SSL
733 dnssdDeregisterInstance(&p->ipps_srv, from_callback);
734 # endif /* HAVE_SSL */
735 dnssdDeregisterInstance(&p->printer_srv, from_callback);
736 # endif /* HAVE_DNSSD */
737 }
738
739 /*
740 * Remove the printer from the array of DNS-SD printers but keep the
741 * registered name...
742 */
743
744 cupsArrayRemove(DNSSDPrinters, p);
745
746 /*
747 * Optionally clear the service name...
748 */
749
750 if (clear_name)
751 cupsdClearString(&p->reg_name);
752 }
753
754
755 /*
756 * 'dnssdErrorString()' - Return an error string for an error code.
757 */
758
759 static const char * /* O - Error message */
760 dnssdErrorString(int error) /* I - Error number */
761 {
762 # ifdef HAVE_DNSSD
763 switch (error)
764 {
765 case kDNSServiceErr_NoError :
766 return ("OK.");
767
768 default :
769 case kDNSServiceErr_Unknown :
770 return ("Unknown error.");
771
772 case kDNSServiceErr_NoSuchName :
773 return ("Service not found.");
774
775 case kDNSServiceErr_NoMemory :
776 return ("Out of memory.");
777
778 case kDNSServiceErr_BadParam :
779 return ("Bad parameter.");
780
781 case kDNSServiceErr_BadReference :
782 return ("Bad service reference.");
783
784 case kDNSServiceErr_BadState :
785 return ("Bad state.");
786
787 case kDNSServiceErr_BadFlags :
788 return ("Bad flags.");
789
790 case kDNSServiceErr_Unsupported :
791 return ("Unsupported.");
792
793 case kDNSServiceErr_NotInitialized :
794 return ("Not initialized.");
795
796 case kDNSServiceErr_AlreadyRegistered :
797 return ("Already registered.");
798
799 case kDNSServiceErr_NameConflict :
800 return ("Name conflict.");
801
802 case kDNSServiceErr_Invalid :
803 return ("Invalid name.");
804
805 case kDNSServiceErr_Firewall :
806 return ("Firewall prevents registration.");
807
808 case kDNSServiceErr_Incompatible :
809 return ("Client library incompatible.");
810
811 case kDNSServiceErr_BadInterfaceIndex :
812 return ("Bad interface index.");
813
814 case kDNSServiceErr_Refused :
815 return ("Server prevents registration.");
816
817 case kDNSServiceErr_NoSuchRecord :
818 return ("Record not found.");
819
820 case kDNSServiceErr_NoAuth :
821 return ("Authentication required.");
822
823 case kDNSServiceErr_NoSuchKey :
824 return ("Encryption key not found.");
825
826 case kDNSServiceErr_NATTraversal :
827 return ("Unable to traverse NAT boundary.");
828
829 case kDNSServiceErr_DoubleNAT :
830 return ("Unable to traverse double-NAT boundary.");
831
832 case kDNSServiceErr_BadTime :
833 return ("Bad system time.");
834
835 case kDNSServiceErr_BadSig :
836 return ("Bad signature.");
837
838 case kDNSServiceErr_BadKey :
839 return ("Bad encryption key.");
840
841 case kDNSServiceErr_Transient :
842 return ("Transient error occurred - please try again.");
843
844 case kDNSServiceErr_ServiceNotRunning :
845 return ("Server not running.");
846
847 case kDNSServiceErr_NATPortMappingUnsupported :
848 return ("NAT doesn't support NAT-PMP or UPnP.");
849
850 case kDNSServiceErr_NATPortMappingDisabled :
851 return ("NAT supports NAT-PNP or UPnP but it is disabled.");
852
853 case kDNSServiceErr_NoRouter :
854 return ("No Internet/default router configured.");
855
856 case kDNSServiceErr_PollingMode :
857 return ("Service polling mode error.");
858
859 case kDNSServiceErr_Timeout :
860 return ("Service timeout.");
861 }
862
863 # else /* HAVE_AVAHI */
864 return (avahi_strerror(error));
865 # endif /* HAVE_DNSSD */
866 }
867
868
869 /*
870 * 'dnssdRegisterCallback()' - Free a TXT record.
871 */
872
873 static void
874 dnssdFreeTxtRecord(cupsd_txt_t *txt) /* I - TXT record */
875 {
876 # ifdef HAVE_DNSSD
877 TXTRecordDeallocate(txt);
878
879 # else /* HAVE_AVAHI */
880 avahi_string_list_free(*txt);
881 *txt = NULL;
882 # endif /* HAVE_DNSSD */
883 }
884
885
886 /*
887 * 'dnssdRegisterAllPrinters()' - Register all printers.
888 */
889
890 static void
891 dnssdRegisterAllPrinters(int from_callback) /* I - Called from callback? */
892 {
893 cupsd_printer_t *p; /* Current printer */
894
895
896 if (!DNSSDMaster)
897 return;
898
899 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
900 p;
901 p = (cupsd_printer_t *)cupsArrayNext(Printers))
902 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
903 dnssdRegisterPrinter(p, from_callback);
904 }
905
906
907 /*
908 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
909 */
910
911 # ifdef HAVE_DNSSD
912 static void
913 dnssdRegisterCallback(
914 DNSServiceRef sdRef, /* I - DNS Service reference */
915 DNSServiceFlags flags, /* I - Reserved for future use */
916 DNSServiceErrorType errorCode, /* I - Error code */
917 const char *name, /* I - Service name */
918 const char *regtype, /* I - Service type */
919 const char *domain, /* I - Domain. ".local" for now */
920 void *context) /* I - Printer */
921 {
922 cupsd_printer_t *p = (cupsd_printer_t *)context;
923 /* Current printer */
924
925
926 (void)sdRef;
927 (void)flags;
928 (void)domain;
929
930 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
931 name, regtype, p ? p->name : "Web Interface",
932 p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
933
934 if (errorCode)
935 {
936 cupsdLogMessage(CUPSD_LOG_ERROR,
937 "DNSServiceRegister failed with error %d", (int)errorCode);
938 return;
939 }
940 else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name)))
941 {
942 cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
943 name, p->name);
944
945 cupsArrayRemove(DNSSDPrinters, p);
946 cupsdSetString(&p->reg_name, name);
947 cupsArrayAdd(DNSSDPrinters, p);
948
949 LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
950 }
951 }
952
953 # else /* HAVE_AVAHI */
954 static void
955 dnssdRegisterCallback(
956 AvahiEntryGroup *srv, /* I - Service */
957 AvahiEntryGroupState state, /* I - Registration state */
958 void *context) /* I - Printer */
959 {
960 cupsd_printer_t *p = (cupsd_printer_t *)context;
961 /* Current printer */
962
963 cupsdLogMessage(CUPSD_LOG_DEBUG2,
964 "dnssdRegisterCallback(srv=%p, state=%d, context=%p) "
965 "for %s (%s)", srv, state, context,
966 p ? p->name : "Web Interface",
967 p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
968
969 /* TODO: Handle collisions with avahi_alternate_service_name(p->reg_name)? */
970 }
971 # endif /* HAVE_DNSSD */
972
973
974 /*
975 * 'dnssdRegisterInstance()' - Register an instance of a printer service.
976 */
977
978 static int /* O - 1 on success, 0 on failure */
979 dnssdRegisterInstance(
980 cupsd_srv_t *srv, /* O - Service */
981 cupsd_printer_t *p, /* I - Printer */
982 char *name, /* I - DNS-SD service name */
983 const char *type, /* I - DNS-SD service type */
984 const char *subtypes, /* I - Subtypes to register or NULL */
985 int port, /* I - Port number or 0 */
986 cupsd_txt_t *txt, /* I - TXT record */
987 int commit, /* I - Commit registration? */
988 int from_callback) /* I - Called from callback? */
989 {
990 char temp[256], /* Temporary string */
991 *ptr; /* Pointer into string */
992 int error; /* Any error */
993
994
995 # ifdef HAVE_DNSSD
996 (void)from_callback;
997 # endif /* HAVE_DNSSD */
998
999 cupsdLogMessage(CUPSD_LOG_DEBUG, "Registering \"%s\" with DNS-SD type \"%s\".", name, type);
1000
1001 if (p && !srv)
1002 {
1003 /*
1004 * Assign the correct pointer for "srv"...
1005 */
1006
1007 # ifdef HAVE_DNSSD
1008 if (!strcmp(type, "_printer._tcp"))
1009 srv = &p->printer_srv; /* Target LPD service */
1010 # ifdef HAVE_SSL
1011 else if (!strcmp(type, "_ipps._tcp"))
1012 srv = &p->ipps_srv; /* Target IPPS service */
1013 # endif /* HAVE_SSL */
1014 else
1015 srv = &p->ipp_srv; /* Target IPP service */
1016
1017 # else /* HAVE_AVAHI */
1018 srv = &p->ipp_srv; /* Target service group */
1019 # endif /* HAVE_DNSSD */
1020 }
1021
1022 # ifdef HAVE_DNSSD
1023 (void)commit;
1024
1025 # else /* HAVE_AVAHI */
1026 if (!from_callback)
1027 avahi_threaded_poll_lock(DNSSDMaster);
1028
1029 if (!*srv)
1030 *srv = avahi_entry_group_new(DNSSDClient, dnssdRegisterCallback, NULL);
1031 if (!*srv)
1032 {
1033 if (!from_callback)
1034 avahi_threaded_poll_unlock(DNSSDMaster);
1035
1036 cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
1037 name, dnssdErrorString(avahi_client_errno(DNSSDClient)));
1038 return (0);
1039 }
1040 # endif /* HAVE_DNSSD */
1041
1042 /*
1043 * Make sure the name is <= 63 octets, and when we truncate be sure to
1044 * properly truncate any UTF-8 characters...
1045 */
1046
1047 ptr = name + strlen(name);
1048 while ((ptr - name) > 63)
1049 {
1050 do
1051 {
1052 ptr --;
1053 }
1054 while (ptr > name && (*ptr & 0xc0) == 0x80);
1055
1056 if (ptr > name)
1057 *ptr = '\0';
1058 }
1059
1060 /*
1061 * Register the service...
1062 */
1063
1064 # ifdef HAVE_DNSSD
1065 if (subtypes)
1066 snprintf(temp, sizeof(temp), "%s,%s", type, subtypes);
1067 else
1068 strlcpy(temp, type, sizeof(temp));
1069
1070 *srv = DNSSDMaster;
1071 error = DNSServiceRegister(srv, kDNSServiceFlagsShareConnection,
1072 0, name, temp, NULL, DNSSDHostName, htons(port),
1073 txt ? TXTRecordGetLength(txt) : 0,
1074 txt ? TXTRecordGetBytesPtr(txt) : NULL,
1075 dnssdRegisterCallback, p);
1076
1077 # else /* HAVE_AVAHI */
1078 if (txt)
1079 {
1080 AvahiStringList *temptxt;
1081 for (temptxt = *txt; temptxt; temptxt = temptxt->next)
1082 cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS_SD \"%s\" %s", name, temptxt->text);
1083 }
1084
1085 error = avahi_entry_group_add_service_strlst(*srv, AVAHI_IF_UNSPEC,
1086 AVAHI_PROTO_UNSPEC, 0, name,
1087 type, NULL, DNSSDHostName, port,
1088 txt ? *txt : NULL);
1089 if (error)
1090 cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD service add for \"%s\" failed.",
1091 name);
1092
1093 if (!error && subtypes)
1094 {
1095 /*
1096 * Register all of the subtypes...
1097 */
1098
1099 char *start, /* Start of subtype */
1100 subtype[256]; /* Subtype string */
1101
1102 strlcpy(temp, subtypes, sizeof(temp));
1103
1104 for (start = temp; *start; start = ptr)
1105 {
1106 /*
1107 * Skip leading whitespace...
1108 */
1109
1110 while (*start && isspace(*start & 255))
1111 start ++;
1112
1113 /*
1114 * Grab everything up to the next comma or the end of the string...
1115 */
1116
1117 for (ptr = start; *ptr && *ptr != ','; ptr ++);
1118
1119 if (*ptr)
1120 *ptr++ = '\0';
1121
1122 if (!*start)
1123 break;
1124
1125 /*
1126 * Register the subtype...
1127 */
1128
1129 snprintf(subtype, sizeof(subtype), "%s._sub.%s", start, type);
1130
1131 error = avahi_entry_group_add_service_subtype(*srv, AVAHI_IF_UNSPEC,
1132 AVAHI_PROTO_UNSPEC, 0,
1133 name, type, NULL, subtype);
1134 if (error)
1135 {
1136 cupsdLogMessage(CUPSD_LOG_DEBUG,
1137 "DNS-SD subtype %s registration for \"%s\" failed." ,
1138 subtype, name);
1139 break;
1140 }
1141 }
1142 }
1143
1144 if (!error && commit)
1145 {
1146 if ((error = avahi_entry_group_commit(*srv)) != 0)
1147 cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD commit of \"%s\" failed.",
1148 name);
1149 }
1150
1151 if (!from_callback)
1152 avahi_threaded_poll_unlock(DNSSDMaster);
1153 # endif /* HAVE_DNSSD */
1154
1155 if (error)
1156 {
1157 cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
1158 name, dnssdErrorString(error));
1159 cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD type: %s", type);
1160 if (subtypes)
1161 cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD sub-types: %s", subtypes);
1162 }
1163
1164 return (!error);
1165 }
1166
1167
1168 /*
1169 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
1170 * or update the broadcast contents.
1171 */
1172
1173 static void
1174 dnssdRegisterPrinter(
1175 cupsd_printer_t *p, /* I - Printer */
1176 int from_callback) /* I - Called from callback? */
1177 {
1178 char name[256]; /* Service name */
1179 int printer_port; /* LPD port number */
1180 int status; /* Registration status */
1181 cupsd_txt_t ipp_txt, /* IPP(S) TXT record */
1182 printer_txt; /* LPD TXT record */
1183
1184
1185 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
1186 !p->ipp_srv ? "new" : "update");
1187
1188 # ifdef HAVE_AVAHI
1189 if (!avahi_running)
1190 return;
1191 # endif /* HAVE_AVAHI */
1192
1193 /*
1194 * Remove the current registrations if we have them and then return if
1195 * per-printer sharing was just disabled...
1196 */
1197
1198 dnssdDeregisterPrinter(p, 0, from_callback);
1199
1200 if (!p->shared)
1201 return;
1202
1203 /*
1204 * Set the registered name as needed; the registered name takes the form of
1205 * "<printer-info> @ <computer name>"...
1206 */
1207
1208 if (!p->reg_name)
1209 {
1210 if (p->info && strlen(p->info) > 0)
1211 {
1212 if (DNSSDComputerName)
1213 snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName);
1214 else
1215 strlcpy(name, p->info, sizeof(name));
1216 }
1217 else if (DNSSDComputerName)
1218 snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
1219 else
1220 strlcpy(name, p->name, sizeof(name));
1221 }
1222 else
1223 strlcpy(name, p->reg_name, sizeof(name));
1224
1225 /*
1226 * Register IPP and LPD...
1227 *
1228 * We always must register the "_printer" service type in order to reserve
1229 * our name, but use port number 0 if we haven't actually configured cups-lpd
1230 * to share via LPD...
1231 */
1232
1233 ipp_txt = dnssdBuildTxtRecord(p, 0);
1234 printer_txt = dnssdBuildTxtRecord(p, 1);
1235
1236 if (BrowseLocalProtocols & BROWSE_LPD)
1237 printer_port = 515;
1238 else
1239 printer_port = 0;
1240
1241 status = dnssdRegisterInstance(NULL, p, name, "_printer._tcp", NULL, printer_port, &printer_txt, 0, from_callback);
1242
1243 # ifdef HAVE_SSL
1244 if (status)
1245 dnssdRegisterInstance(NULL, p, name, "_ipps._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 0, from_callback);
1246 # endif /* HAVE_SSL */
1247
1248 if (status)
1249 {
1250 /*
1251 * Use the "_fax-ipp" service type for fax queues, otherwise use "_ipp"...
1252 */
1253
1254 if (p->type & CUPS_PRINTER_FAX)
1255 status = dnssdRegisterInstance(NULL, p, name, "_fax-ipp._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 1, from_callback);
1256 else
1257 status = dnssdRegisterInstance(NULL, p, name, "_ipp._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 1, from_callback);
1258 }
1259
1260 dnssdFreeTxtRecord(&ipp_txt);
1261 dnssdFreeTxtRecord(&printer_txt);
1262
1263 if (status)
1264 {
1265 /*
1266 * Save the registered name and add the printer to the array of DNS-SD
1267 * printers...
1268 */
1269
1270 cupsdSetString(&p->reg_name, name);
1271 cupsArrayAdd(DNSSDPrinters, p);
1272 }
1273 else
1274 {
1275 /*
1276 * Registration failed for this printer...
1277 */
1278
1279 dnssdDeregisterInstance(&p->ipp_srv, from_callback);
1280
1281 # ifdef HAVE_DNSSD
1282 # ifdef HAVE_SSL
1283 dnssdDeregisterInstance(&p->ipps_srv, from_callback);
1284 # endif /* HAVE_SSL */
1285 dnssdDeregisterInstance(&p->printer_srv, from_callback);
1286 # endif /* HAVE_DNSSD */
1287 }
1288 }
1289
1290
1291 /*
1292 * 'dnssdStop()' - Stop all DNS-SD registrations.
1293 */
1294
1295 static void
1296 dnssdStop(void)
1297 {
1298 cupsd_printer_t *p; /* Current printer */
1299
1300
1301 /*
1302 * De-register the individual printers
1303 */
1304
1305 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1306 p;
1307 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1308 dnssdDeregisterPrinter(p, 1, 0);
1309
1310 /*
1311 * Shutdown the rest of the service refs...
1312 */
1313
1314 dnssdDeregisterInstance(&WebIFSrv, 0);
1315
1316 # ifdef HAVE_DNSSD
1317 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDMaster));
1318
1319 DNSServiceRefDeallocate(DNSSDMaster);
1320 DNSSDMaster = NULL;
1321
1322 # else /* HAVE_AVAHI */
1323 if (DNSSDMaster)
1324 avahi_threaded_poll_stop(DNSSDMaster);
1325
1326 if (DNSSDClient)
1327 {
1328 avahi_client_free(DNSSDClient);
1329 DNSSDClient = NULL;
1330 }
1331
1332 if (DNSSDMaster)
1333 {
1334 avahi_threaded_poll_free(DNSSDMaster);
1335 DNSSDMaster = NULL;
1336 }
1337 # endif /* HAVE_DNSSD */
1338
1339 cupsArrayDelete(DNSSDPrinters);
1340 DNSSDPrinters = NULL;
1341
1342 DNSSDPort = 0;
1343 }
1344
1345
1346 # ifdef HAVE_DNSSD
1347 /*
1348 * 'dnssdUpdate()' - Handle DNS-SD queries.
1349 */
1350
1351 static void
1352 dnssdUpdate(void)
1353 {
1354 DNSServiceErrorType sdErr; /* Service discovery error */
1355
1356
1357 if ((sdErr = DNSServiceProcessResult(DNSSDMaster)) != kDNSServiceErr_NoError)
1358 {
1359 cupsdLogMessage(CUPSD_LOG_ERROR,
1360 "DNS Service Discovery registration error %d!",
1361 sdErr);
1362 dnssdStop();
1363 }
1364 }
1365 # endif /* HAVE_DNSSD */
1366
1367
1368 /*
1369 * 'dnssdUpdateDNSSDName()' - Update the listen port, computer name, and web interface registration.
1370 */
1371
1372 static void
1373 dnssdUpdateDNSSDName(int from_callback) /* I - Called from callback? */
1374 {
1375 char webif[1024]; /* Web interface share name */
1376 # ifdef __APPLE__
1377 SCDynamicStoreRef sc; /* Context for dynamic store */
1378 CFDictionaryRef btmm; /* Back-to-My-Mac domains */
1379 CFStringEncoding nameEncoding; /* Encoding of computer name */
1380 CFStringRef nameRef; /* Host name CFString */
1381 char nameBuffer[1024]; /* C-string buffer */
1382 # endif /* __APPLE__ */
1383
1384
1385 /*
1386 * Only share the web interface and printers when non-local listening is
1387 * enabled...
1388 */
1389
1390 if (!DNSSDPort)
1391 {
1392 /*
1393 * Get the port we use for registrations. If we are not listening on any
1394 * non-local ports, there is no sense sharing local printers via Bonjour...
1395 */
1396
1397 cupsd_listener_t *lis; /* Current listening socket */
1398
1399 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1400 lis;
1401 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1402 {
1403 if (httpAddrLocalhost(&(lis->address)))
1404 continue;
1405
1406 DNSSDPort = httpAddrPort(&(lis->address));
1407 break;
1408 }
1409 }
1410
1411 if (!DNSSDPort)
1412 return;
1413
1414 /*
1415 * Get the computer name as a c-string...
1416 */
1417
1418 # ifdef __APPLE__
1419 sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
1420
1421 if (sc)
1422 {
1423 /*
1424 * Get the computer name from the dynamic store...
1425 */
1426
1427 cupsdClearString(&DNSSDComputerName);
1428
1429 if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
1430 {
1431 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
1432 kCFStringEncodingUTF8))
1433 {
1434 cupsdLogMessage(CUPSD_LOG_DEBUG,
1435 "Dynamic store computer name is \"%s\".", nameBuffer);
1436 cupsdSetString(&DNSSDComputerName, nameBuffer);
1437 }
1438
1439 CFRelease(nameRef);
1440 }
1441
1442 if (!DNSSDComputerName)
1443 {
1444 /*
1445 * Use the ServerName instead...
1446 */
1447
1448 cupsdLogMessage(CUPSD_LOG_DEBUG,
1449 "Using ServerName \"%s\" as computer name.", ServerName);
1450 cupsdSetString(&DNSSDComputerName, ServerName);
1451 }
1452
1453 if (!DNSSDHostName)
1454 {
1455 /*
1456 * Get the local hostname from the dynamic store...
1457 */
1458
1459 if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
1460 {
1461 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
1462 kCFStringEncodingUTF8))
1463 {
1464 cupsdLogMessage(CUPSD_LOG_DEBUG, "Dynamic store host name is \"%s\".", nameBuffer);
1465
1466 if (strchr(nameBuffer, '.'))
1467 cupsdSetString(&DNSSDHostName, nameBuffer);
1468 else
1469 cupsdSetStringf(&DNSSDHostName, "%s.local", nameBuffer);
1470
1471 cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
1472 }
1473
1474 CFRelease(nameRef);
1475 }
1476 }
1477
1478 if (!DNSSDHostName)
1479 {
1480 /*
1481 * Use the ServerName instead...
1482 */
1483
1484 cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as host name.", ServerName);
1485 cupsdSetString(&DNSSDHostName, ServerName);
1486
1487 cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
1488 }
1489
1490 /*
1491 * Get any Back-to-My-Mac domains and add them as aliases...
1492 */
1493
1494 cupsdFreeAliases(DNSSDAlias);
1495 DNSSDAlias = NULL;
1496
1497 btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
1498 if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
1499 {
1500 cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
1501 (int)CFDictionaryGetCount(btmm));
1502 CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
1503 }
1504 else if (btmm)
1505 cupsdLogMessage(CUPSD_LOG_ERROR,
1506 "Bad Back to My Mac data in dynamic store!");
1507 else
1508 cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
1509
1510 if (btmm)
1511 CFRelease(btmm);
1512
1513 CFRelease(sc);
1514 }
1515 else
1516 # endif /* __APPLE__ */
1517 # ifdef HAVE_AVAHI
1518 if (DNSSDClient)
1519 {
1520 const char *host_name = avahi_client_get_host_name(DNSSDClient);
1521
1522 cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName);
1523
1524 if (!DNSSDHostName)
1525 {
1526 const char *host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient);
1527
1528 if (host_fqdn)
1529 cupsdSetString(&DNSSDHostName, host_fqdn);
1530 else if (strchr(ServerName, '.'))
1531 cupsdSetString(&DNSSDHostName, ServerName);
1532 else
1533 cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
1534
1535 cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
1536 }
1537 }
1538 else
1539 # endif /* HAVE_AVAHI */
1540 {
1541 cupsdSetString(&DNSSDComputerName, ServerName);
1542
1543 if (!DNSSDHostName)
1544 {
1545 if (strchr(ServerName, '.'))
1546 cupsdSetString(&DNSSDHostName, ServerName);
1547 else
1548 cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
1549
1550 cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
1551 }
1552 }
1553
1554 /*
1555 * Then (re)register the web interface if enabled...
1556 */
1557
1558 if (BrowseWebIF)
1559 {
1560 if (DNSSDComputerName)
1561 snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
1562 else
1563 strlcpy(webif, "CUPS", sizeof(webif));
1564
1565 dnssdDeregisterInstance(&WebIFSrv, from_callback);
1566 dnssdRegisterInstance(&WebIFSrv, NULL, webif, "_http._tcp", "_printer", DNSSDPort, NULL, 1, from_callback);
1567 }
1568 }
1569
1570
1571 /*
1572 * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
1573 */
1574
1575 static char * /* O - String or NULL if none */
1576 get_auth_info_required(
1577 cupsd_printer_t *p, /* I - Printer */
1578 char *buffer, /* I - Value buffer */
1579 size_t bufsize) /* I - Size of value buffer */
1580 {
1581 cupsd_location_t *auth; /* Pointer to authentication element */
1582 char resource[1024]; /* Printer/class resource path */
1583
1584
1585 /*
1586 * If auth-info-required is set for this printer, return that...
1587 */
1588
1589 if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
1590 {
1591 int i; /* Looping var */
1592 char *bufptr; /* Pointer into buffer */
1593
1594 for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
1595 {
1596 if (bufptr >= (buffer + bufsize - 2))
1597 break;
1598
1599 if (i)
1600 *bufptr++ = ',';
1601
1602 strlcpy(bufptr, p->auth_info_required[i], bufsize - (size_t)(bufptr - buffer));
1603 bufptr += strlen(bufptr);
1604 }
1605
1606 return (buffer);
1607 }
1608
1609 /*
1610 * Figure out the authentication data requirements to advertise...
1611 */
1612
1613 if (p->type & CUPS_PRINTER_CLASS)
1614 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
1615 else
1616 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
1617
1618 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
1619 auth->type == CUPSD_AUTH_NONE)
1620 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
1621
1622 if (auth)
1623 {
1624 int auth_type; /* Authentication type */
1625
1626 if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
1627 auth_type = cupsdDefaultAuthType();
1628
1629 switch (auth_type)
1630 {
1631 case CUPSD_AUTH_NONE :
1632 return (NULL);
1633
1634 case CUPSD_AUTH_NEGOTIATE :
1635 strlcpy(buffer, "negotiate", bufsize);
1636 break;
1637
1638 default :
1639 strlcpy(buffer, "username,password", bufsize);
1640 break;
1641 }
1642
1643 return (buffer);
1644 }
1645
1646 return ("none");
1647 }
1648 #endif /* HAVE_DNSSD || HAVE_AVAHI */
1649
1650
1651 #ifdef __APPLE__
1652 /*
1653 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
1654 */
1655
1656 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
1657 get_hostconfig(const char *name) /* I - Name of service */
1658 {
1659 cups_file_t *fp; /* Hostconfig file */
1660 char line[1024], /* Line from file */
1661 *ptr; /* Pointer to value */
1662 int state = 1; /* State of service */
1663
1664
1665 /*
1666 * Try opening the /etc/hostconfig file; if we can't open it, assume that
1667 * the service is enabled/auto.
1668 */
1669
1670 if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
1671 {
1672 /*
1673 * Read lines from the file until we find the service...
1674 */
1675
1676 while (cupsFileGets(fp, line, sizeof(line)))
1677 {
1678 if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
1679 continue;
1680
1681 *ptr++ = '\0';
1682
1683 if (!_cups_strcasecmp(line, name))
1684 {
1685 /*
1686 * Found the service, see if it is set to "-NO-"...
1687 */
1688
1689 if (!_cups_strncasecmp(ptr, "-NO-", 4))
1690 state = 0;
1691 break;
1692 }
1693 }
1694
1695 cupsFileClose(fp);
1696 }
1697
1698 return (state);
1699 }
1700 #endif /* __APPLE__ */
1701
1702
1703 /*
1704 * 'update_lpd()' - Update the LPD configuration as needed.
1705 */
1706
1707 static void
1708 update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
1709 {
1710 if (!LPDConfigFile)
1711 return;
1712
1713 #ifdef __APPLE__
1714 /*
1715 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
1716 * setting for backwards-compatibility.
1717 */
1718
1719 if (onoff && !get_hostconfig("CUPS_LPD"))
1720 onoff = 0;
1721 #endif /* __APPLE__ */
1722
1723 if (!strncmp(LPDConfigFile, "xinetd:///", 10))
1724 {
1725 /*
1726 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
1727 */
1728
1729 char newfile[1024]; /* New cups-lpd.N file */
1730 cups_file_t *ofp, /* Original file pointer */
1731 *nfp; /* New file pointer */
1732 char line[1024]; /* Line from file */
1733
1734
1735 snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
1736
1737 if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
1738 {
1739 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
1740 LPDConfigFile + 9, strerror(errno));
1741 return;
1742 }
1743
1744 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
1745 {
1746 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
1747 newfile, strerror(errno));
1748 cupsFileClose(ofp);
1749 return;
1750 }
1751
1752 /*
1753 * Copy all of the lines from the cups-lpd file...
1754 */
1755
1756 while (cupsFileGets(ofp, line, sizeof(line)))
1757 {
1758 if (line[0] == '{')
1759 {
1760 cupsFilePrintf(nfp, "%s\n", line);
1761 snprintf(line, sizeof(line), "\tdisable = %s",
1762 onoff ? "no" : "yes");
1763 }
1764 else if (!strstr(line, "disable ="))
1765 cupsFilePrintf(nfp, "%s\n", line);
1766 }
1767
1768 cupsFileClose(nfp);
1769 cupsFileClose(ofp);
1770 rename(newfile, LPDConfigFile + 9);
1771 }
1772 #ifdef __APPLE__
1773 else if (!strncmp(LPDConfigFile, "launchd:///", 11))
1774 {
1775 /*
1776 * Enable/disable LPD via the launchctl command...
1777 */
1778
1779 char *argv[5], /* Arguments for command */
1780 *envp[MAX_ENV]; /* Environment for command */
1781 int pid; /* Process ID */
1782
1783
1784 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1785 argv[0] = (char *)"launchctl";
1786 argv[1] = (char *)(onoff ? "load" : "unload");
1787 argv[2] = (char *)"-w";
1788 argv[3] = LPDConfigFile + 10;
1789 argv[4] = NULL;
1790
1791 cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
1792 NULL, NULL, &pid);
1793 }
1794 #endif /* __APPLE__ */
1795 else
1796 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
1797 }
1798
1799
1800 /*
1801 * 'update_smb()' - Update the SMB configuration as needed.
1802 */
1803
1804 static void
1805 update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
1806 {
1807 if (!SMBConfigFile)
1808 return;
1809
1810 if (!strncmp(SMBConfigFile, "samba:///", 9))
1811 {
1812 /*
1813 * Enable/disable SMB via the specified smb.conf config file...
1814 */
1815
1816 char newfile[1024]; /* New smb.conf.N file */
1817 cups_file_t *ofp, /* Original file pointer */
1818 *nfp; /* New file pointer */
1819 char line[1024]; /* Line from file */
1820 int in_printers; /* In [printers] section? */
1821
1822
1823 snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
1824
1825 if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
1826 {
1827 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
1828 SMBConfigFile + 8, strerror(errno));
1829 return;
1830 }
1831
1832 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
1833 {
1834 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
1835 newfile, strerror(errno));
1836 cupsFileClose(ofp);
1837 return;
1838 }
1839
1840 /*
1841 * Copy all of the lines from the smb.conf file...
1842 */
1843
1844 in_printers = 0;
1845
1846 while (cupsFileGets(ofp, line, sizeof(line)))
1847 {
1848 if (in_printers && strstr(line, "printable ="))
1849 snprintf(line, sizeof(line), " printable = %s",
1850 onoff ? "yes" : "no");
1851
1852 cupsFilePrintf(nfp, "%s\n", line);
1853
1854 if (line[0] == '[')
1855 in_printers = !strcmp(line, "[printers]");
1856 }
1857
1858 cupsFileClose(nfp);
1859 cupsFileClose(ofp);
1860 rename(newfile, SMBConfigFile + 8);
1861 }
1862 else
1863 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
1864 }