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