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