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