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