• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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