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