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