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