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