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