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