this repo has no description
at fixPythonPipStalling 967 lines 24 kB view raw
1/* 2 * Copyright (c) 2006-2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * June 26, 2006 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31#include <ctype.h> 32#include <stdio.h> 33#include <unistd.h> 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/socket.h> 37#include <sys/stat.h> 38#include <sys/sysctl.h> 39#include <sys/time.h> 40#include <net/if.h> 41#include <net/if_dl.h> 42#include <netinet/in.h> 43#include <arpa/inet.h> 44#include <netdb_async.h> 45#include <notify.h> 46#include <smb_server_prefs.h> 47 48#include <CoreFoundation/CoreFoundation.h> 49#include <CoreFoundation/CFStringDefaultEncoding.h> // for __CFStringGetInstallationEncodingAndRegion() 50#include <SystemConfiguration/SystemConfiguration.h> 51#include <SystemConfiguration/SCValidation.h> 52#include <SystemConfiguration/SCPrivate.h> 53 54#ifdef MAIN 55#define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__) 56#else // MAIN 57#include "ip_plugin.h" 58#endif // MAIN 59 60#define HW_MODEL_LEN 64 // Note: must be >= NETBIOS_NAME_LEN (below) 61 62#define NETBIOS_NAME_LEN 16 63 64#define SMB_STARTUP_DELAY 60.0 65#define SMB_DEBOUNCE_DELAY 5.0 66#define SMB_CONFIGURATION_QUEUE "com.apple.config.smb-configuration" 67 68static SCDynamicStoreRef store = NULL; 69static CFRunLoopRef rl = NULL; 70static CFRunLoopSourceRef rls = NULL; 71static dispatch_queue_t queue = NULL; 72 73static int notify_token = -1; 74 75static struct timeval ptrQueryStart; 76static SCNetworkReachabilityRef ptrTarget = NULL; 77 78static CFRunLoopTimerRef timer = NULL; 79 80 81static CFAbsoluteTime 82boottime(void) 83{ 84 static CFAbsoluteTime bt = 0; 85 86 if (bt == 0) { 87 int mib[2] = { CTL_KERN, KERN_BOOTTIME }; 88 struct timeval tv; 89 size_t tv_len = sizeof(tv); 90 91 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &tv, &tv_len, NULL, 0) == -1) { 92 my_log(LOG_ERR, "sysctl() CTL_KERN/KERN_BOOTTIME failed: %s", strerror(errno)); 93 return kCFAbsoluteTimeIntervalSince1970; 94 } 95 96 // Note: we need to convert from Unix time to CF time. 97 bt = (CFTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970; 98 bt += (1.0E-6 * (CFTimeInterval)tv.tv_usec); 99 } 100 101 return bt; 102} 103 104 105static CFStringRef 106copy_default_name(void) 107{ 108 CFStringRef model; 109 CFIndex n; 110 CFMutableStringRef str; 111 112 // get HW model name 113 model = _SC_hw_model(TRUE); 114 if (model == NULL) { 115 return NULL; 116 } 117 118 // start off with the [trunated] HW model 119 str = CFStringCreateMutable(NULL, 0); 120 CFStringAppend(str, model); 121 122 // truncate as needed 123 n = CFStringGetLength(str); 124 if (n > (NETBIOS_NAME_LEN - 1)) { 125 CFStringReplace(str, 126 CFRangeMake(NETBIOS_NAME_LEN, n - (NETBIOS_NAME_LEN - 1)), 127 CFSTR("")); 128 n = NETBIOS_NAME_LEN - 1; 129 } 130 131 // 132 // if there is room for at least one byte (two hex characters) 133 // of the MAC address than append that to the NetBIOS name. 134 // 135 // NETBIOS_NAME_LEN max length 136 // -1 the last byte is reserved 137 // -3 "-XX" 138 // 139 if (n < (NETBIOS_NAME_LEN - 1 - 3)) { 140 SCNetworkInterfaceRef interface; 141 142 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, CFSTR("en0"), 143 kIncludeNoVirtualInterfaces); 144 if (interface != NULL) { 145 CFMutableStringRef en0_MAC; 146 147 en0_MAC = (CFMutableStringRef)SCNetworkInterfaceGetHardwareAddressString(interface); 148 if (en0_MAC != NULL) { 149 CFIndex en0_MAC_len; 150 151 // remove ":" characters from MAC address string 152 en0_MAC = CFStringCreateMutableCopy(NULL, 0, en0_MAC); 153 CFStringFindAndReplace(en0_MAC, 154 CFSTR(":"), 155 CFSTR(""), 156 CFRangeMake(0, CFStringGetLength(en0_MAC)), 157 0); 158 159 // 160 // compute how may bytes (characters) to append 161 // ... and limit that number to 6 162 // 163 // NETBIOS_NAME_LEN max length 164 // -1 the last byte is reserved 165 // -n "iMac" 166 // -1 "-" 167 // 168 n = ((NETBIOS_NAME_LEN - 1 - n - 1) / 2) * 2; 169 if (n > 6) { 170 n = 6; 171 } 172 173 // remove what we don't want 174 en0_MAC_len = CFStringGetLength(en0_MAC); 175 if (en0_MAC_len > n) { 176 CFStringDelete(en0_MAC, CFRangeMake(0, en0_MAC_len - n)); 177 } 178 179 // append 180 CFStringAppendFormat(str, NULL, CFSTR("-%@"), en0_MAC); 181 CFRelease(en0_MAC); 182 } 183 184 CFRelease(interface); 185 } 186 } 187 188 CFStringUppercase(str, NULL); 189 return str; 190} 191 192 193static CFDictionaryRef 194smb_copy_global_configuration(SCDynamicStoreRef store) 195{ 196 CFDictionaryRef dict; 197 CFStringRef key; 198 199 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 200 kSCDynamicStoreDomainState, 201 kSCEntNetSMB); 202 dict = SCDynamicStoreCopyValue(store, key); 203 CFRelease(key); 204 205 if (dict != NULL) { 206 if (isA_CFDictionary(dict)) { 207 return dict; 208 } 209 210 CFRelease(dict); 211 } 212 213 dict = CFDictionaryCreate(NULL, // allocator 214 NULL, // keys 215 NULL, // values 216 0, // numValues 217 &kCFTypeDictionaryKeyCallBacks, 218 &kCFTypeDictionaryValueCallBacks); 219 return dict; 220} 221 222 223static void 224update_pref(SCPreferencesRef prefs, CFStringRef key, CFTypeRef newVal, Boolean *changed) 225{ 226 CFTypeRef curVal; 227 228 curVal = SCPreferencesGetValue(prefs, key); 229 if (!_SC_CFEqual(curVal, newVal)) { 230 if (newVal != NULL) { 231 SCPreferencesSetValue(prefs, key, newVal); 232 } else { 233 SCPreferencesRemoveValue(prefs, key); 234 } 235 236 *changed = TRUE; 237 } 238 239 return; 240} 241 242 243static void 244smb_set_configuration(SCDynamicStoreRef store, CFDictionaryRef dict) 245{ 246 CFArrayRef array; 247 Boolean changed = FALSE; 248 UInt32 dosCodepage = 0; 249 CFStringEncoding dosEncoding = 0; 250 CFStringEncoding macEncoding = kCFStringEncodingMacRoman; 251 uint32_t macRegion = 0; 252 Boolean ok; 253 SCPreferencesRef prefs; 254 CFStringRef str; 255 256 prefs = SCPreferencesCreate(NULL, CFSTR("smb-configuration"), CFSTR(kSMBPreferencesAppID)); 257 if (prefs == NULL) { 258 my_log(LOG_ERR, 259 "smb_set_configuration: SCPreferencesCreate() failed: %s", 260 SCErrorString(SCError())); 261 return; 262 } 263 264 ok = SCPreferencesLock(prefs, TRUE); 265 if (!ok) { 266 my_log(LOG_ERR, 267 "smb_set_configuration: SCPreferencesLock() failed: %s", 268 SCErrorString(SCError())); 269 goto done; 270 } 271 272 // Server description 273 str = SCDynamicStoreCopyComputerName(store, &macEncoding); 274 update_pref(prefs, CFSTR(kSMBPrefServerDescription), str, &changed); 275 276 // DOS code page 277 if (str != NULL) { 278 if (macEncoding == kCFStringEncodingMacRoman) { 279 CFStringRef key; 280 CFDictionaryRef dict; 281 282 // get region 283 key = SCDynamicStoreKeyCreateComputerName(NULL); 284 dict = SCDynamicStoreCopyValue(store, key); 285 CFRelease(key); 286 if (dict != NULL) { 287 if (isA_CFDictionary(dict)) { 288 CFNumberRef num; 289 SInt32 val; 290 291 num = CFDictionaryGetValue(dict, kSCPropSystemComputerNameRegion); 292 if (isA_CFNumber(num) && 293 CFNumberGetValue(num, kCFNumberSInt32Type, &val)) { 294 macRegion = (uint32_t)val; 295 } 296 } 297 298 CFRelease(dict); 299 } 300 } 301 302 CFRelease(str); 303 } else { 304 // Important: must have root acccess (eUID==0) to access the config file! 305 __CFStringGetInstallationEncodingAndRegion((uint32_t *)&macEncoding, &macRegion); 306 } 307 _SC_dos_encoding_and_codepage(macEncoding, macRegion, &dosEncoding, &dosCodepage); 308 str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (unsigned int)dosCodepage); 309 assert(str != NULL); 310 update_pref(prefs, CFSTR(kSMBPrefDOSCodePage), str, &changed); 311 CFRelease(str); 312 313 // NetBIOS name 314 str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName); 315 str = isA_CFString(str); 316 update_pref(prefs, CFSTR(kSMBPrefNetBIOSName), str, &changed); 317 318 // NetBIOS node type 319 str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSNodeType); 320 str = isA_CFString(str); 321 if (str != NULL) { 322 if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeBroadcast)) { 323 // B-node 324 str = CFSTR(kSMBPrefNetBIOSNodeBroadcast); 325 } else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypePeer)) { 326 // P-node 327 str = CFSTR(kSMBPrefNetBIOSNodePeer); 328 } else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeMixed)) { 329 // M-node 330 str = CFSTR(kSMBPrefNetBIOSNodeMixed); 331 } else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeHybrid)) { 332 // H-node 333 str = CFSTR(kSMBPrefNetBIOSNodeHybrid); 334 } else { 335 str = NULL; 336 } 337 } 338 update_pref(prefs, CFSTR(kSMBPrefNetBIOSNodeType), str, &changed); 339 340#ifdef ADD_NETBIOS_SCOPE 341 // NetBIOS scope 342 str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSScope); 343 str = isA_CFString(str); 344 update_pref(prefs, CFSTR(kSMBPrefNetBIOSScope), str, &changed); 345#endif // ADD_NETBIOS_SCOPE 346 347 // WINS addresses 348 array = CFDictionaryGetValue(dict, kSCPropNetSMBWINSAddresses); 349 array = isA_CFArray(array); 350 update_pref(prefs, CFSTR(kSMBPrefWINSServerAddressList), array, &changed); 351 352 // Workgroup (or domain) 353 str = CFDictionaryGetValue(dict, kSCPropNetSMBWorkgroup); 354 str = isA_CFString(str); 355 update_pref(prefs, CFSTR(kSMBPrefWorkgroup), str, &changed); 356 357 if (changed) { 358 ok = SCPreferencesCommitChanges(prefs); 359 if (!ok) { 360 if ((SCError() != EROFS)) { 361 my_log(LOG_ERR, 362 "smb_set_configuration: SCPreferencesCommitChanges() failed: %s", 363 SCErrorString(SCError())); 364 } 365 goto done; 366 } 367 368 ok = SCPreferencesApplyChanges(prefs); 369 if (!ok) { 370 my_log(LOG_ERR, 371 "smb_set_configuration: SCPreferencesApplyChanges() failed: %s", 372 SCErrorString(SCError())); 373 goto done; 374 } 375 } 376 377 done : 378 379 (void) SCPreferencesUnlock(prefs); 380 CFRelease(prefs); 381 return; 382} 383 384 385static CFStringRef 386copy_primary_service(SCDynamicStoreRef store) 387{ 388 CFDictionaryRef dict; 389 CFStringRef key; 390 CFStringRef serviceID = NULL; 391 392 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 393 kSCDynamicStoreDomainState, 394 kSCEntNetIPv4); 395 dict = SCDynamicStoreCopyValue(store, key); 396 CFRelease(key); 397 398 if (dict != NULL) { 399 if (isA_CFDictionary(dict)) { 400 serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService); 401 if (isA_CFString(serviceID)) { 402 CFRetain(serviceID); 403 } else { 404 serviceID = NULL; 405 } 406 } 407 CFRelease(dict); 408 } 409 410 return serviceID; 411} 412 413 414static CFStringRef 415copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID) 416{ 417 CFStringRef address = NULL; 418 CFDictionaryRef dict; 419 CFStringRef key; 420 421 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 422 kSCDynamicStoreDomainState, 423 serviceID, 424 kSCEntNetIPv4); 425 dict = SCDynamicStoreCopyValue(store, key); 426 CFRelease(key); 427 428 if (dict != NULL) { 429 if (isA_CFDictionary(dict)) { 430 CFArrayRef addresses; 431 432 addresses = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses); 433 if (isA_CFArray(addresses) && (CFArrayGetCount(addresses) > 0)) { 434 address = CFArrayGetValueAtIndex(addresses, 0); 435 if (isA_CFString(address)) { 436 CFRetain(address); 437 } else { 438 address = NULL; 439 } 440 } 441 } 442 CFRelease(dict); 443 } 444 445 return address; 446} 447 448 449static void 450ptr_query_stop() 451{ 452 if (ptrTarget == NULL) { 453 return; 454 } 455 456 my_log(LOG_INFO, "NetBIOS name: ptr query stop"); 457 458 SCNetworkReachabilitySetCallback(ptrTarget, NULL, NULL); 459 SCNetworkReachabilityUnscheduleFromRunLoop(ptrTarget, rl, kCFRunLoopDefaultMode); 460 CFRelease(ptrTarget); 461 ptrTarget = NULL; 462 463 return; 464} 465 466 467static void 468ptr_query_callback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) 469{ 470#pragma unused(info) 471 CFDictionaryRef dict; 472 CFStringRef name; 473 CFMutableDictionaryRef newDict; 474 struct timeval ptrQueryComplete; 475 struct timeval ptrQueryElapsed; 476 477 (void) gettimeofday(&ptrQueryComplete, NULL); 478 timersub(&ptrQueryComplete, &ptrQueryStart, &ptrQueryElapsed); 479 my_log(LOG_INFO, "NetBIOS name: ptr query complete%s (query time = %ld.%3.3d)", 480 (flags & kSCNetworkReachabilityFlagsReachable) ? "" : ", host not found", 481 ptrQueryElapsed.tv_sec, 482 ptrQueryElapsed.tv_usec / 1000); 483 484 // get network configuration 485 dict = smb_copy_global_configuration(store); 486 487 // use NetBIOS name from network configuration (if available) 488 name = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName); 489 if ((name != NULL) && _SC_CFStringIsValidNetBIOSName(name)) { 490 my_log(LOG_INFO, "NetBIOS name (network configuration) = %@", name); 491 goto setDict; 492 } 493 494 // use reverse DNS name, if available 495 496 name = NULL; 497 if (flags & kSCNetworkReachabilityFlagsReachable) { 498 int error_num; 499 CFArrayRef hosts; 500 501 /* 502 * if [reverse] DNS query was successful 503 */ 504 hosts = SCNetworkReachabilityCopyResolvedAddress(target, &error_num); 505 if (hosts != NULL) { 506 if (CFArrayGetCount(hosts) > 0) { 507 CFIndex ptrLen; 508 CFMutableStringRef ptrName; 509 CFRange range; 510 511 name = CFArrayGetValueAtIndex(hosts, 0); 512 ptrName = CFStringCreateMutableCopy(NULL, 0, name); 513 ptrLen = CFStringGetLength(ptrName); 514 if (CFStringFindWithOptions(ptrName, 515 CFSTR("."), 516 CFRangeMake(0, ptrLen), 517 0, 518 &range)) { 519 CFStringDelete(ptrName, 520 CFRangeMake(range.location, ptrLen - range.location)); 521 } 522 name = ptrName; 523 } 524 CFRelease(hosts); 525 } 526 } 527 if (name != NULL) { 528 if (_SC_CFStringIsValidNetBIOSName(name)) { 529 my_log(LOG_INFO, "NetBIOS name (reverse DNS query) = %@", name); 530 goto setName; 531 } 532 CFRelease(name); 533 } 534 535 // try local (multicast DNS) name, if available 536 name = SCDynamicStoreCopyLocalHostName(store); 537 if (name != NULL) { 538 if (_SC_CFStringIsValidNetBIOSName(name)) { 539 my_log(LOG_INFO, "NetBIOS name (multicast DNS) = %@", name); 540 goto setName; 541 } 542 CFRelease(name); 543 } 544 545 // use "default" name 546 name = copy_default_name(); 547 if (name != NULL) { 548 my_log(LOG_INFO, "NetBIOS name (default) = %@", name); 549 goto setName; 550 } 551 552 goto setDict; 553 554 setName : 555 556 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 557 CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name); 558 CFRelease(dict); 559 dict = newDict; 560 CFRelease(name); 561 562 setDict : 563 564 // update SMB configuration 565 smb_set_configuration(store, dict); 566 CFRelease(dict); 567 568 ptr_query_stop(); 569 570#ifdef MAIN 571 CFRunLoopStop(rl); 572#endif // MAIN 573 574 return; 575} 576 577 578static Boolean 579ptr_query_start(CFStringRef address) 580{ 581 union { 582 struct sockaddr sa; 583 struct sockaddr_in sin; 584 struct sockaddr_in6 sin6; 585 } addr; 586 char buf[64]; 587 CFDataRef data; 588 CFMutableDictionaryRef options; 589 590 if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) { 591 my_log(LOG_ERR, "could not convert [primary] address string"); 592 return FALSE; 593 } 594 595 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) { 596 my_log(LOG_ERR, "could not convert [primary] address"); 597 return FALSE; 598 } 599 600 options = CFDictionaryCreateMutable(NULL, 601 0, 602 &kCFTypeDictionaryKeyCallBacks, 603 &kCFTypeDictionaryValueCallBacks); 604 data = CFDataCreate(NULL, (const UInt8 *)&addr.sa, addr.sa.sa_len); 605 CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, data); 606 CFRelease(data); 607 ptrTarget = SCNetworkReachabilityCreateWithOptions(NULL, options); 608 CFRelease(options); 609 if (ptrTarget == NULL) { 610 my_log(LOG_ERR, "could not resolve [primary] address"); 611 return FALSE; 612 } 613 614 my_log(LOG_INFO, "NetBIOS name: ptr query start"); 615 616 (void) gettimeofday(&ptrQueryStart, NULL); 617 (void) SCNetworkReachabilitySetCallback(ptrTarget, ptr_query_callback, NULL); 618 (void) SCNetworkReachabilityScheduleWithRunLoop(ptrTarget, rl, kCFRunLoopDefaultMode); 619 620 return TRUE; 621} 622 623 624static void 625smb_update_configuration(CFRunLoopTimerRef _timer, void *info) 626{ 627#pragma unused(_timer) 628 CFStringRef address = NULL; 629 CFDictionaryRef dict; 630 CFStringRef name; 631 CFStringRef serviceID = NULL; 632 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 633 634 // get network configuration 635 dict = smb_copy_global_configuration(store); 636 637 // use NetBIOS name from network configuration (if available) 638 name = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName); 639 if ((name != NULL) && _SC_CFStringIsValidNetBIOSName(name)) { 640 my_log(LOG_INFO, "NetBIOS name (network configuration) = %@", name); 641 goto set; 642 } 643 644 // get primary service ID 645 serviceID = copy_primary_service(store); 646 if (serviceID == NULL) { 647 // if no primary service 648 goto mDNS; 649 } 650 651 // get DNS name associated with primary IP, if available 652 address = copy_primary_ip(store, serviceID); 653 if (address != NULL) { 654 Boolean ok; 655 656 // start reverse DNS query using primary IP address 657 ok = ptr_query_start(address); 658 if (ok) { 659 // if query started 660 goto done; 661 } 662 } 663 664 mDNS : 665 666 // get local (multicast DNS) name, if available 667 668 name = SCDynamicStoreCopyLocalHostName(store); 669 if (name != NULL) { 670 if (_SC_CFStringIsValidNetBIOSName(name)) { 671 CFMutableDictionaryRef newDict; 672 673 my_log(LOG_INFO, "NetBIOS name (multicast DNS) = %@", name); 674 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 675 CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name); 676 CFRelease(dict); 677 dict = newDict; 678 CFRelease(name); 679 goto set; 680 } 681 CFRelease(name); 682 } 683 684 // get "default" name 685 name = copy_default_name(); 686 if (name != NULL) { 687 CFMutableDictionaryRef newDict; 688 689 my_log(LOG_INFO, "NetBIOS name (default) = %@", name); 690 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 691 CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name); 692 CFRelease(dict); 693 dict = newDict; 694 CFRelease(name); 695 } 696 697 set : 698 699 // update SMB configuration 700 smb_set_configuration(store, dict); 701 702 done : 703 704 if (address != NULL) CFRelease(address); 705 if (dict != NULL) CFRelease(dict); 706 if (serviceID != NULL) CFRelease(serviceID); 707 708 if (timer != NULL) { 709 CFRunLoopTimerInvalidate(timer); 710 CFRelease(timer); 711 timer = NULL; 712 } 713 714 return; 715} 716 717 718static void 719configuration_changed(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) 720{ 721#pragma unused(changedKeys) 722#pragma unused(info) 723 CFRunLoopTimerContext context = { 0, (void *)store, CFRetain, CFRelease, NULL }; 724 CFAbsoluteTime time_boot; 725 CFAbsoluteTime time_now ; 726 727 // if active, cancel any in-progress attempt to resolve the primary IP address 728 729 if (ptrTarget != NULL) { 730 ptr_query_stop(); 731 } 732 733 // if active, cancel any queued configuration change 734 if (timer != NULL) { 735 CFRunLoopTimerInvalidate(timer); 736 CFRelease(timer); 737 timer = NULL; 738 } 739 740 // queue configuration change 741 time_boot = boottime() + SMB_STARTUP_DELAY; 742 time_now = CFAbsoluteTimeGetCurrent() + SMB_DEBOUNCE_DELAY; 743 744 timer = CFRunLoopTimerCreate(NULL, 745 time_now > time_boot ? time_now : time_boot, 746 0, 747 0, 748 0, 749 smb_update_configuration, 750 &context); 751 CFRunLoopAddTimer(rl, timer, kCFRunLoopDefaultMode); 752 753 return; 754} 755 756 757__private_extern__ 758void 759load_smb_configuration(Boolean verbose) 760{ 761#pragma unused(verbose) 762 CFStringRef key; 763 CFMutableArrayRef keys = NULL; 764 dispatch_block_t notify_block; 765 Boolean ok; 766 CFMutableArrayRef patterns = NULL; 767 uint32_t status; 768 769 /* initialize a few globals */ 770 queue = dispatch_queue_create(SMB_CONFIGURATION_QUEUE, NULL); 771 if (queue == NULL) { 772 my_log(LOG_ERR, 773 "dispatch_queue_create() failed"); 774 goto error; 775 } 776 777 store = SCDynamicStoreCreate(NULL, CFSTR("smb-configuration"), configuration_changed, NULL); 778 if (store == NULL) { 779 my_log(LOG_ERR, 780 "SCDynamicStoreCreate() failed: %s", 781 SCErrorString(SCError())); 782 goto error; 783 } 784 785 /* establish notification keys and patterns */ 786 787 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 788 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 789 790 /* ...watch for SMB configuration changes */ 791 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 792 kSCDynamicStoreDomainState, 793 kSCEntNetSMB); 794 CFArrayAppendValue(keys, key); 795 CFRelease(key); 796 797 /* ...watch for ComputerName changes */ 798 key = SCDynamicStoreKeyCreateComputerName(NULL); 799 CFArrayAppendValue(keys, key); 800 CFRelease(key); 801 802 /* ...watch for local (multicast DNS) hostname changes */ 803 key = SCDynamicStoreKeyCreateHostNames(NULL); 804 CFArrayAppendValue(keys, key); 805 CFRelease(key); 806 807 /* register the keys/patterns */ 808 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns); 809 CFRelease(keys); 810 CFRelease(patterns); 811 if (!ok) { 812 my_log(LOG_ERR, 813 "SCDynamicStoreSetNotificationKeys() failed: %s", 814 SCErrorString(SCError())); 815 goto error; 816 } 817 818 rl = CFRunLoopGetCurrent(); 819 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 820 if (rls == NULL) { 821 my_log(LOG_ERR, 822 "SCDynamicStoreCreateRunLoopSource() failed: %s", 823 SCErrorString(SCError())); 824 goto error; 825 } 826 CFRunLoopAddSource(rl, rls, kCFRunLoopDefaultMode); 827 828 /* ...watch for primary service/interface and DNS configuration changes */ 829 notify_block = ^{ 830 CFArrayRef changes; 831 CFStringRef key; 832 833 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 834 kSCDynamicStoreDomainState, 835 kSCEntNetDNS); 836 changes = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks); 837 (*configuration_changed)(store, changes, NULL); 838 CFRelease(changes); 839 CFRelease(key); 840 841 return; 842 }; 843 status = notify_register_dispatch(_SC_NOTIFY_NETWORK_CHANGE, 844 &notify_token, 845 queue, 846 ^(int token){ 847#pragma unused(token) 848 CFRunLoopPerformBlock(rl, 849 kCFRunLoopDefaultMode, 850 notify_block); 851 CFRunLoopWakeUp(rl); 852 }); 853 if (status != NOTIFY_STATUS_OK) { 854 my_log(LOG_ERR, "notify_register_dispatch() failed: %u", status); 855 goto error; 856 } 857 858 return; 859 860 error : 861 862 if (rls != NULL) { 863 CFRunLoopRemoveSource(rl, rls, kCFRunLoopDefaultMode); 864 CFRelease(rls); 865 rls = NULL; 866 } 867 if (store != NULL) { 868 CFRelease(store); 869 store = NULL; 870 } 871 if (queue != NULL) { 872 dispatch_release(queue); 873 queue = NULL; 874 } 875 876 return; 877} 878 879 880#ifdef MAIN 881int 882main(int argc, char **argv) 883{ 884 885#ifdef DEBUG 886 CFStringRef address; 887 CFStringRef name; 888 CFStringRef serviceID; 889 SCDynamicStoreRef store; 890 891 _sc_log = FALSE; 892 if ((argc > 1) && (strcmp(argv[1], "-d") == 0)) { 893 _sc_verbose = TRUE; 894 argv++; 895 argc--; 896 } 897 898 store = SCDynamicStoreCreate(NULL, CFSTR("smb-configuration"), NULL, NULL); 899 if (store == NULL) { 900 SCPrint(TRUE, stdout, 901 CFSTR("SCDynamicStoreCreate() failed: %s\n"), 902 SCErrorString(SCError())); 903 exit(1); 904 } 905 906 // get "default" name 907 name = copy_default_name(); 908 if (name != NULL) { 909 SCPrint(TRUE, stdout, CFSTR("default name = %@\n"), name); 910 CFRelease(name); 911 } 912 913 // get primary service 914 serviceID = copy_primary_service(store); 915 if (serviceID != NULL) { 916 SCPrint(TRUE, stdout, CFSTR("primary service ID = %@\n"), serviceID); 917 } else { 918 SCPrint(TRUE, stdout, CFSTR("No primary service\n")); 919 goto done; 920 } 921 922 if ((argc == (2+1)) && (argv[1][0] == 's')) { 923 if (serviceID != NULL) CFRelease(serviceID); 924 serviceID = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8); 925 SCPrint(TRUE, stdout, CFSTR("alternate service ID = %@\n"), serviceID); 926 } 927 928 // get primary IP address 929 address = copy_primary_ip(store, serviceID); 930 CFRelease(serviceID); 931 if (address != NULL) { 932 SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address); 933 934 if ((argc == (2+1)) && (argv[1][0] == 'a')) { 935 if (address != NULL) CFRelease(address); 936 address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8); 937 SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address); 938 } 939 940 // start reverse DNS query using primary IP address 941 (void) ptr_query_start(address); 942 CFRelease(address); 943 } 944 945 done : 946 947 smb_update_configuration(NULL, (void *)store); 948 949 CFRelease(store); 950 951 CFRunLoopRun(); 952 953#else /* DEBUG */ 954 955 _sc_log = FALSE; 956 _sc_verbose = (argc > 1) ? TRUE : FALSE; 957 958 load_smb_configuration((argc > 1) ? TRUE : FALSE); 959 CFRunLoopRun(); 960 /* not reached */ 961 962#endif /* DEBUG */ 963 964 exit(0); 965 return 0; 966} 967#endif /* MAIN */