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