]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
b19ccc9e | 2 | * "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $" |
ef416fc2 | 3 | * |
10d09e33 | 4 | * Directory services routines for the CUPS scheduler. |
ef416fc2 | 5 | * |
e60ec91f | 6 | * Copyright 2007-2011 by Apple Inc. |
b86bc4cf | 7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 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/". | |
ef416fc2 | 14 | * |
15 | * Contents: | |
16 | * | |
a2326b5b MS |
17 | * cupsdDeregisterPrinter() - Stop sending broadcast information for a local |
18 | * printer and remove any pending references to | |
19 | * remote printers. | |
20 | * cupsdRegisterPrinter() - Start sending broadcast information for a | |
21 | * printer or update the broadcast contents. | |
22 | * cupsdStartBrowsing() - Start sending and receiving broadcast | |
23 | * information. | |
24 | * cupsdStopBrowsing() - Stop sending and receiving broadcast | |
25 | * information. | |
26 | * cupsdUpdateDNSSDName() - Update the computer name we use for browsing... | |
27 | * dnssdAddAlias() - Add a DNS-SD alias name. | |
28 | * dnssdBuildTxtRecord() - Build a TXT record from printer info. | |
29 | * dnssdDeregisterPrinter() - Stop sending broadcast information for a | |
30 | * printer. | |
31 | * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT | |
32 | * record format. | |
33 | * dnssdRegisterCallback() - DNSServiceRegister callback. | |
34 | * dnssdRegisterPrinter() - Start sending broadcast information for a | |
35 | * printer or update the broadcast contents. | |
36 | * dnssdStop() - Stop all DNS-SD registrations. | |
37 | * dnssdUpdate() - Handle DNS-SD queries. | |
38 | * get_auth_info_required() - Get the auth-info-required value to advertise. | |
39 | * get_hostconfig() - Get an /etc/hostconfig service setting. | |
40 | * update_lpd() - Update the LPD configuration as needed. | |
41 | * update_smb() - Update the SMB configuration as needed. | |
ef416fc2 | 42 | */ |
43 | ||
44 | /* | |
45 | * Include necessary headers... | |
46 | */ | |
47 | ||
48 | #include "cupsd.h" | |
49 | #include <grp.h> | |
50 | ||
f7deaa1a | 51 | #ifdef HAVE_DNSSD |
52 | # include <dns_sd.h> | |
cc0d019f MS |
53 | # ifdef __APPLE__ |
54 | # include <nameser.h> | |
55 | # ifdef HAVE_COREFOUNDATION | |
56 | # include <CoreFoundation/CoreFoundation.h> | |
57 | # endif /* HAVE_COREFOUNDATION */ | |
58 | # ifdef HAVE_SYSTEMCONFIGURATION | |
59 | # include <SystemConfiguration/SystemConfiguration.h> | |
60 | # endif /* HAVE_SYSTEMCONFIGURATION */ | |
61 | # endif /* __APPLE__ */ | |
f7deaa1a | 62 | #endif /* HAVE_DNSSD */ |
63 | ||
ef416fc2 | 64 | |
65 | /* | |
e00b005a | 66 | * Local functions... |
ef416fc2 | 67 | */ |
68 | ||
dcb445bc | 69 | #ifdef HAVE_DNSSD |
178cb736 MS |
70 | static char *get_auth_info_required(cupsd_printer_t *p, char *buffer, |
71 | size_t bufsize); | |
dcb445bc | 72 | #endif /* HAVE_DNSSD */ |
a603edef MS |
73 | #ifdef __APPLE__ |
74 | static int get_hostconfig(const char *name); | |
75 | #endif /* __APPLE__ */ | |
2e4ff8af | 76 | static void update_lpd(int onoff); |
2e4ff8af | 77 | static void update_smb(int onoff); |
f899b121 | 78 | |
e00b005a | 79 | |
7a14d768 | 80 | #ifdef HAVE_DNSSD |
e07d4801 MS |
81 | # ifdef HAVE_COREFOUNDATION |
82 | static void dnssdAddAlias(const void *key, const void *value, | |
83 | void *context); | |
84 | # endif /* HAVE_COREFOUNDATION */ | |
7a14d768 MS |
85 | static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p, |
86 | int for_lpd); | |
7a14d768 MS |
87 | static void dnssdDeregisterPrinter(cupsd_printer_t *p); |
88 | static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2], | |
89 | int count); | |
90 | static void dnssdRegisterCallback(DNSServiceRef sdRef, | |
88f9aafc | 91 | DNSServiceFlags flags, |
7a14d768 MS |
92 | DNSServiceErrorType errorCode, |
93 | const char *name, const char *regtype, | |
94 | const char *domain, void *context); | |
95 | static void dnssdRegisterPrinter(cupsd_printer_t *p); | |
f0ab5bff | 96 | static void dnssdStop(void); |
75bd9771 | 97 | static void dnssdUpdate(void); |
7a14d768 MS |
98 | #endif /* HAVE_DNSSD */ |
99 | ||
f7deaa1a | 100 | |
101 | /* | |
88f9aafc | 102 | * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a |
f7deaa1a | 103 | * local printer and remove any pending |
104 | * references to remote printers. | |
105 | */ | |
106 | ||
107 | void | |
108 | cupsdDeregisterPrinter( | |
109 | cupsd_printer_t *p, /* I - Printer to register */ | |
110 | int removeit) /* I - Printer being permanently removed */ | |
111 | { | |
112 | /* | |
7a14d768 | 113 | * Only deregister if browsing is enabled and it's a local printer... |
f7deaa1a | 114 | */ |
115 | ||
745129be MS |
116 | cupsdLogMessage(CUPSD_LOG_DEBUG, |
117 | "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name, | |
118 | removeit); | |
119 | ||
f7deaa1a | 120 | if (!Browsing || !p->shared || |
a2326b5b | 121 | (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) |
f7deaa1a | 122 | return; |
123 | ||
124 | /* | |
125 | * Announce the deletion... | |
126 | */ | |
127 | ||
a2326b5b MS |
128 | #ifdef HAVE_DNSSD |
129 | if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) | |
130 | dnssdDeregisterPrinter(p); | |
131 | #endif /* HAVE_DNSSD */ | |
132 | } | |
f7deaa1a | 133 | |
f7deaa1a | 134 | |
a2326b5b MS |
135 | /* |
136 | * 'cupsdRegisterPrinter()' - Start sending broadcast information for a | |
137 | * printer or update the broadcast contents. | |
138 | */ | |
f7deaa1a | 139 | |
a2326b5b MS |
140 | void |
141 | cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ | |
142 | { | |
143 | cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p, | |
144 | p->name); | |
f7deaa1a | 145 | |
a2326b5b MS |
146 | if (!Browsing || !BrowseLocalProtocols || |
147 | (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) | |
148 | return; | |
749b1e90 | 149 | |
f7deaa1a | 150 | #ifdef HAVE_DNSSD |
a2326b5b MS |
151 | if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) |
152 | dnssdRegisterPrinter(p); | |
f7deaa1a | 153 | #endif /* HAVE_DNSSD */ |
154 | } | |
155 | ||
ef416fc2 | 156 | |
157 | /* | |
a2326b5b | 158 | * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information. |
ef416fc2 | 159 | */ |
160 | ||
161 | void | |
a2326b5b | 162 | cupsdStartBrowsing(void) |
ef416fc2 | 163 | { |
ef416fc2 | 164 | cupsd_printer_t *p; /* Current printer */ |
411affcf | 165 | |
411affcf | 166 | |
a2326b5b | 167 | if (!Browsing || !BrowseLocalProtocols) |
ef416fc2 | 168 | return; |
169 | ||
a2326b5b MS |
170 | #ifdef HAVE_DNSSD |
171 | if (BrowseLocalProtocols & BROWSE_DNSSD) | |
172 | { | |
173 | DNSServiceErrorType error; /* Error from service creation */ | |
174 | cupsd_listener_t *lis; /* Current listening socket */ | |
ef416fc2 | 175 | |
ef416fc2 | 176 | |
ef416fc2 | 177 | /* |
a2326b5b | 178 | * First create a "master" connection for all registrations... |
ef416fc2 | 179 | */ |
180 | ||
a2326b5b MS |
181 | if ((error = DNSServiceCreateConnection(&DNSSDRef)) |
182 | != kDNSServiceErr_NoError) | |
ef416fc2 | 183 | { |
184 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
a2326b5b | 185 | "Unable to create master DNS-SD reference: %d", error); |
bd7854cb | 186 | |
a2326b5b MS |
187 | if (FatalErrors & CUPSD_FATAL_BROWSE) |
188 | cupsdEndProcess(getpid(), 0); | |
ef416fc2 | 189 | } |
a2326b5b | 190 | else |
b423cd4c | 191 | { |
192 | /* | |
a2326b5b | 193 | * Add the master connection to the select list... |
b423cd4c | 194 | */ |
195 | ||
a2326b5b | 196 | int fd = DNSServiceRefSockFD(DNSSDRef); |
b423cd4c | 197 | |
a2326b5b | 198 | fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); |
b423cd4c | 199 | |
a2326b5b | 200 | cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL); |
ef416fc2 | 201 | |
ef416fc2 | 202 | /* |
a2326b5b MS |
203 | * Then get the port we use for registrations. If we are not listening |
204 | * on any non-local ports, there is no sense sharing local printers via | |
205 | * Bonjour... | |
ef416fc2 | 206 | */ |
207 | ||
a2326b5b | 208 | DNSSDPort = 0; |
ef416fc2 | 209 | |
a2326b5b MS |
210 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
211 | lis; | |
212 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
ef416fc2 | 213 | { |
a2326b5b MS |
214 | if (httpAddrLocalhost(&(lis->address))) |
215 | continue; | |
ef416fc2 | 216 | |
a2326b5b MS |
217 | DNSSDPort = _httpAddrPort(&(lis->address)); |
218 | break; | |
ef416fc2 | 219 | } |
ef416fc2 | 220 | |
ef416fc2 | 221 | /* |
a2326b5b | 222 | * Set the computer name and register the web interface... |
ef416fc2 | 223 | */ |
224 | ||
a2326b5b | 225 | cupsdUpdateDNSSDName(); |
ef416fc2 | 226 | } |
227 | } | |
a2326b5b MS |
228 | #endif /* HAVE_DNSSD */ |
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); | |
ef416fc2 | 236 | |
a2326b5b MS |
237 | if (BrowseLocalProtocols & BROWSE_SMB) |
238 | update_smb(1); | |
ef416fc2 | 239 | |
240 | /* | |
a2326b5b | 241 | * Register the individual printers |
ef416fc2 | 242 | */ |
243 | ||
a2326b5b MS |
244 | for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); |
245 | p; | |
246 | p = (cupsd_printer_t *)cupsArrayNext(Printers)) | |
247 | if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) | |
248 | cupsdRegisterPrinter(p); | |
ef416fc2 | 249 | } |
250 | ||
251 | ||
f7deaa1a | 252 | /* |
a2326b5b | 253 | * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information. |
f7deaa1a | 254 | */ |
255 | ||
256 | void | |
a2326b5b | 257 | cupsdStopBrowsing(void) |
f7deaa1a | 258 | { |
a2326b5b | 259 | cupsd_printer_t *p; /* Current printer */ |
745129be | 260 | |
a2326b5b MS |
261 | |
262 | if (!Browsing || !BrowseLocalProtocols) | |
f7deaa1a | 263 | return; |
264 | ||
a2326b5b MS |
265 | /* |
266 | * De-register the individual printers | |
267 | */ | |
268 | ||
269 | for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); | |
270 | p; | |
271 | p = (cupsd_printer_t *)cupsArrayNext(Printers)) | |
272 | if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) | |
273 | cupsdDeregisterPrinter(p, 1); | |
274 | ||
275 | /* | |
276 | * Shut down browsing sockets... | |
277 | */ | |
f7deaa1a | 278 | |
279 | #ifdef HAVE_DNSSD | |
bdd6c45b | 280 | if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) |
a2326b5b | 281 | dnssdStop(); |
f7deaa1a | 282 | #endif /* HAVE_DNSSD */ |
d09495fa | 283 | |
a2326b5b MS |
284 | /* |
285 | * Disable LPD and SMB printer sharing as needed through external programs... | |
286 | */ | |
d09495fa | 287 | |
a2326b5b MS |
288 | if (BrowseLocalProtocols & BROWSE_LPD) |
289 | update_lpd(0); | |
d09495fa | 290 | |
a2326b5b MS |
291 | if (BrowseLocalProtocols & BROWSE_SMB) |
292 | update_smb(0); | |
d09495fa | 293 | } |
294 | ||
295 | ||
a2326b5b | 296 | #ifdef HAVE_DNSSD |
ef416fc2 | 297 | /* |
a2326b5b | 298 | * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing... |
ef416fc2 | 299 | */ |
300 | ||
301 | void | |
a2326b5b | 302 | cupsdUpdateDNSSDName(void) |
ef416fc2 | 303 | { |
a2326b5b MS |
304 | DNSServiceErrorType error; /* Error from service creation */ |
305 | char webif[1024]; /* Web interface share name */ | |
306 | # ifdef HAVE_SYSTEMCONFIGURATION | |
307 | SCDynamicStoreRef sc; /* Context for dynamic store */ | |
308 | CFDictionaryRef btmm; /* Back-to-My-Mac domains */ | |
309 | CFStringEncoding nameEncoding; /* Encoding of computer name */ | |
310 | CFStringRef nameRef; /* Host name CFString */ | |
311 | char nameBuffer[1024]; /* C-string buffer */ | |
312 | # endif /* HAVE_SYSTEMCONFIGURATION */ | |
ef416fc2 | 313 | |
ef416fc2 | 314 | |
315 | /* | |
a2326b5b MS |
316 | * Only share the web interface and printers when non-local listening is |
317 | * enabled... | |
318 | */ | |
ef416fc2 | 319 | |
a2326b5b | 320 | if (!DNSSDPort) |
ef416fc2 | 321 | return; |
ef416fc2 | 322 | |
e00b005a | 323 | /* |
a2326b5b | 324 | * Get the computer name as a c-string... |
e00b005a | 325 | */ |
ef416fc2 | 326 | |
a2326b5b MS |
327 | # ifdef HAVE_SYSTEMCONFIGURATION |
328 | sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL); | |
ef416fc2 | 329 | |
a2326b5b | 330 | if (sc) |
ef416fc2 | 331 | { |
332 | /* | |
a2326b5b | 333 | * Get the computer name from the dynamic store... |
ef416fc2 | 334 | */ |
335 | ||
a2326b5b | 336 | cupsdClearString(&DNSSDComputerName); |
ef416fc2 | 337 | |
a2326b5b | 338 | if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL) |
58dc1933 | 339 | { |
a2326b5b MS |
340 | if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer), |
341 | kCFStringEncodingUTF8)) | |
342 | { | |
343 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
344 | "Dynamic store computer name is \"%s\".", nameBuffer); | |
345 | cupsdSetString(&DNSSDComputerName, nameBuffer); | |
346 | } | |
e00b005a | 347 | |
a2326b5b MS |
348 | CFRelease(nameRef); |
349 | } | |
e00b005a | 350 | |
a2326b5b MS |
351 | if (!DNSSDComputerName) |
352 | { | |
353 | /* | |
354 | * Use the ServerName instead... | |
355 | */ | |
e00b005a | 356 | |
a2326b5b MS |
357 | cupsdLogMessage(CUPSD_LOG_DEBUG, |
358 | "Using ServerName \"%s\" as computer name.", ServerName); | |
359 | cupsdSetString(&DNSSDComputerName, ServerName); | |
360 | } | |
e00b005a | 361 | |
362 | /* | |
a2326b5b | 363 | * Get the local hostname from the dynamic store... |
e00b005a | 364 | */ |
365 | ||
a2326b5b | 366 | cupsdClearString(&DNSSDHostName); |
e00b005a | 367 | |
a2326b5b MS |
368 | if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL) |
369 | { | |
370 | if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer), | |
371 | kCFStringEncodingUTF8)) | |
372 | { | |
373 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
374 | "Dynamic store host name is \"%s\".", nameBuffer); | |
375 | cupsdSetString(&DNSSDHostName, nameBuffer); | |
376 | } | |
e00b005a | 377 | |
a2326b5b MS |
378 | CFRelease(nameRef); |
379 | } | |
e00b005a | 380 | |
a2326b5b | 381 | if (!DNSSDHostName) |
ef416fc2 | 382 | { |
383 | /* | |
a2326b5b | 384 | * Use the ServerName instead... |
ef416fc2 | 385 | */ |
386 | ||
a2326b5b MS |
387 | cupsdLogMessage(CUPSD_LOG_DEBUG, |
388 | "Using ServerName \"%s\" as host name.", ServerName); | |
389 | cupsdSetString(&DNSSDHostName, ServerName); | |
ef416fc2 | 390 | } |
e00b005a | 391 | |
392 | /* | |
a2326b5b | 393 | * Get any Back-to-My-Mac domains and add them as aliases... |
e00b005a | 394 | */ |
395 | ||
a2326b5b MS |
396 | cupsdFreeAliases(DNSSDAlias); |
397 | DNSSDAlias = NULL; | |
ef416fc2 | 398 | |
a2326b5b MS |
399 | btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac")); |
400 | if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID()) | |
ef416fc2 | 401 | { |
a2326b5b MS |
402 | cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.", |
403 | (int)CFDictionaryGetCount(btmm)); | |
404 | CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL); | |
ef416fc2 | 405 | } |
a2326b5b MS |
406 | else if (btmm) |
407 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
408 | "Bad Back to My Mac data in dynamic store!"); | |
409 | else | |
410 | cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add."); | |
749b1e90 | 411 | |
a2326b5b MS |
412 | if (btmm) |
413 | CFRelease(btmm); | |
321d8d57 | 414 | |
a2326b5b MS |
415 | CFRelease(sc); |
416 | } | |
417 | else | |
418 | # endif /* HAVE_SYSTEMCONFIGURATION */ | |
419 | { | |
420 | cupsdSetString(&DNSSDComputerName, ServerName); | |
421 | cupsdSetString(&DNSSDHostName, ServerName); | |
422 | } | |
321d8d57 | 423 | |
749b1e90 | 424 | /* |
a2326b5b | 425 | * Then (re)register the web interface if enabled... |
749b1e90 MS |
426 | */ |
427 | ||
a2326b5b MS |
428 | if (BrowseWebIF) |
429 | { | |
430 | if (DNSSDComputerName) | |
431 | snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName); | |
432 | else | |
433 | strlcpy(webif, "CUPS Web Interface", sizeof(webif)); | |
749b1e90 | 434 | |
a2326b5b MS |
435 | if (WebIFRef) |
436 | DNSServiceRefDeallocate(WebIFRef); | |
749b1e90 | 437 | |
a2326b5b MS |
438 | WebIFRef = DNSSDRef; |
439 | if ((error = DNSServiceRegister(&WebIFRef, | |
440 | kDNSServiceFlagsShareConnection, | |
441 | 0, webif, "_http._tcp", NULL, | |
442 | NULL, htons(DNSSDPort), 7, | |
443 | "\006path=/", dnssdRegisterCallback, | |
444 | NULL)) != kDNSServiceErr_NoError) | |
445 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
446 | "DNS-SD web interface registration failed: %d", error); | |
447 | } | |
749b1e90 | 448 | } |
a2326b5b | 449 | #endif /* HAVE_DNSSD */ |
749b1e90 | 450 | |
749b1e90 | 451 | |
a2326b5b MS |
452 | #ifdef HAVE_DNSSD |
453 | # ifdef HAVE_COREFOUNDATION | |
749b1e90 | 454 | /* |
a2326b5b | 455 | * 'dnssdAddAlias()' - Add a DNS-SD alias name. |
749b1e90 MS |
456 | */ |
457 | ||
a2326b5b MS |
458 | static void |
459 | dnssdAddAlias(const void *key, /* I - Key */ | |
460 | const void *value, /* I - Value (domain) */ | |
461 | void *context) /* I - Unused */ | |
749b1e90 | 462 | { |
a2326b5b | 463 | char valueStr[1024], /* Domain string */ |
dcb445bc MS |
464 | hostname[1024], /* Complete hostname */ |
465 | *hostptr; /* Pointer into hostname */ | |
749b1e90 | 466 | |
749b1e90 | 467 | |
a2326b5b MS |
468 | (void)key; |
469 | (void)context; | |
749b1e90 | 470 | |
a2326b5b MS |
471 | if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() && |
472 | CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr), | |
473 | kCFStringEncodingUTF8)) | |
474 | { | |
475 | snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr); | |
dcb445bc MS |
476 | hostptr = hostname + strlen(hostname) - 1; |
477 | if (*hostptr == '.') | |
478 | *hostptr = '\0'; /* Strip trailing dot */ | |
479 | ||
a2326b5b MS |
480 | if (!DNSSDAlias) |
481 | DNSSDAlias = cupsArrayNew(NULL, NULL); | |
749b1e90 | 482 | |
a2326b5b MS |
483 | cupsdAddAlias(DNSSDAlias, hostname); |
484 | cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s", | |
485 | hostname); | |
749b1e90 | 486 | } |
a2326b5b MS |
487 | else |
488 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
489 | "Bad Back to My Mac domain in dynamic store!"); | |
749b1e90 | 490 | } |
a2326b5b | 491 | # endif /* HAVE_COREFOUNDATION */ |
749b1e90 MS |
492 | |
493 | ||
749b1e90 | 494 | /* |
a2326b5b | 495 | * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info. |
749b1e90 MS |
496 | */ |
497 | ||
a2326b5b MS |
498 | static char * /* O - TXT record */ |
499 | dnssdBuildTxtRecord( | |
500 | int *txt_len, /* O - TXT record length */ | |
501 | cupsd_printer_t *p, /* I - Printer information */ | |
502 | int for_lpd) /* I - 1 = LPD, 0 = IPP */ | |
ef416fc2 | 503 | { |
e00b005a | 504 | int i; /* Looping var */ |
a2326b5b MS |
505 | char admin_hostname[256], /* .local hostname for admin page */ |
506 | adminurl_str[256], /* URL for the admin page */ | |
507 | type_str[32], /* Type to string buffer */ | |
508 | state_str[32], /* State to string buffer */ | |
509 | rp_str[1024], /* Queue name string buffer */ | |
510 | air_str[1024], /* auth-info-required string buffer */ | |
511 | *keyvalue[32][2]; /* Table of key/value pairs */ | |
749b1e90 | 512 | |
749b1e90 MS |
513 | |
514 | /* | |
a2326b5b | 515 | * Load up the key value pairs... |
749b1e90 MS |
516 | */ |
517 | ||
a2326b5b | 518 | i = 0; |
749b1e90 | 519 | |
a2326b5b MS |
520 | keyvalue[i ][0] = "txtvers"; |
521 | keyvalue[i++][1] = "1"; | |
749b1e90 | 522 | |
a2326b5b MS |
523 | keyvalue[i ][0] = "qtotal"; |
524 | keyvalue[i++][1] = "1"; | |
749b1e90 | 525 | |
a2326b5b MS |
526 | keyvalue[i ][0] = "rp"; |
527 | keyvalue[i++][1] = rp_str; | |
528 | if (for_lpd) | |
529 | strlcpy(rp_str, p->name, sizeof(rp_str)); | |
530 | else | |
531 | snprintf(rp_str, sizeof(rp_str), "%s/%s", | |
532 | (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); | |
88f9aafc | 533 | |
a2326b5b MS |
534 | keyvalue[i ][0] = "ty"; |
535 | keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown"; | |
749b1e90 | 536 | |
a2326b5b MS |
537 | snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName); |
538 | httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), | |
539 | "http", NULL, admin_hostname, DNSSDPort, "/%s/%s", | |
540 | (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", | |
541 | p->name); | |
542 | keyvalue[i ][0] = "adminurl"; | |
543 | keyvalue[i++][1] = adminurl_str; | |
749b1e90 | 544 | |
a2326b5b MS |
545 | keyvalue[i ][0] = "note"; |
546 | keyvalue[i++][1] = p->location ? p->location : ""; | |
749b1e90 | 547 | |
a2326b5b MS |
548 | keyvalue[i ][0] = "priority"; |
549 | keyvalue[i++][1] = for_lpd ? "100" : "0"; | |
749b1e90 | 550 | |
a2326b5b MS |
551 | keyvalue[i ][0] = "product"; |
552 | keyvalue[i++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown"; | |
749b1e90 | 553 | |
a2326b5b MS |
554 | keyvalue[i ][0] = "pdl"; |
555 | keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript"; | |
556 | ||
557 | if (get_auth_info_required(p, air_str, sizeof(air_str))) | |
749b1e90 | 558 | { |
a2326b5b MS |
559 | keyvalue[i ][0] = "air"; |
560 | keyvalue[i++][1] = air_str; | |
561 | } | |
749b1e90 | 562 | |
a2326b5b MS |
563 | keyvalue[i ][0] = "UUID"; |
564 | keyvalue[i++][1] = p->uuid + 9; | |
749b1e90 | 565 | |
a2326b5b MS |
566 | #ifdef HAVE_SSL |
567 | keyvalue[i ][0] = "TLS"; | |
568 | keyvalue[i++][1] = "1.2"; | |
569 | #endif /* HAVE_SSL */ | |
749b1e90 | 570 | |
a2326b5b MS |
571 | keyvalue[i ][0] = "Transparent"; |
572 | keyvalue[i++][1] = "F"; | |
749b1e90 | 573 | |
a2326b5b MS |
574 | keyvalue[i ][0] = "Binary"; |
575 | keyvalue[i++][1] = "F"; | |
749b1e90 | 576 | |
a2326b5b MS |
577 | keyvalue[i ][0] = "Fax"; |
578 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F"; | |
749b1e90 | 579 | |
a2326b5b MS |
580 | keyvalue[i ][0] = "Color"; |
581 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F"; | |
749b1e90 | 582 | |
a2326b5b MS |
583 | keyvalue[i ][0] = "Duplex"; |
584 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F"; | |
749b1e90 | 585 | |
a2326b5b MS |
586 | keyvalue[i ][0] = "Staple"; |
587 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F"; | |
749b1e90 | 588 | |
a2326b5b MS |
589 | keyvalue[i ][0] = "Copies"; |
590 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F"; | |
749b1e90 | 591 | |
a2326b5b MS |
592 | keyvalue[i ][0] = "Collate"; |
593 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F"; | |
749b1e90 | 594 | |
a2326b5b MS |
595 | keyvalue[i ][0] = "Punch"; |
596 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F"; | |
749b1e90 | 597 | |
a2326b5b MS |
598 | keyvalue[i ][0] = "Bind"; |
599 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F"; | |
e1d6a774 | 600 | |
a2326b5b MS |
601 | keyvalue[i ][0] = "Sort"; |
602 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F"; | |
e1d6a774 | 603 | |
a2326b5b MS |
604 | keyvalue[i ][0] = "Scan"; |
605 | keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F"; | |
749b1e90 | 606 | |
a2326b5b MS |
607 | snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); |
608 | snprintf(state_str, sizeof(state_str), "%d", p->state); | |
749b1e90 | 609 | |
a2326b5b MS |
610 | keyvalue[i ][0] = "printer-state"; |
611 | keyvalue[i++][1] = state_str; | |
749b1e90 | 612 | |
a2326b5b MS |
613 | keyvalue[i ][0] = "printer-type"; |
614 | keyvalue[i++][1] = type_str; | |
749b1e90 | 615 | |
e1d6a774 | 616 | /* |
a2326b5b | 617 | * Then pack them into a proper txt record... |
e1d6a774 | 618 | */ |
619 | ||
a2326b5b MS |
620 | return (dnssdPackTxtRecord(txt_len, keyvalue, i)); |
621 | } | |
e1d6a774 | 622 | |
e1d6a774 | 623 | |
a2326b5b MS |
624 | /* |
625 | * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a | |
626 | * printer. | |
627 | */ | |
749b1e90 | 628 | |
a2326b5b MS |
629 | static void |
630 | dnssdDeregisterPrinter( | |
631 | cupsd_printer_t *p) /* I - Printer */ | |
632 | { | |
633 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name); | |
749b1e90 MS |
634 | |
635 | /* | |
a2326b5b | 636 | * Closing the socket deregisters the service |
749b1e90 MS |
637 | */ |
638 | ||
a2326b5b | 639 | if (p->ipp_ref) |
749b1e90 | 640 | { |
a2326b5b MS |
641 | DNSServiceRefDeallocate(p->ipp_ref); |
642 | p->ipp_ref = NULL; | |
749b1e90 MS |
643 | } |
644 | ||
a2326b5b | 645 | if (p->ipp_txt) |
e1d6a774 | 646 | { |
647 | /* | |
a2326b5b | 648 | * p->ipp_txt is malloc'd, not _cupsStrAlloc'd... |
749b1e90 MS |
649 | */ |
650 | ||
a2326b5b MS |
651 | free(p->ipp_txt); |
652 | p->ipp_txt = NULL; | |
653 | } | |
749b1e90 | 654 | |
a2326b5b MS |
655 | if (p->printer_ref) |
656 | { | |
657 | DNSServiceRefDeallocate(p->printer_ref); | |
658 | p->printer_ref = NULL; | |
e1d6a774 | 659 | } |
a2326b5b MS |
660 | |
661 | if (p->printer_txt) | |
e1d6a774 | 662 | { |
663 | /* | |
a2326b5b | 664 | * p->printer_txt is malloc'd, not _cupsStrAlloc'd... |
e1d6a774 | 665 | */ |
666 | ||
a2326b5b MS |
667 | free(p->printer_txt); |
668 | p->printer_txt = NULL; | |
e1d6a774 | 669 | } |
749b1e90 | 670 | |
a2326b5b MS |
671 | /* |
672 | * Remove the printer from the array of DNS-SD printers, then clear the | |
673 | * registered name... | |
674 | */ | |
675 | ||
676 | cupsArrayRemove(DNSSDPrinters, p); | |
677 | cupsdClearString(&p->reg_name); | |
e1d6a774 | 678 | } |
749b1e90 MS |
679 | |
680 | ||
681 | /* | |
a2326b5b MS |
682 | * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the |
683 | * TXT record format. | |
749b1e90 MS |
684 | */ |
685 | ||
a2326b5b MS |
686 | static char * /* O - TXT record */ |
687 | dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ | |
688 | char *keyvalue[][2], /* I - Table of key value pairs */ | |
689 | int count) /* I - Items in table */ | |
749b1e90 | 690 | { |
a2326b5b MS |
691 | int i; /* Looping var */ |
692 | int length; /* Length of TXT record */ | |
693 | int length2; /* Length of value */ | |
694 | char *txtRecord; /* TXT record buffer */ | |
695 | char *cursor; /* Looping pointer */ | |
749b1e90 | 696 | |
749b1e90 MS |
697 | |
698 | /* | |
a2326b5b | 699 | * Calculate the buffer size |
749b1e90 MS |
700 | */ |
701 | ||
a2326b5b MS |
702 | if (count <= 0) |
703 | return (NULL); | |
704 | ||
705 | for (length = i = 0; i < count; i++) | |
706 | length += 1 + strlen(keyvalue[i][0]) + | |
707 | (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0); | |
749b1e90 MS |
708 | |
709 | /* | |
a2326b5b | 710 | * Allocate and fill it |
749b1e90 MS |
711 | */ |
712 | ||
a2326b5b MS |
713 | txtRecord = malloc(length); |
714 | if (txtRecord) | |
749b1e90 | 715 | { |
a2326b5b | 716 | *txt_len = length; |
749b1e90 | 717 | |
a2326b5b MS |
718 | for (cursor = txtRecord, i = 0; i < count; i++) |
719 | { | |
720 | /* | |
721 | * Drop in the p-string style length byte followed by the data | |
722 | */ | |
723 | ||
724 | length = strlen(keyvalue[i][0]); | |
725 | length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0; | |
726 | ||
727 | *cursor++ = (unsigned char)(length + length2); | |
728 | ||
729 | memcpy(cursor, keyvalue[i][0], length); | |
730 | cursor += length; | |
749b1e90 | 731 | |
a2326b5b MS |
732 | if (length2) |
733 | { | |
734 | length2 --; | |
735 | *cursor++ = '='; | |
736 | memcpy(cursor, keyvalue[i][1], length2); | |
737 | cursor += length2; | |
738 | } | |
749b1e90 MS |
739 | } |
740 | } | |
a2326b5b MS |
741 | |
742 | return (txtRecord); | |
749b1e90 MS |
743 | } |
744 | ||
745 | ||
ef55b745 | 746 | /* |
a2326b5b | 747 | * 'dnssdRegisterCallback()' - DNSServiceRegister callback. |
ef55b745 MS |
748 | */ |
749 | ||
749b1e90 | 750 | static void |
a2326b5b MS |
751 | dnssdRegisterCallback( |
752 | DNSServiceRef sdRef, /* I - DNS Service reference */ | |
753 | DNSServiceFlags flags, /* I - Reserved for future use */ | |
754 | DNSServiceErrorType errorCode, /* I - Error code */ | |
755 | const char *name, /* I - Service name */ | |
756 | const char *regtype, /* I - Service type */ | |
757 | const char *domain, /* I - Domain. ".local" for now */ | |
758 | void *context) /* I - User-defined context */ | |
749b1e90 | 759 | { |
a2326b5b MS |
760 | cupsd_printer_t *p = (cupsd_printer_t *)context; |
761 | /* Current printer */ | |
749b1e90 MS |
762 | |
763 | ||
a2326b5b MS |
764 | (void)sdRef; |
765 | (void)flags; | |
766 | (void)domain; | |
749b1e90 | 767 | |
a2326b5b MS |
768 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)", |
769 | name, regtype, p ? p->name : "Web Interface", | |
770 | p ? (p->reg_name ? p->reg_name : "(null)") : "NA"); | |
749b1e90 | 771 | |
a2326b5b | 772 | if (errorCode) |
749b1e90 | 773 | { |
a2326b5b MS |
774 | cupsdLogMessage(CUPSD_LOG_ERROR, |
775 | "DNSServiceRegister failed with error %d", (int)errorCode); | |
749b1e90 MS |
776 | return; |
777 | } | |
a2326b5b | 778 | else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name))) |
749b1e90 | 779 | { |
a2326b5b MS |
780 | cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"", |
781 | name, p->name); | |
749b1e90 | 782 | |
a2326b5b MS |
783 | cupsArrayRemove(DNSSDPrinters, p); |
784 | cupsdSetString(&p->reg_name, name); | |
785 | cupsArrayAdd(DNSSDPrinters, p); | |
749b1e90 | 786 | |
a2326b5b | 787 | LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED; |
749b1e90 MS |
788 | } |
789 | } | |
e1d6a774 | 790 | |
791 | ||
e1d6a774 | 792 | /* |
a2326b5b MS |
793 | * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer |
794 | * or update the broadcast contents. | |
e1d6a774 | 795 | */ |
796 | ||
797 | static void | |
a2326b5b | 798 | dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ |
e1d6a774 | 799 | { |
a2326b5b MS |
800 | DNSServiceErrorType se; /* dnssd errors */ |
801 | char *ipp_txt, /* IPP TXT record buffer */ | |
802 | *printer_txt, /* LPD TXT record buffer */ | |
803 | name[1024], /* Service name */ | |
804 | *nameptr; /* Pointer into name */ | |
805 | int ipp_len, /* IPP TXT record length */ | |
806 | printer_len, /* LPD TXT record length */ | |
807 | printer_port; /* LPD port number */ | |
808 | const char *regtype; /* Registration type */ | |
e1d6a774 | 809 | |
e1d6a774 | 810 | |
a2326b5b MS |
811 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name, |
812 | !p->ipp_ref ? "new" : "update"); | |
e1d6a774 | 813 | |
814 | /* | |
a2326b5b MS |
815 | * If per-printer sharing was just disabled make sure we're not |
816 | * registered before returning. | |
e1d6a774 | 817 | */ |
818 | ||
a2326b5b | 819 | if (!p->shared) |
e1d6a774 | 820 | { |
a2326b5b MS |
821 | dnssdDeregisterPrinter(p); |
822 | return; | |
e1d6a774 | 823 | } |
824 | ||
a2326b5b MS |
825 | /* |
826 | * The registered name takes the form of "<printer-info> @ <computer name>"... | |
827 | */ | |
e1d6a774 | 828 | |
a2326b5b | 829 | if (p->info && strlen(p->info) > 0) |
e1d6a774 | 830 | { |
a2326b5b MS |
831 | if (DNSSDComputerName) |
832 | snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName); | |
e1d6a774 | 833 | else |
a2326b5b | 834 | strlcpy(name, p->info, sizeof(name)); |
e1d6a774 | 835 | } |
a2326b5b MS |
836 | else if (DNSSDComputerName) |
837 | snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName); | |
838 | else | |
839 | strlcpy(name, p->name, sizeof(name)); | |
e1d6a774 | 840 | |
841 | /* | |
a2326b5b | 842 | * If an existing printer was renamed, unregister it and start over... |
e1d6a774 | 843 | */ |
844 | ||
a2326b5b MS |
845 | if (p->reg_name && strcmp(p->reg_name, name)) |
846 | dnssdDeregisterPrinter(p); | |
e1d6a774 | 847 | |
a2326b5b | 848 | if (!p->reg_name) |
e1d6a774 | 849 | { |
a2326b5b MS |
850 | cupsdSetString(&p->reg_name, name); |
851 | cupsArrayAdd(DNSSDPrinters, p); | |
e1d6a774 | 852 | } |
853 | ||
e1d6a774 | 854 | /* |
a2326b5b | 855 | * Register IPP and (optionally) LPD... |
e1d6a774 | 856 | */ |
857 | ||
a2326b5b MS |
858 | ipp_len = 0; /* anti-compiler-warning-code */ |
859 | ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0); | |
e1d6a774 | 860 | |
a2326b5b MS |
861 | if (p->ipp_ref && |
862 | (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))) | |
863 | { | |
864 | /* | |
865 | * Update the existing registration... | |
866 | */ | |
ef416fc2 | 867 | |
a2326b5b MS |
868 | /* A TTL of 0 means use record's original value (Radar 3176248) */ |
869 | if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, | |
870 | 0)) == kDNSServiceErr_NoError) | |
871 | { | |
872 | if (p->ipp_txt) | |
873 | free(p->ipp_txt); | |
ef416fc2 | 874 | |
a2326b5b MS |
875 | p->ipp_txt = ipp_txt; |
876 | p->ipp_len = ipp_len; | |
877 | ipp_txt = NULL; | |
878 | } | |
879 | else | |
880 | { | |
881 | /* | |
882 | * Failed to update record, lets close this reference and move on... | |
883 | */ | |
ef416fc2 | 884 | |
a2326b5b MS |
885 | cupsdLogMessage(CUPSD_LOG_ERROR, |
886 | "Unable to update IPP DNS-SD record for %s - %d", p->name, | |
887 | se); | |
ef416fc2 | 888 | |
a2326b5b MS |
889 | DNSServiceRefDeallocate(p->ipp_ref); |
890 | p->ipp_ref = NULL; | |
891 | } | |
892 | } | |
ef416fc2 | 893 | |
a2326b5b MS |
894 | if (!p->ipp_ref) |
895 | { | |
896 | /* | |
897 | * Initial registration. Use the _fax-ipp regtype for fax queues... | |
898 | */ | |
ef416fc2 | 899 | |
a2326b5b | 900 | regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType; |
ef416fc2 | 901 | |
a2326b5b MS |
902 | cupsdLogMessage(CUPSD_LOG_DEBUG, |
903 | "Registering DNS-SD printer %s with name \"%s\" and " | |
904 | "type \"%s\"", p->name, name, regtype); | |
ef416fc2 | 905 | |
a2326b5b MS |
906 | /* |
907 | * Register the queue, dropping characters as needed until we succeed... | |
908 | */ | |
ef416fc2 | 909 | |
a2326b5b | 910 | nameptr = name + strlen(name); |
ef416fc2 | 911 | |
a2326b5b MS |
912 | do |
913 | { | |
914 | p->ipp_ref = DNSSDRef; | |
915 | if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection, | |
916 | 0, name, regtype, NULL, NULL, | |
917 | htons(DNSSDPort), ipp_len, ipp_txt, | |
918 | dnssdRegisterCallback, | |
919 | p)) == kDNSServiceErr_BadParam) | |
920 | { | |
921 | /* | |
922 | * Name is too long, drop trailing characters, taking into account | |
923 | * UTF-8 encoding... | |
924 | */ | |
ef416fc2 | 925 | |
a2326b5b | 926 | nameptr --; |
ef416fc2 | 927 | |
a2326b5b MS |
928 | while (nameptr > name && (*nameptr & 0xc0) == 0x80) |
929 | nameptr --; | |
ef416fc2 | 930 | |
a2326b5b MS |
931 | if (nameptr > name) |
932 | *nameptr = '\0'; | |
933 | } | |
934 | } | |
935 | while (se == kDNSServiceErr_BadParam && nameptr > name); | |
ef416fc2 | 936 | |
a2326b5b MS |
937 | if (se == kDNSServiceErr_NoError) |
938 | { | |
939 | p->ipp_txt = ipp_txt; | |
940 | p->ipp_len = ipp_len; | |
941 | ipp_txt = NULL; | |
942 | } | |
943 | else | |
944 | cupsdLogMessage(CUPSD_LOG_WARN, | |
945 | "DNS-SD IPP registration of \"%s\" failed: %d", | |
946 | p->name, se); | |
947 | } | |
ef416fc2 | 948 | |
a2326b5b MS |
949 | if (ipp_txt) |
950 | free(ipp_txt); | |
ef416fc2 | 951 | |
a2326b5b | 952 | if (BrowseLocalProtocols & BROWSE_LPD) |
ef416fc2 | 953 | { |
a2326b5b MS |
954 | printer_len = 0; /* anti-compiler-warning-code */ |
955 | printer_port = 515; | |
956 | printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1); | |
957 | } | |
958 | else | |
959 | { | |
960 | printer_len = 0; | |
961 | printer_port = 0; | |
962 | printer_txt = NULL; | |
963 | } | |
ef416fc2 | 964 | |
a2326b5b MS |
965 | if (p->printer_ref && |
966 | (printer_len != p->printer_len || | |
967 | memcmp(printer_txt, p->printer_txt, printer_len))) | |
968 | { | |
ef416fc2 | 969 | /* |
a2326b5b | 970 | * Update the existing registration... |
ef416fc2 | 971 | */ |
972 | ||
a2326b5b MS |
973 | /* A TTL of 0 means use record's original value (Radar 3176248) */ |
974 | if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len, | |
975 | printer_txt, | |
976 | 0)) == kDNSServiceErr_NoError) | |
977 | { | |
978 | if (p->printer_txt) | |
979 | free(p->printer_txt); | |
ef416fc2 | 980 | |
a2326b5b MS |
981 | p->printer_txt = printer_txt; |
982 | p->printer_len = printer_len; | |
983 | printer_txt = NULL; | |
984 | } | |
985 | else | |
ef416fc2 | 986 | { |
987 | /* | |
a2326b5b | 988 | * Failed to update record, lets close this reference and move on... |
ef416fc2 | 989 | */ |
990 | ||
a2326b5b MS |
991 | cupsdLogMessage(CUPSD_LOG_ERROR, |
992 | "Unable to update LPD DNS-SD record for %s - %d", | |
993 | p->name, se); | |
ef416fc2 | 994 | |
a2326b5b MS |
995 | DNSServiceRefDeallocate(p->printer_ref); |
996 | p->printer_ref = NULL; | |
ef416fc2 | 997 | } |
998 | } | |
999 | ||
a2326b5b MS |
1000 | if (!p->printer_ref) |
1001 | { | |
1002 | /* | |
1003 | * Initial registration... | |
1004 | */ | |
ef416fc2 | 1005 | |
a2326b5b MS |
1006 | cupsdLogMessage(CUPSD_LOG_DEBUG, |
1007 | "Registering DNS-SD printer %s with name \"%s\" and " | |
1008 | "type \"_printer._tcp\"", p->name, name); | |
ef416fc2 | 1009 | |
a2326b5b MS |
1010 | p->printer_ref = DNSSDRef; |
1011 | if ((se = DNSServiceRegister(&p->printer_ref, | |
1012 | kDNSServiceFlagsShareConnection, | |
1013 | 0, name, "_printer._tcp", NULL, NULL, | |
1014 | htons(printer_port), printer_len, printer_txt, | |
1015 | dnssdRegisterCallback, | |
1016 | p)) == kDNSServiceErr_NoError) | |
1017 | { | |
1018 | p->printer_txt = printer_txt; | |
1019 | p->printer_len = printer_len; | |
1020 | printer_txt = NULL; | |
1021 | } | |
1022 | else | |
1023 | cupsdLogMessage(CUPSD_LOG_WARN, | |
1024 | "DNS-SD LPD registration of \"%s\" failed: %d", | |
1025 | p->name, se); | |
1026 | } | |
ef416fc2 | 1027 | |
a2326b5b MS |
1028 | if (printer_txt) |
1029 | free(printer_txt); | |
ef416fc2 | 1030 | } |
1031 | ||
1032 | ||
1033 | /* | |
a2326b5b | 1034 | * 'dnssdStop()' - Stop all DNS-SD registrations. |
ef416fc2 | 1035 | */ |
1036 | ||
a2326b5b MS |
1037 | static void |
1038 | dnssdStop(void) | |
ef416fc2 | 1039 | { |
a2326b5b | 1040 | cupsd_printer_t *p; /* Current printer */ |
ef416fc2 | 1041 | |
1042 | ||
1043 | /* | |
a2326b5b | 1044 | * De-register the individual printers |
ef416fc2 | 1045 | */ |
1046 | ||
a2326b5b MS |
1047 | for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); |
1048 | p; | |
1049 | p = (cupsd_printer_t *)cupsArrayNext(Printers)) | |
1050 | dnssdDeregisterPrinter(p); | |
ef416fc2 | 1051 | |
1052 | /* | |
a2326b5b | 1053 | * Shutdown the rest of the service refs... |
ef416fc2 | 1054 | */ |
1055 | ||
a2326b5b MS |
1056 | if (WebIFRef) |
1057 | { | |
1058 | DNSServiceRefDeallocate(WebIFRef); | |
1059 | WebIFRef = NULL; | |
1060 | } | |
ef416fc2 | 1061 | |
a2326b5b | 1062 | cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef)); |
ef416fc2 | 1063 | |
a2326b5b MS |
1064 | DNSServiceRefDeallocate(DNSSDRef); |
1065 | DNSSDRef = NULL; | |
ef416fc2 | 1066 | |
a2326b5b MS |
1067 | cupsArrayDelete(DNSSDPrinters); |
1068 | DNSSDPrinters = NULL; | |
ef416fc2 | 1069 | |
a2326b5b MS |
1070 | DNSSDPort = 0; |
1071 | } | |
ef416fc2 | 1072 | |
ef416fc2 | 1073 | |
a2326b5b MS |
1074 | /* |
1075 | * 'dnssdUpdate()' - Handle DNS-SD queries. | |
1076 | */ | |
ef416fc2 | 1077 | |
a2326b5b MS |
1078 | static void |
1079 | dnssdUpdate(void) | |
1080 | { | |
1081 | DNSServiceErrorType sdErr; /* Service discovery error */ | |
ef416fc2 | 1082 | |
ef416fc2 | 1083 | |
a2326b5b MS |
1084 | if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError) |
1085 | { | |
1086 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
1087 | "DNS Service Discovery registration error %d!", | |
1088 | sdErr); | |
1089 | dnssdStop(); | |
1090 | } | |
ef416fc2 | 1091 | } |
ef416fc2 | 1092 | |
1093 | ||
1094 | /* | |
a2326b5b | 1095 | * 'get_auth_info_required()' - Get the auth-info-required value to advertise. |
f899b121 | 1096 | */ |
1097 | ||
a2326b5b MS |
1098 | static char * /* O - String or NULL if none */ |
1099 | get_auth_info_required( | |
1100 | cupsd_printer_t *p, /* I - Printer */ | |
1101 | char *buffer, /* I - Value buffer */ | |
1102 | size_t bufsize) /* I - Size of value buffer */ | |
f899b121 | 1103 | { |
a2326b5b MS |
1104 | cupsd_location_t *auth; /* Pointer to authentication element */ |
1105 | char resource[1024]; /* Printer/class resource path */ | |
f899b121 | 1106 | |
1107 | ||
1108 | /* | |
a2326b5b | 1109 | * If auth-info-required is set for this printer, return that... |
f899b121 | 1110 | */ |
1111 | ||
a2326b5b | 1112 | if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none")) |
f899b121 | 1113 | { |
a2326b5b MS |
1114 | int i; /* Looping var */ |
1115 | char *bufptr; /* Pointer into buffer */ | |
f899b121 | 1116 | |
a2326b5b | 1117 | for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++) |
f899b121 | 1118 | { |
a2326b5b MS |
1119 | if (bufptr >= (buffer + bufsize - 2)) |
1120 | break; | |
7a14d768 | 1121 | |
a2326b5b MS |
1122 | if (i) |
1123 | *bufptr++ = ','; | |
f899b121 | 1124 | |
a2326b5b MS |
1125 | strlcpy(bufptr, p->auth_info_required[i], bufsize - (bufptr - buffer)); |
1126 | bufptr += strlen(bufptr); | |
f899b121 | 1127 | } |
1128 | ||
a2326b5b | 1129 | return (buffer); |
f899b121 | 1130 | } |
1131 | ||
f899b121 | 1132 | /* |
a2326b5b | 1133 | * Figure out the authentication data requirements to advertise... |
f899b121 | 1134 | */ |
1135 | ||
a2326b5b MS |
1136 | if (p->type & CUPS_PRINTER_CLASS) |
1137 | snprintf(resource, sizeof(resource), "/classes/%s", p->name); | |
f899b121 | 1138 | else |
a2326b5b | 1139 | snprintf(resource, sizeof(resource), "/printers/%s", p->name); |
f899b121 | 1140 | |
a2326b5b MS |
1141 | if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL || |
1142 | auth->type == CUPSD_AUTH_NONE) | |
1143 | auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); | |
f899b121 | 1144 | |
a2326b5b | 1145 | if (auth) |
f899b121 | 1146 | { |
a2326b5b | 1147 | int auth_type; /* Authentication type */ |
f899b121 | 1148 | |
a2326b5b | 1149 | if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT) |
dcb445bc | 1150 | auth_type = cupsdDefaultAuthType(); |
f899b121 | 1151 | |
a2326b5b MS |
1152 | switch (auth_type) |
1153 | { | |
1154 | case CUPSD_AUTH_NONE : | |
1155 | return (NULL); | |
f899b121 | 1156 | |
a2326b5b MS |
1157 | case CUPSD_AUTH_NEGOTIATE : |
1158 | strlcpy(buffer, "negotiate", bufsize); | |
1159 | break; | |
f899b121 | 1160 | |
a2326b5b MS |
1161 | default : |
1162 | strlcpy(buffer, "username,password", bufsize); | |
1163 | break; | |
1164 | } | |
f899b121 | 1165 | |
a2326b5b MS |
1166 | return (buffer); |
1167 | } | |
f899b121 | 1168 | |
a2326b5b MS |
1169 | return ("none"); |
1170 | } | |
dcb445bc | 1171 | #endif /* HAVE_DNSSD */ |
f899b121 | 1172 | |
f899b121 | 1173 | |
a2326b5b MS |
1174 | #ifdef __APPLE__ |
1175 | /* | |
1176 | * 'get_hostconfig()' - Get an /etc/hostconfig service setting. | |
1177 | */ | |
f899b121 | 1178 | |
a2326b5b MS |
1179 | static int /* O - 1 for YES or AUTOMATIC, 0 for NO */ |
1180 | get_hostconfig(const char *name) /* I - Name of service */ | |
1181 | { | |
1182 | cups_file_t *fp; /* Hostconfig file */ | |
1183 | char line[1024], /* Line from file */ | |
1184 | *ptr; /* Pointer to value */ | |
1185 | int state = 1; /* State of service */ | |
f899b121 | 1186 | |
f899b121 | 1187 | |
1188 | /* | |
a2326b5b MS |
1189 | * Try opening the /etc/hostconfig file; if we can't open it, assume that |
1190 | * the service is enabled/auto. | |
f899b121 | 1191 | */ |
1192 | ||
a2326b5b | 1193 | if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL) |
f899b121 | 1194 | { |
1195 | /* | |
a2326b5b | 1196 | * Read lines from the file until we find the service... |
f899b121 | 1197 | */ |
1198 | ||
a2326b5b | 1199 | while (cupsFileGets(fp, line, sizeof(line))) |
f899b121 | 1200 | { |
a2326b5b MS |
1201 | if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL) |
1202 | continue; | |
f899b121 | 1203 | |
a2326b5b | 1204 | *ptr++ = '\0'; |
f899b121 | 1205 | |
a2326b5b | 1206 | if (!_cups_strcasecmp(line, name)) |
f899b121 | 1207 | { |
a2326b5b MS |
1208 | /* |
1209 | * Found the service, see if it is set to "-NO-"... | |
1210 | */ | |
f899b121 | 1211 | |
a2326b5b MS |
1212 | if (!_cups_strncasecmp(ptr, "-NO-", 4)) |
1213 | state = 0; | |
1214 | break; | |
f899b121 | 1215 | } |
1216 | } | |
f899b121 | 1217 | |
a2326b5b | 1218 | cupsFileClose(fp); |
f899b121 | 1219 | } |
1220 | ||
a2326b5b | 1221 | return (state); |
f899b121 | 1222 | } |
a2326b5b | 1223 | #endif /* __APPLE__ */ |
f899b121 | 1224 | |
1225 | ||
2e4ff8af MS |
1226 | /* |
1227 | * 'update_lpd()' - Update the LPD configuration as needed. | |
1228 | */ | |
1229 | ||
1230 | static void | |
1231 | update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */ | |
1232 | { | |
1233 | if (!LPDConfigFile) | |
1234 | return; | |
1235 | ||
a603edef MS |
1236 | #ifdef __APPLE__ |
1237 | /* | |
1238 | * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf | |
1239 | * setting for backwards-compatibility. | |
1240 | */ | |
1241 | ||
1242 | if (onoff && !get_hostconfig("CUPS_LPD")) | |
1243 | onoff = 0; | |
1244 | #endif /* __APPLE__ */ | |
1245 | ||
2e4ff8af MS |
1246 | if (!strncmp(LPDConfigFile, "xinetd:///", 10)) |
1247 | { | |
1248 | /* | |
1249 | * Enable/disable LPD via the xinetd.d config file for cups-lpd... | |
1250 | */ | |
1251 | ||
1252 | char newfile[1024]; /* New cups-lpd.N file */ | |
1253 | cups_file_t *ofp, /* Original file pointer */ | |
1254 | *nfp; /* New file pointer */ | |
1255 | char line[1024]; /* Line from file */ | |
1256 | ||
1257 | ||
1258 | snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9); | |
1259 | ||
1260 | if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL) | |
1261 | { | |
1262 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s", | |
1263 | LPDConfigFile + 9, strerror(errno)); | |
1264 | return; | |
1265 | } | |
1266 | ||
1267 | if ((nfp = cupsFileOpen(newfile, "w")) == NULL) | |
1268 | { | |
1269 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s", | |
1270 | newfile, strerror(errno)); | |
1271 | cupsFileClose(ofp); | |
1272 | return; | |
1273 | } | |
1274 | ||
1275 | /* | |
1276 | * Copy all of the lines from the cups-lpd file... | |
1277 | */ | |
1278 | ||
1279 | while (cupsFileGets(ofp, line, sizeof(line))) | |
1280 | { | |
1281 | if (line[0] == '{') | |
1282 | { | |
1283 | cupsFilePrintf(nfp, "%s\n", line); | |
1284 | snprintf(line, sizeof(line), "\tdisable = %s", | |
1285 | onoff ? "no" : "yes"); | |
1286 | } | |
568fa3fa MS |
1287 | else if (!strstr(line, "disable =")) |
1288 | cupsFilePrintf(nfp, "%s\n", line); | |
2e4ff8af MS |
1289 | } |
1290 | ||
1291 | cupsFileClose(nfp); | |
1292 | cupsFileClose(ofp); | |
1293 | rename(newfile, LPDConfigFile + 9); | |
1294 | } | |
568fa3fa | 1295 | #ifdef __APPLE__ |
2e4ff8af MS |
1296 | else if (!strncmp(LPDConfigFile, "launchd:///", 11)) |
1297 | { | |
1298 | /* | |
1299 | * Enable/disable LPD via the launchctl command... | |
1300 | */ | |
1301 | ||
1302 | char *argv[5], /* Arguments for command */ | |
1303 | *envp[MAX_ENV]; /* Environment for command */ | |
1304 | int pid; /* Process ID */ | |
1305 | ||
1306 | ||
1307 | cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); | |
1308 | argv[0] = (char *)"launchctl"; | |
1309 | argv[1] = (char *)(onoff ? "load" : "unload"); | |
1310 | argv[2] = (char *)"-w"; | |
1311 | argv[3] = LPDConfigFile + 10; | |
1312 | argv[4] = NULL; | |
1313 | ||
a4924f6c | 1314 | cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, |
38e73f87 | 1315 | NULL, NULL, &pid); |
2e4ff8af | 1316 | } |
568fa3fa MS |
1317 | #endif /* __APPLE__ */ |
1318 | else | |
1319 | cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!"); | |
2e4ff8af MS |
1320 | } |
1321 | ||
1322 | ||
f899b121 | 1323 | /* |
2e4ff8af MS |
1324 | * 'update_smb()' - Update the SMB configuration as needed. |
1325 | */ | |
1326 | ||
1327 | static void | |
1328 | update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */ | |
1329 | { | |
1330 | if (!SMBConfigFile) | |
1331 | return; | |
1332 | ||
1333 | if (!strncmp(SMBConfigFile, "samba:///", 9)) | |
1334 | { | |
1335 | /* | |
1336 | * Enable/disable SMB via the specified smb.conf config file... | |
1337 | */ | |
1338 | ||
1339 | char newfile[1024]; /* New smb.conf.N file */ | |
1340 | cups_file_t *ofp, /* Original file pointer */ | |
1341 | *nfp; /* New file pointer */ | |
1342 | char line[1024]; /* Line from file */ | |
1343 | int in_printers; /* In [printers] section? */ | |
1344 | ||
1345 | ||
1346 | snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8); | |
1347 | ||
1348 | if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL) | |
1349 | { | |
1350 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s", | |
1351 | SMBConfigFile + 8, strerror(errno)); | |
1352 | return; | |
1353 | } | |
1354 | ||
1355 | if ((nfp = cupsFileOpen(newfile, "w")) == NULL) | |
1356 | { | |
1357 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s", | |
1358 | newfile, strerror(errno)); | |
1359 | cupsFileClose(ofp); | |
1360 | return; | |
1361 | } | |
1362 | ||
1363 | /* | |
1364 | * Copy all of the lines from the smb.conf file... | |
1365 | */ | |
1366 | ||
1367 | in_printers = 0; | |
1368 | ||
1369 | while (cupsFileGets(ofp, line, sizeof(line))) | |
1370 | { | |
1371 | if (in_printers && strstr(line, "printable =")) | |
1372 | snprintf(line, sizeof(line), " printable = %s", | |
1373 | onoff ? "yes" : "no"); | |
1374 | ||
1375 | cupsFilePrintf(nfp, "%s\n", line); | |
1376 | ||
1377 | if (line[0] == '[') | |
1378 | in_printers = !strcmp(line, "[printers]"); | |
1379 | } | |
1380 | ||
1381 | cupsFileClose(nfp); | |
1382 | cupsFileClose(ofp); | |
1383 | rename(newfile, SMBConfigFile + 8); | |
1384 | } | |
568fa3fa MS |
1385 | else |
1386 | cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!"); | |
2e4ff8af MS |
1387 | } |
1388 | ||
1389 | ||
1390 | /* | |
b19ccc9e | 1391 | * End of "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $". |
ef416fc2 | 1392 | */ |