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