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