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