2 * "$Id: dirsvc.c 11193 2013-07-26 03:12:37Z msweet $"
4 * Directory services routines for the CUPS scheduler.
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
17 * cupsdDeregisterPrinter() - Stop sending broadcast information for a local
18 * printer and remove any pending references to
20 * cupsdRegisterPrinter() - Start sending broadcast information for a
21 * printer or update the broadcast contents.
22 * cupsdStartBrowsing() - Start sending and receiving broadcast
24 * cupsdStopBrowsing() - Stop sending and receiving broadcast
26 * cupsdUpdateDNSSDName() - Update the computer name we use for
28 * dnssdAddAlias() - Add a DNS-SD alias name.
29 * dnssdBuildTxtRecord() - Build a TXT record from printer info.
30 * dnssdDeregisterInstance() - Deregister a DNS-SD service instance.
31 * dnssdDeregisterPrinter() - Deregister all services for a printer.
32 * dnssdErrorString() - Return an error string for an error code.
33 * dnssdRegisterCallback() - Free a TXT record.
34 * dnssdRegisterCallback() - DNSServiceRegister callback.
35 * dnssdRegisterInstance() - Register an instance of a printer service.
36 * dnssdRegisterPrinter() - Start sending broadcast information for a
37 * printer or update the broadcast contents.
38 * dnssdStop() - Stop all DNS-SD registrations.
39 * dnssdUpdate() - Handle DNS-SD queries.
40 * get_auth_info_required() - Get the auth-info-required value to advertise.
41 * get_hostconfig() - Get an /etc/hostconfig service setting.
42 * update_lpd() - Update the LPD configuration as needed.
43 * update_smb() - Update the SMB configuration as needed.
47 * Include necessary headers...
53 #if defined(HAVE_DNSSD) && defined(__APPLE__)
55 # include <CoreFoundation/CoreFoundation.h>
56 # include <SystemConfiguration/SystemConfiguration.h>
57 #endif /* HAVE_DNSSD && __APPLE__ */
64 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
65 static char *get_auth_info_required(cupsd_printer_t
*p
,
66 char *buffer
, size_t bufsize
);
67 #endif /* HAVE_DNSSD || HAVE_AVAHI */
69 static int get_hostconfig(const char *name
);
70 #endif /* __APPLE__ */
71 static void update_lpd(int onoff
);
72 static void update_smb(int onoff
);
75 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
77 static void dnssdAddAlias(const void *key
, const void *value
,
79 # endif /* __APPLE__ */
80 static cupsd_txt_t
dnssdBuildTxtRecord(cupsd_printer_t
*p
, int for_lpd
);
81 static void dnssdDeregisterInstance(cupsd_srv_t
*srv
);
82 static void dnssdDeregisterPrinter(cupsd_printer_t
*p
,
84 static const char *dnssdErrorString(int error
);
85 static void dnssdFreeTxtRecord(cupsd_txt_t
*txt
);
87 static void dnssdRegisterCallback(DNSServiceRef sdRef
,
88 DNSServiceFlags flags
,
89 DNSServiceErrorType errorCode
,
95 static void dnssdRegisterCallback(AvahiEntryGroup
*p
,
96 AvahiEntryGroupState state
,
98 # endif /* HAVE_DNSSD */
99 static int dnssdRegisterInstance(cupsd_srv_t
*srv
,
101 char *name
, const char *type
,
102 const char *subtypes
, int port
,
103 cupsd_txt_t
*txt
, int commit
);
104 static void dnssdRegisterPrinter(cupsd_printer_t
*p
);
105 static void dnssdStop(void);
107 static void dnssdUpdate(void);
108 # endif /* HAVE_DNSSD */
109 #endif /* HAVE_DNSSD || HAVE_AVAHI */
113 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
114 * local printer and remove any pending
115 * references to remote printers.
119 cupsdDeregisterPrinter(
120 cupsd_printer_t
*p
, /* I - Printer to register */
121 int removeit
) /* I - Printer being permanently removed */
124 * Only deregister if browsing is enabled and it's a local printer...
127 cupsdLogMessage(CUPSD_LOG_DEBUG
,
128 "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p
, p
->name
,
131 if (!Browsing
|| !p
->shared
||
132 (p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_SCANNER
)))
136 * Announce the deletion...
139 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
140 if (removeit
&& (BrowseLocalProtocols
& BROWSE_DNSSD
) && DNSSDMaster
)
141 dnssdDeregisterPrinter(p
, 1);
142 #endif /* HAVE_DNSSD || HAVE_AVAHI */
147 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
148 * printer or update the broadcast contents.
152 cupsdRegisterPrinter(cupsd_printer_t
*p
)/* I - Printer */
154 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdRegisterPrinter(p=%p(%s))", p
,
157 if (!Browsing
|| !BrowseLocalProtocols
||
158 (p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_SCANNER
)))
161 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
162 if ((BrowseLocalProtocols
& BROWSE_DNSSD
) && DNSSDMaster
)
163 dnssdRegisterPrinter(p
);
164 #endif /* HAVE_DNSSD || HAVE_AVAHI */
169 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
173 cupsdStartBrowsing(void)
175 cupsd_printer_t
*p
; /* Current printer */
178 if (!Browsing
|| !BrowseLocalProtocols
)
181 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
182 if (BrowseLocalProtocols
& BROWSE_DNSSD
)
184 cupsd_listener_t
*lis
; /* Current listening socket */
186 DNSServiceErrorType error
; /* Error from service creation */
189 * First create a "master" connection for all registrations...
192 if ((error
= DNSServiceCreateConnection(&DNSSDMaster
))
193 != kDNSServiceErr_NoError
)
195 cupsdLogMessage(CUPSD_LOG_ERROR
,
196 "Unable to create master DNS-SD reference: %d", error
);
198 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
199 cupsdEndProcess(getpid(), 0);
204 * Add the master connection to the select list...
207 int fd
= DNSServiceRefSockFD(DNSSDMaster
);
209 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
211 cupsdAddSelect(fd
, (cupsd_selfunc_t
)dnssdUpdate
, NULL
, NULL
);
214 # else /* HAVE_AVAHI */
215 if ((DNSSDMaster
= avahi_threaded_poll_new()) == NULL
)
217 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to create DNS-SD thread.");
219 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
220 cupsdEndProcess(getpid(), 0);
224 int error
; /* Error code, if any */
226 DNSSDClient
= avahi_client_new(avahi_threaded_poll_get(DNSSDMaster
), 0,
229 if (DNSSDClient
== NULL
)
231 cupsdLogMessage(CUPSD_LOG_ERROR
,
232 "Unable to communicate with avahi-daemon: %s",
233 dnssdErrorString(error
));
235 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
236 cupsdEndProcess(getpid(), 0);
238 avahi_threaded_poll_free(DNSSDMaster
);
242 avahi_threaded_poll_start(DNSSDMaster
);
244 # endif /* HAVE_DNSSD */
247 * Then get the port we use for registrations. If we are not listening
248 * on any non-local ports, there is no sense sharing local printers via
254 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
256 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
258 if (httpAddrLocalhost(&(lis
->address
)))
261 DNSSDPort
= httpAddrPort(&(lis
->address
));
266 * Set the computer name and register the web interface...
269 cupsdUpdateDNSSDName();
271 #endif /* HAVE_DNSSD || HAVE_AVAHI */
274 * Enable LPD and SMB printer sharing as needed through external programs...
277 if (BrowseLocalProtocols
& BROWSE_LPD
)
280 if (BrowseLocalProtocols
& BROWSE_SMB
)
284 * Register the individual printers
287 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
289 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
290 if (!(p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_SCANNER
)))
291 cupsdRegisterPrinter(p
);
296 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
300 cupsdStopBrowsing(void)
302 cupsd_printer_t
*p
; /* Current printer */
305 if (!Browsing
|| !BrowseLocalProtocols
)
309 * De-register the individual printers
312 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
314 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
315 if (!(p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_SCANNER
)))
316 cupsdDeregisterPrinter(p
, 1);
319 * Shut down browsing sockets...
322 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
323 if ((BrowseLocalProtocols
& BROWSE_DNSSD
) && DNSSDMaster
)
325 #endif /* HAVE_DNSSD || HAVE_AVAHI */
328 * Disable LPD and SMB printer sharing as needed through external programs...
331 if (BrowseLocalProtocols
& BROWSE_LPD
)
334 if (BrowseLocalProtocols
& BROWSE_SMB
)
339 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
341 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
345 cupsdUpdateDNSSDName(void)
347 char webif
[1024]; /* Web interface share name */
349 SCDynamicStoreRef sc
; /* Context for dynamic store */
350 CFDictionaryRef btmm
; /* Back-to-My-Mac domains */
351 CFStringEncoding nameEncoding
; /* Encoding of computer name */
352 CFStringRef nameRef
; /* Host name CFString */
353 char nameBuffer
[1024]; /* C-string buffer */
354 # endif /* __APPLE__ */
358 * Only share the web interface and printers when non-local listening is
366 * Get the computer name as a c-string...
370 sc
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"), NULL
, NULL
);
375 * Get the computer name from the dynamic store...
378 cupsdClearString(&DNSSDComputerName
);
380 if ((nameRef
= SCDynamicStoreCopyComputerName(sc
, &nameEncoding
)) != NULL
)
382 if (CFStringGetCString(nameRef
, nameBuffer
, sizeof(nameBuffer
),
383 kCFStringEncodingUTF8
))
385 cupsdLogMessage(CUPSD_LOG_DEBUG
,
386 "Dynamic store computer name is \"%s\".", nameBuffer
);
387 cupsdSetString(&DNSSDComputerName
, nameBuffer
);
393 if (!DNSSDComputerName
)
396 * Use the ServerName instead...
399 cupsdLogMessage(CUPSD_LOG_DEBUG
,
400 "Using ServerName \"%s\" as computer name.", ServerName
);
401 cupsdSetString(&DNSSDComputerName
, ServerName
);
405 * Get the local hostname from the dynamic store...
408 cupsdClearString(&DNSSDHostName
);
410 if ((nameRef
= SCDynamicStoreCopyLocalHostName(sc
)) != NULL
)
412 if (CFStringGetCString(nameRef
, nameBuffer
, sizeof(nameBuffer
),
413 kCFStringEncodingUTF8
))
415 cupsdLogMessage(CUPSD_LOG_DEBUG
,
416 "Dynamic store host name is \"%s\".", nameBuffer
);
417 cupsdSetString(&DNSSDHostName
, nameBuffer
);
426 * Use the ServerName instead...
429 cupsdLogMessage(CUPSD_LOG_DEBUG
,
430 "Using ServerName \"%s\" as host name.", ServerName
);
431 cupsdSetString(&DNSSDHostName
, ServerName
);
435 * Get any Back-to-My-Mac domains and add them as aliases...
438 cupsdFreeAliases(DNSSDAlias
);
441 btmm
= SCDynamicStoreCopyValue(sc
, CFSTR("Setup:/Network/BackToMyMac"));
442 if (btmm
&& CFGetTypeID(btmm
) == CFDictionaryGetTypeID())
444 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%d Back to My Mac aliases to add.",
445 (int)CFDictionaryGetCount(btmm
));
446 CFDictionaryApplyFunction(btmm
, dnssdAddAlias
, NULL
);
449 cupsdLogMessage(CUPSD_LOG_ERROR
,
450 "Bad Back to My Mac data in dynamic store!");
452 cupsdLogMessage(CUPSD_LOG_DEBUG
, "No Back to My Mac aliases to add.");
460 # endif /* __APPLE__ */
464 const char *host_name
= avahi_client_get_host_name(DNSSDClient
);
465 const char *host_fqdn
= avahi_client_get_host_name_fqdn(DNSSDClient
);
467 cupsdSetString(&DNSSDComputerName
, host_name
? host_name
: ServerName
);
470 cupsdSetString(&DNSSDHostName
, host_fqdn
);
471 else if (strchr(ServerName
, '.'))
472 cupsdSetString(&DNSSDHostName
, ServerName
);
474 cupsdSetStringf(&DNSSDHostName
, "%s.local", ServerName
);
477 # endif /* HAVE_AVAHI */
479 cupsdSetString(&DNSSDComputerName
, ServerName
);
481 if (strchr(ServerName
, '.'))
482 cupsdSetString(&DNSSDHostName
, ServerName
);
484 cupsdSetStringf(&DNSSDHostName
, "%s.local", ServerName
);
488 * Then (re)register the web interface if enabled...
493 if (DNSSDComputerName
)
494 snprintf(webif
, sizeof(webif
), "CUPS @ %s", DNSSDComputerName
);
496 strlcpy(webif
, "CUPS", sizeof(webif
));
498 dnssdDeregisterInstance(&WebIFSrv
);
499 dnssdRegisterInstance(&WebIFSrv
, NULL
, webif
, "_http._tcp", "_printer",
507 * 'dnssdAddAlias()' - Add a DNS-SD alias name.
511 dnssdAddAlias(const void *key
, /* I - Key */
512 const void *value
, /* I - Value (domain) */
513 void *context
) /* I - Unused */
515 char valueStr
[1024], /* Domain string */
516 hostname
[1024], /* Complete hostname */
517 *hostptr
; /* Pointer into hostname */
523 if (CFGetTypeID((CFStringRef
)value
) == CFStringGetTypeID() &&
524 CFStringGetCString((CFStringRef
)value
, valueStr
, sizeof(valueStr
),
525 kCFStringEncodingUTF8
))
527 snprintf(hostname
, sizeof(hostname
), "%s.%s", DNSSDHostName
, valueStr
);
528 hostptr
= hostname
+ strlen(hostname
) - 1;
530 *hostptr
= '\0'; /* Strip trailing dot */
533 DNSSDAlias
= cupsArrayNew(NULL
, NULL
);
535 cupsdAddAlias(DNSSDAlias
, hostname
);
536 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added Back to My Mac ServerAlias %s",
540 cupsdLogMessage(CUPSD_LOG_ERROR
,
541 "Bad Back to My Mac domain in dynamic store!");
543 # endif /* __APPLE__ */
547 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
550 static cupsd_txt_t
/* O - TXT record */
552 cupsd_printer_t
*p
, /* I - Printer information */
553 int for_lpd
) /* I - 1 = LPD, 0 = IPP */
555 int i
, /* Looping var */
556 count
; /* Count of key/value pairs */
557 char admin_hostname
[256], /* .local hostname for admin page */
558 adminurl_str
[256], /* URL for the admin page */
559 type_str
[32], /* Type to string buffer */
560 state_str
[32], /* State to string buffer */
561 rp_str
[1024], /* Queue name string buffer */
562 air_str
[1024], /* auth-info-required string buffer */
563 *keyvalue
[32][2]; /* Table of key/value pairs */
564 cupsd_txt_t txt
; /* TXT record */
568 * Load up the key value pairs...
573 if (!for_lpd
|| (BrowseLocalProtocols
& BROWSE_LPD
))
575 keyvalue
[count
][0] = "txtvers";
576 keyvalue
[count
++][1] = "1";
578 keyvalue
[count
][0] = "qtotal";
579 keyvalue
[count
++][1] = "1";
581 keyvalue
[count
][0] = "rp";
582 keyvalue
[count
++][1] = rp_str
;
584 strlcpy(rp_str
, p
->name
, sizeof(rp_str
));
586 snprintf(rp_str
, sizeof(rp_str
), "%s/%s",
587 (p
->type
& CUPS_PRINTER_CLASS
) ? "classes" : "printers",
590 keyvalue
[count
][0] = "ty";
591 keyvalue
[count
++][1] = p
->make_model
? p
->make_model
: "Unknown";
593 if (strstr(DNSSDHostName
, ".local"))
594 strlcpy(admin_hostname
, DNSSDHostName
, sizeof(admin_hostname
));
596 snprintf(admin_hostname
, sizeof(admin_hostname
), "%s.local.",
598 httpAssembleURIf(HTTP_URI_CODING_ALL
, adminurl_str
, sizeof(adminurl_str
),
603 # endif /* HAVE_SSL */
604 NULL
, admin_hostname
, DNSSDPort
, "/%s/%s",
605 (p
->type
& CUPS_PRINTER_CLASS
) ? "classes" : "printers",
607 keyvalue
[count
][0] = "adminurl";
608 keyvalue
[count
++][1] = adminurl_str
;
612 keyvalue
[count
][0] = "note";
613 keyvalue
[count
++][1] = p
->location
;
616 keyvalue
[count
][0] = "priority";
617 keyvalue
[count
++][1] = for_lpd
? "100" : "0";
619 keyvalue
[count
][0] = "product";
620 keyvalue
[count
++][1] = p
->pc
&& p
->pc
->product
? p
->pc
->product
: "Unknown";
622 keyvalue
[count
][0] = "pdl";
623 keyvalue
[count
++][1] = p
->pdl
? p
->pdl
: "application/postscript";
625 if (get_auth_info_required(p
, air_str
, sizeof(air_str
)))
627 keyvalue
[count
][0] = "air";
628 keyvalue
[count
++][1] = air_str
;
631 keyvalue
[count
][0] = "UUID";
632 keyvalue
[count
++][1] = p
->uuid
+ 9;
635 keyvalue
[count
][0] = "TLS";
636 keyvalue
[count
++][1] = "1.2";
637 #endif /* HAVE_SSL */
639 if (p
->type
& CUPS_PRINTER_FAX
)
641 keyvalue
[count
][0] = "Fax";
642 keyvalue
[count
++][1] = "T";
643 keyvalue
[count
][0] = "rfo";
644 keyvalue
[count
++][1] = rp_str
;
647 if (p
->type
& CUPS_PRINTER_COLOR
)
649 keyvalue
[count
][0] = "Color";
650 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_COLOR
) ? "T" : "F";
653 if (p
->type
& CUPS_PRINTER_DUPLEX
)
655 keyvalue
[count
][0] = "Duplex";
656 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_DUPLEX
) ? "T" : "F";
659 if (p
->type
& CUPS_PRINTER_STAPLE
)
661 keyvalue
[count
][0] = "Staple";
662 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_STAPLE
) ? "T" : "F";
665 if (p
->type
& CUPS_PRINTER_COPIES
)
667 keyvalue
[count
][0] = "Copies";
668 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_COPIES
) ? "T" : "F";
671 if (p
->type
& CUPS_PRINTER_COLLATE
)
673 keyvalue
[count
][0] = "Collate";
674 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_COLLATE
) ? "T" : "F";
677 if (p
->type
& CUPS_PRINTER_PUNCH
)
679 keyvalue
[count
][0] = "Punch";
680 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_PUNCH
) ? "T" : "F";
683 if (p
->type
& CUPS_PRINTER_BIND
)
685 keyvalue
[count
][0] = "Bind";
686 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_BIND
) ? "T" : "F";
689 if (p
->type
& CUPS_PRINTER_SORT
)
691 keyvalue
[count
][0] = "Sort";
692 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_SORT
) ? "T" : "F";
695 if (p
->type
& CUPS_PRINTER_MFP
)
697 keyvalue
[count
][0] = "Scan";
698 keyvalue
[count
++][1] = (p
->type
& CUPS_PRINTER_MFP
) ? "T" : "F";
701 snprintf(type_str
, sizeof(type_str
), "0x%X", p
->type
| CUPS_PRINTER_REMOTE
);
702 snprintf(state_str
, sizeof(state_str
), "%d", p
->state
);
704 keyvalue
[count
][0] = "printer-state";
705 keyvalue
[count
++][1] = state_str
;
707 keyvalue
[count
][0] = "printer-type";
708 keyvalue
[count
++][1] = type_str
;
712 * Then pack them into a proper txt record...
716 TXTRecordCreate(&txt
, 0, NULL
);
718 for (i
= 0; i
< count
; i
++)
720 size_t len
= strlen(keyvalue
[i
][1]);
723 TXTRecordSetValue(&txt
, keyvalue
[i
][0], (uint8_t)len
, keyvalue
[i
][1]);
727 for (i
= 0, txt
= NULL
; i
< count
; i
++)
728 txt
= avahi_string_list_add_printf(txt
, "%s=%s", keyvalue
[i
][0],
730 # endif /* HAVE_DNSSD */
737 * 'dnssdDeregisterInstance()' - Deregister a DNS-SD service instance.
741 dnssdDeregisterInstance(
742 cupsd_srv_t
*srv
) /* I - Service */
748 DNSServiceRefDeallocate(*srv
);
750 # else /* HAVE_AVAHI */
751 avahi_threaded_poll_lock(DNSSDMaster
);
752 avahi_entry_group_free(*srv
);
753 avahi_threaded_poll_unlock(DNSSDMaster
);
754 # endif /* HAVE_DNSSD */
761 * 'dnssdDeregisterPrinter()' - Deregister all services for a printer.
765 dnssdDeregisterPrinter(
766 cupsd_printer_t
*p
, /* I - Printer */
767 int clear_name
) /* I - Clear the name? */
770 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
771 "dnssdDeregisterPrinter(p=%p(%s), clear_name=%d)", p
, p
->name
,
776 dnssdDeregisterInstance(&p
->ipp_srv
);
780 dnssdDeregisterInstance(&p
->ipps_srv
);
781 # endif /* HAVE_SSL */
782 dnssdDeregisterInstance(&p
->printer_srv
);
783 # endif /* HAVE_DNSSD */
787 * Remove the printer from the array of DNS-SD printers but keep the
791 cupsArrayRemove(DNSSDPrinters
, p
);
794 * Optionally clear the service name...
798 cupsdClearString(&p
->reg_name
);
803 * 'dnssdErrorString()' - Return an error string for an error code.
806 static const char * /* O - Error message */
807 dnssdErrorString(int error
) /* I - Error number */
812 case kDNSServiceErr_NoError
:
816 case kDNSServiceErr_Unknown
:
817 return ("Unknown error.");
819 case kDNSServiceErr_NoSuchName
:
820 return ("Service not found.");
822 case kDNSServiceErr_NoMemory
:
823 return ("Out of memory.");
825 case kDNSServiceErr_BadParam
:
826 return ("Bad parameter.");
828 case kDNSServiceErr_BadReference
:
829 return ("Bad service reference.");
831 case kDNSServiceErr_BadState
:
832 return ("Bad state.");
834 case kDNSServiceErr_BadFlags
:
835 return ("Bad flags.");
837 case kDNSServiceErr_Unsupported
:
838 return ("Unsupported.");
840 case kDNSServiceErr_NotInitialized
:
841 return ("Not initialized.");
843 case kDNSServiceErr_AlreadyRegistered
:
844 return ("Already registered.");
846 case kDNSServiceErr_NameConflict
:
847 return ("Name conflict.");
849 case kDNSServiceErr_Invalid
:
850 return ("Invalid name.");
852 case kDNSServiceErr_Firewall
:
853 return ("Firewall prevents registration.");
855 case kDNSServiceErr_Incompatible
:
856 return ("Client library incompatible.");
858 case kDNSServiceErr_BadInterfaceIndex
:
859 return ("Bad interface index.");
861 case kDNSServiceErr_Refused
:
862 return ("Server prevents registration.");
864 case kDNSServiceErr_NoSuchRecord
:
865 return ("Record not found.");
867 case kDNSServiceErr_NoAuth
:
868 return ("Authentication required.");
870 case kDNSServiceErr_NoSuchKey
:
871 return ("Encryption key not found.");
873 case kDNSServiceErr_NATTraversal
:
874 return ("Unable to traverse NAT boundary.");
876 case kDNSServiceErr_DoubleNAT
:
877 return ("Unable to traverse double-NAT boundary.");
879 case kDNSServiceErr_BadTime
:
880 return ("Bad system time.");
882 case kDNSServiceErr_BadSig
:
883 return ("Bad signature.");
885 case kDNSServiceErr_BadKey
:
886 return ("Bad encryption key.");
888 case kDNSServiceErr_Transient
:
889 return ("Transient error occurred - please try again.");
891 case kDNSServiceErr_ServiceNotRunning
:
892 return ("Server not running.");
894 case kDNSServiceErr_NATPortMappingUnsupported
:
895 return ("NAT doesn't support NAT-PMP or UPnP.");
897 case kDNSServiceErr_NATPortMappingDisabled
:
898 return ("NAT supports NAT-PNP or UPnP but it is disabled.");
900 case kDNSServiceErr_NoRouter
:
901 return ("No Internet/default router configured.");
903 case kDNSServiceErr_PollingMode
:
904 return ("Service polling mode error.");
906 case kDNSServiceErr_Timeout
:
907 return ("Service timeout.");
910 # else /* HAVE_AVAHI */
911 return (avahi_strerror(error
));
912 # endif /* HAVE_DNSSD */
917 * 'dnssdRegisterCallback()' - Free a TXT record.
921 dnssdFreeTxtRecord(cupsd_txt_t
*txt
) /* I - TXT record */
924 TXTRecordDeallocate(txt
);
926 # else /* HAVE_AVAHI */
927 avahi_string_list_free(*txt
);
929 # endif /* HAVE_DNSSD */
934 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
939 dnssdRegisterCallback(
940 DNSServiceRef sdRef
, /* I - DNS Service reference */
941 DNSServiceFlags flags
, /* I - Reserved for future use */
942 DNSServiceErrorType errorCode
, /* I - Error code */
943 const char *name
, /* I - Service name */
944 const char *regtype
, /* I - Service type */
945 const char *domain
, /* I - Domain. ".local" for now */
946 void *context
) /* I - Printer */
948 cupsd_printer_t
*p
= (cupsd_printer_t
*)context
;
949 /* Current printer */
956 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "dnssdRegisterCallback(%s, %s) for %s (%s)",
957 name
, regtype
, p
? p
->name
: "Web Interface",
958 p
? (p
->reg_name
? p
->reg_name
: "(null)") : "NA");
962 cupsdLogMessage(CUPSD_LOG_ERROR
,
963 "DNSServiceRegister failed with error %d", (int)errorCode
);
966 else if (p
&& (!p
->reg_name
|| _cups_strcasecmp(name
, p
->reg_name
)))
968 cupsdLogMessage(CUPSD_LOG_INFO
, "Using service name \"%s\" for \"%s\"",
971 cupsArrayRemove(DNSSDPrinters
, p
);
972 cupsdSetString(&p
->reg_name
, name
);
973 cupsArrayAdd(DNSSDPrinters
, p
);
975 LastEvent
|= CUPSD_EVENT_PRINTER_MODIFIED
;
979 # else /* HAVE_AVAHI */
981 dnssdRegisterCallback(
982 AvahiEntryGroup
*srv
, /* I - Service */
983 AvahiEntryGroupState state
, /* I - Registration state */
984 void *context
) /* I - Printer */
986 cupsd_printer_t
*p
= (cupsd_printer_t
*)context
;
987 /* Current printer */
989 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
990 "dnssdRegisterCallback(srv=%p, state=%d, context=%p) "
991 "for %s (%s)", srv
, state
, context
,
992 p
? p
->name
: "Web Interface",
993 p
? (p
->reg_name
? p
->reg_name
: "(null)") : "NA");
995 /* TODO: Handle collisions with avahi_alternate_service_name(p->reg_name)? */
997 # endif /* HAVE_DNSSD */
1001 * 'dnssdRegisterInstance()' - Register an instance of a printer service.
1004 static int /* O - 1 on success, 0 on failure */
1005 dnssdRegisterInstance(
1006 cupsd_srv_t
*srv
, /* O - Service */
1007 cupsd_printer_t
*p
, /* I - Printer */
1008 char *name
, /* I - DNS-SD service name */
1009 const char *type
, /* I - DNS-SD service type */
1010 const char *subtypes
, /* I - Subtypes to register or NULL */
1011 int port
, /* I - Port number or 0 */
1012 cupsd_txt_t
*txt
, /* I - TXT record */
1013 int commit
) /* I - Commit registration? */
1015 char temp
[256], /* Temporary string */
1016 *ptr
; /* Pointer into string */
1017 int error
; /* Any error */
1020 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1021 "Registering \"%s\" with DNS-SD type \"%s\".", name
, type
);
1026 * Assign the correct pointer for "srv"...
1030 if (!strcmp(type
, "_printer._tcp"))
1031 srv
= &p
->printer_srv
; /* Target LPD service */
1033 else if (!strcmp(type
, "_ipps._tcp"))
1034 srv
= &p
->ipps_srv
; /* Target IPPS service */
1035 # endif /* HAVE_SSL */
1037 srv
= &p
->ipp_srv
; /* Target IPP service */
1039 # else /* HAVE_AVAHI */
1040 srv
= &p
->ipp_srv
; /* Target service group */
1041 # endif /* HAVE_DNSSD */
1047 # else /* HAVE_AVAHI */
1048 avahi_threaded_poll_lock(DNSSDMaster
);
1051 *srv
= avahi_entry_group_new(DNSSDClient
, dnssdRegisterCallback
, NULL
);
1054 avahi_threaded_poll_unlock(DNSSDMaster
);
1056 cupsdLogMessage(CUPSD_LOG_WARN
, "DNS-SD registration of \"%s\" failed: %s",
1057 name
, dnssdErrorString(avahi_client_errno(DNSSDClient
)));
1060 # endif /* HAVE_DNSSD */
1063 * Make sure the name is <= 63 octets, and when we truncate be sure to
1064 * properly truncate any UTF-8 characters...
1067 ptr
= name
+ strlen(name
);
1068 while ((ptr
- name
) > 63)
1074 while (ptr
> name
&& (*ptr
& 0xc0) == 0x80);
1081 * Register the service...
1086 snprintf(temp
, sizeof(temp
), "%s,%s", type
, subtypes
);
1088 strlcpy(temp
, type
, sizeof(temp
));
1091 error
= DNSServiceRegister(srv
, kDNSServiceFlagsShareConnection
,
1092 0, name
, temp
, NULL
, NULL
, htons(port
),
1093 txt
? TXTRecordGetLength(txt
) : 0,
1094 txt
? TXTRecordGetBytesPtr(txt
) : NULL
,
1095 dnssdRegisterCallback
, p
);
1097 # else /* HAVE_AVAHI */
1100 AvahiStringList
*temptxt
;
1101 for (temptxt
= *txt
; temptxt
; temptxt
= temptxt
->next
)
1102 cupsdLogMessage(CUPSD_LOG_DEBUG
, "DNS_SD \"%s\" %s", name
, temptxt
->text
);
1105 error
= avahi_entry_group_add_service_strlst(*srv
, AVAHI_IF_UNSPEC
,
1106 AVAHI_PROTO_UNSPEC
, 0, name
,
1107 type
, NULL
, NULL
, port
,
1110 cupsdLogMessage(CUPSD_LOG_DEBUG
, "DNS-SD service add for \"%s\" failed.",
1113 if (!error
&& subtypes
)
1116 * Register all of the subtypes...
1119 char *start
, /* Start of subtype */
1120 subtype
[256]; /* Subtype string */
1122 strlcpy(temp
, subtypes
, sizeof(temp
));
1124 for (start
= temp
; *start
; start
= ptr
)
1127 * Skip leading whitespace...
1130 while (*start
&& isspace(*start
& 255))
1134 * Grab everything up to the next comma or the end of the string...
1137 for (ptr
= start
; *ptr
&& *ptr
!= ','; ptr
++);
1146 * Register the subtype...
1149 snprintf(subtype
, sizeof(subtype
), "%s._sub.%s", start
, type
);
1151 error
= avahi_entry_group_add_service_subtype(*srv
, AVAHI_IF_UNSPEC
,
1152 AVAHI_PROTO_UNSPEC
, 0,
1153 name
, type
, NULL
, subtype
);
1156 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1157 "DNS-SD subtype %s registration for \"%s\" failed." ,
1164 if (!error
&& commit
)
1166 if ((error
= avahi_entry_group_commit(*srv
)) != 0)
1167 cupsdLogMessage(CUPSD_LOG_DEBUG
, "DNS-SD commit of \"%s\" failed.",
1171 avahi_threaded_poll_unlock(DNSSDMaster
);
1172 # endif /* HAVE_DNSSD */
1176 cupsdLogMessage(CUPSD_LOG_WARN
, "DNS-SD registration of \"%s\" failed: %s",
1177 name
, dnssdErrorString(error
));
1178 cupsdLogMessage(CUPSD_LOG_DEBUG
, "DNS-SD type: %s", type
);
1180 cupsdLogMessage(CUPSD_LOG_DEBUG
, "DNS-SD sub-types: %s", subtypes
);
1188 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
1189 * or update the broadcast contents.
1193 dnssdRegisterPrinter(cupsd_printer_t
*p
)/* I - Printer */
1195 char name
[256]; /* Service name */
1196 int printer_port
; /* LPD port number */
1197 int status
; /* Registration status */
1198 cupsd_txt_t ipp_txt
, /* IPP(S) TXT record */
1199 printer_txt
; /* LPD TXT record */
1201 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "dnssdRegisterPrinter(%s) %s", p
->name
,
1202 !p
->ipp_srv
? "new" : "update");
1205 * Remove the current registrations if we have them and then return if
1206 * per-printer sharing was just disabled...
1209 dnssdDeregisterPrinter(p
, 0);
1215 * Set the registered name as needed; the registered name takes the form of
1216 * "<printer-info> @ <computer name>"...
1221 if (p
->info
&& strlen(p
->info
) > 0)
1223 if (DNSSDComputerName
)
1224 snprintf(name
, sizeof(name
), "%s @ %s", p
->info
, DNSSDComputerName
);
1226 strlcpy(name
, p
->info
, sizeof(name
));
1228 else if (DNSSDComputerName
)
1229 snprintf(name
, sizeof(name
), "%s @ %s", p
->name
, DNSSDComputerName
);
1231 strlcpy(name
, p
->name
, sizeof(name
));
1234 strlcpy(name
, p
->reg_name
, sizeof(name
));
1237 * Register IPP and LPD...
1239 * We always must register the "_printer" service type in order to reserve
1240 * our name, but use port number 0 if we haven't actually configured cups-lpd
1241 * to share via LPD...
1244 ipp_txt
= dnssdBuildTxtRecord(p
, 0);
1245 printer_txt
= dnssdBuildTxtRecord(p
, 1);
1247 if (BrowseLocalProtocols
& BROWSE_LPD
)
1252 status
= dnssdRegisterInstance(NULL
, p
, name
, "_printer._tcp", NULL
,
1253 printer_port
, &printer_txt
, 0);
1257 dnssdRegisterInstance(NULL
, p
, name
, "_ipps._tcp", DNSSDSubTypes
,
1258 DNSSDPort
, &ipp_txt
, 0);
1259 # endif /* HAVE_SSL */
1264 * Use the "_fax-ipp" service type for fax queues, otherwise use "_ipp"...
1267 if (p
->type
& CUPS_PRINTER_FAX
)
1268 status
= dnssdRegisterInstance(NULL
, p
, name
, "_fax-ipp._tcp",
1269 DNSSDSubTypes
, DNSSDPort
, &ipp_txt
, 1);
1271 status
= dnssdRegisterInstance(NULL
, p
, name
, "_ipp._tcp", DNSSDSubTypes
,
1272 DNSSDPort
, &ipp_txt
, 1);
1275 dnssdFreeTxtRecord(&ipp_txt
);
1276 dnssdFreeTxtRecord(&printer_txt
);
1281 * Save the registered name and add the printer to the array of DNS-SD
1285 cupsdSetString(&p
->reg_name
, name
);
1286 cupsArrayAdd(DNSSDPrinters
, p
);
1291 * Registration failed for this printer...
1294 dnssdDeregisterInstance(&p
->ipp_srv
);
1298 dnssdDeregisterInstance(&p
->ipps_srv
);
1299 # endif /* HAVE_SSL */
1300 dnssdDeregisterInstance(&p
->printer_srv
);
1301 # endif /* HAVE_DNSSD */
1307 * 'dnssdStop()' - Stop all DNS-SD registrations.
1313 cupsd_printer_t
*p
; /* Current printer */
1317 * De-register the individual printers
1320 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1322 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1323 dnssdDeregisterPrinter(p
, 1);
1326 * Shutdown the rest of the service refs...
1329 dnssdDeregisterInstance(&WebIFSrv
);
1332 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDMaster
));
1334 DNSServiceRefDeallocate(DNSSDMaster
);
1337 # else /* HAVE_AVAHI */
1338 avahi_threaded_poll_stop(DNSSDMaster
);
1340 avahi_client_free(DNSSDClient
);
1343 avahi_threaded_poll_free(DNSSDMaster
);
1345 # endif /* HAVE_DNSSD */
1347 cupsArrayDelete(DNSSDPrinters
);
1348 DNSSDPrinters
= NULL
;
1356 * 'dnssdUpdate()' - Handle DNS-SD queries.
1362 DNSServiceErrorType sdErr
; /* Service discovery error */
1365 if ((sdErr
= DNSServiceProcessResult(DNSSDMaster
)) != kDNSServiceErr_NoError
)
1367 cupsdLogMessage(CUPSD_LOG_ERROR
,
1368 "DNS Service Discovery registration error %d!",
1373 # endif /* HAVE_DNSSD */
1377 * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
1380 static char * /* O - String or NULL if none */
1381 get_auth_info_required(
1382 cupsd_printer_t
*p
, /* I - Printer */
1383 char *buffer
, /* I - Value buffer */
1384 size_t bufsize
) /* I - Size of value buffer */
1386 cupsd_location_t
*auth
; /* Pointer to authentication element */
1387 char resource
[1024]; /* Printer/class resource path */
1391 * If auth-info-required is set for this printer, return that...
1394 if (p
->num_auth_info_required
> 0 && strcmp(p
->auth_info_required
[0], "none"))
1396 int i
; /* Looping var */
1397 char *bufptr
; /* Pointer into buffer */
1399 for (i
= 0, bufptr
= buffer
; i
< p
->num_auth_info_required
; i
++)
1401 if (bufptr
>= (buffer
+ bufsize
- 2))
1407 strlcpy(bufptr
, p
->auth_info_required
[i
], bufsize
- (bufptr
- buffer
));
1408 bufptr
+= strlen(bufptr
);
1415 * Figure out the authentication data requirements to advertise...
1418 if (p
->type
& CUPS_PRINTER_CLASS
)
1419 snprintf(resource
, sizeof(resource
), "/classes/%s", p
->name
);
1421 snprintf(resource
, sizeof(resource
), "/printers/%s", p
->name
);
1423 if ((auth
= cupsdFindBest(resource
, HTTP_POST
)) == NULL
||
1424 auth
->type
== CUPSD_AUTH_NONE
)
1425 auth
= cupsdFindPolicyOp(p
->op_policy_ptr
, IPP_PRINT_JOB
);
1429 int auth_type
; /* Authentication type */
1431 if ((auth_type
= auth
->type
) == CUPSD_AUTH_DEFAULT
)
1432 auth_type
= cupsdDefaultAuthType();
1436 case CUPSD_AUTH_NONE
:
1439 case CUPSD_AUTH_NEGOTIATE
:
1440 strlcpy(buffer
, "negotiate", bufsize
);
1444 strlcpy(buffer
, "username,password", bufsize
);
1453 #endif /* HAVE_DNSSD || HAVE_AVAHI */
1458 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
1461 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
1462 get_hostconfig(const char *name
) /* I - Name of service */
1464 cups_file_t
*fp
; /* Hostconfig file */
1465 char line
[1024], /* Line from file */
1466 *ptr
; /* Pointer to value */
1467 int state
= 1; /* State of service */
1471 * Try opening the /etc/hostconfig file; if we can't open it, assume that
1472 * the service is enabled/auto.
1475 if ((fp
= cupsFileOpen("/etc/hostconfig", "r")) != NULL
)
1478 * Read lines from the file until we find the service...
1481 while (cupsFileGets(fp
, line
, sizeof(line
)))
1483 if (line
[0] == '#' || (ptr
= strchr(line
, '=')) == NULL
)
1488 if (!_cups_strcasecmp(line
, name
))
1491 * Found the service, see if it is set to "-NO-"...
1494 if (!_cups_strncasecmp(ptr
, "-NO-", 4))
1505 #endif /* __APPLE__ */
1509 * 'update_lpd()' - Update the LPD configuration as needed.
1513 update_lpd(int onoff
) /* - 1 = turn on, 0 = turn off */
1520 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
1521 * setting for backwards-compatibility.
1524 if (onoff
&& !get_hostconfig("CUPS_LPD"))
1526 #endif /* __APPLE__ */
1528 if (!strncmp(LPDConfigFile
, "xinetd:///", 10))
1531 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
1534 char newfile
[1024]; /* New cups-lpd.N file */
1535 cups_file_t
*ofp
, /* Original file pointer */
1536 *nfp
; /* New file pointer */
1537 char line
[1024]; /* Line from file */
1540 snprintf(newfile
, sizeof(newfile
), "%s.N", LPDConfigFile
+ 9);
1542 if ((ofp
= cupsFileOpen(LPDConfigFile
+ 9, "r")) == NULL
)
1544 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open \"%s\" - %s",
1545 LPDConfigFile
+ 9, strerror(errno
));
1549 if ((nfp
= cupsFileOpen(newfile
, "w")) == NULL
)
1551 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to create \"%s\" - %s",
1552 newfile
, strerror(errno
));
1558 * Copy all of the lines from the cups-lpd file...
1561 while (cupsFileGets(ofp
, line
, sizeof(line
)))
1565 cupsFilePrintf(nfp
, "%s\n", line
);
1566 snprintf(line
, sizeof(line
), "\tdisable = %s",
1567 onoff
? "no" : "yes");
1569 else if (!strstr(line
, "disable ="))
1570 cupsFilePrintf(nfp
, "%s\n", line
);
1575 rename(newfile
, LPDConfigFile
+ 9);
1578 else if (!strncmp(LPDConfigFile
, "launchd:///", 11))
1581 * Enable/disable LPD via the launchctl command...
1584 char *argv
[5], /* Arguments for command */
1585 *envp
[MAX_ENV
]; /* Environment for command */
1586 int pid
; /* Process ID */
1589 cupsdLoadEnv(envp
, (int)(sizeof(envp
) / sizeof(envp
[0])));
1590 argv
[0] = (char *)"launchctl";
1591 argv
[1] = (char *)(onoff
? "load" : "unload");
1592 argv
[2] = (char *)"-w";
1593 argv
[3] = LPDConfigFile
+ 10;
1596 cupsdStartProcess("/bin/launchctl", argv
, envp
, -1, -1, -1, -1, -1, 1,
1599 #endif /* __APPLE__ */
1601 cupsdLogMessage(CUPSD_LOG_INFO
, "Unknown LPDConfigFile scheme!");
1606 * 'update_smb()' - Update the SMB configuration as needed.
1610 update_smb(int onoff
) /* I - 1 = turn on, 0 = turn off */
1615 if (!strncmp(SMBConfigFile
, "samba:///", 9))
1618 * Enable/disable SMB via the specified smb.conf config file...
1621 char newfile
[1024]; /* New smb.conf.N file */
1622 cups_file_t
*ofp
, /* Original file pointer */
1623 *nfp
; /* New file pointer */
1624 char line
[1024]; /* Line from file */
1625 int in_printers
; /* In [printers] section? */
1628 snprintf(newfile
, sizeof(newfile
), "%s.N", SMBConfigFile
+ 8);
1630 if ((ofp
= cupsFileOpen(SMBConfigFile
+ 8, "r")) == NULL
)
1632 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open \"%s\" - %s",
1633 SMBConfigFile
+ 8, strerror(errno
));
1637 if ((nfp
= cupsFileOpen(newfile
, "w")) == NULL
)
1639 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to create \"%s\" - %s",
1640 newfile
, strerror(errno
));
1646 * Copy all of the lines from the smb.conf file...
1651 while (cupsFileGets(ofp
, line
, sizeof(line
)))
1653 if (in_printers
&& strstr(line
, "printable ="))
1654 snprintf(line
, sizeof(line
), " printable = %s",
1655 onoff
? "yes" : "no");
1657 cupsFilePrintf(nfp
, "%s\n", line
);
1660 in_printers
= !strcmp(line
, "[printers]");
1665 rename(newfile
, SMBConfigFile
+ 8);
1668 cupsdLogMessage(CUPSD_LOG_INFO
, "Unknown SMBConfigFile scheme!");
1673 * End of "$Id: dirsvc.c 11193 2013-07-26 03:12:37Z msweet $".