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