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