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