2  * Copyright (c) 2006-2009 Apple Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * Modification History 
  27  * June 26, 2006        Allan Nathanson <ajn@apple.com> 
  34 #include <sys/param.h> 
  35 #include <sys/types.h> 
  36 #include <sys/socket.h> 
  38 #include <sys/sysctl.h> 
  41 #include <net/if_dl.h> 
  42 #include <netinet/in.h> 
  43 #include <arpa/inet.h> 
  44 #include <netdb_async.h> 
  46 #include <smb_server_prefs.h> 
  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>              // for SCLog(), SCPrint() 
  54 #define HW_MODEL_LEN            64                      // Note: must be >= NETBIOS_NAME_LEN (below) 
  56 #define NETBIOS_NAME_LEN        16 
  58 #define SMB_STARTUP_DELAY       60.0 
  59 #define SMB_DEBOUNCE_DELAY      5.0 
  61 static SCDynamicStoreRef        store           
= NULL
; 
  62 static CFRunLoopSourceRef       rls             
= NULL
; 
  64 static Boolean                  dnsActive       
= FALSE
; 
  65 static CFMachPortRef            dnsPort         
= NULL
; 
  66 static struct timeval           dnsQueryStart
; 
  68 static CFRunLoopTimerRef        timer           
= NULL
; 
  70 static Boolean                  _verbose        
= FALSE
; 
  76         static enum { Unknown
, Client
, Server 
} isServer        
= Unknown
; 
  78         if (isServer 
== Unknown
) { 
  82                 ret 
= stat("/System/Library/CoreServices/ServerVersion.plist", &statbuf
); 
  83                 isServer 
= (ret 
== 0) ? Server 
: Client
; 
  86         return (isServer 
== Server
) ? TRUE 
: FALSE
; 
  93         static CFAbsoluteTime   bt      
= 0; 
  96                 int             mib
[2]  = { CTL_KERN
, KERN_BOOTTIME 
}; 
  98                 size_t          tv_len  
= sizeof(tv
); 
 100                 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &tv
, &tv_len
, NULL
, 0) == -1) { 
 101                         SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() CTL_KERN/KERN_BOOTTIME failed: %s"), strerror(errno
)); 
 102                         return kCFAbsoluteTimeIntervalSince1970
; 
 105                 // Note: we need to convert from Unix time to CF time. 
 106                 bt 
= (CFTimeInterval
)tv
.tv_sec 
- kCFAbsoluteTimeIntervalSince1970
; 
 107                 bt 
+= (1.0E-6 * (CFTimeInterval
)tv
.tv_usec
); 
 115 copy_default_name(void) 
 118         char                    hwModel
[HW_MODEL_LEN
]; 
 119         int                     mib
[]           = { CTL_HW
, HW_MODEL 
}; 
 120         size_t                  n               
= sizeof(hwModel
); 
 122         CFMutableStringRef      str
; 
 125         bzero(&hwModel
, sizeof(hwModel
)); 
 126         ret 
= sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &hwModel
, &n
, NULL
, 0); 
 128                 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno
)); 
 133         hwModel
[NETBIOS_NAME_LEN 
- 1] = '\0'; 
 135         // trim everything after (and including) a comma 
 136         cp 
= index(hwModel
, ','); 
 141         // trim any trailing digits 
 144                 if (!isdigit(hwModel
[n 
- 1])) { 
 150         // start off with the [trunated] HW model 
 151         str 
= CFStringCreateMutable(NULL
, 0); 
 152         CFStringAppendFormat(str
, NULL
, CFSTR("%s"), hwModel
); 
 155         // if there is room for at least one byte (two hex characters) 
 156         // of the MAC address than append that to the NetBIOS name. 
 158         //    NETBIOS_NAME_LEN  max length 
 159         //      -1              the last byte is reserved 
 162         if (n 
< (NETBIOS_NAME_LEN 
- 1 - 3)) { 
 163                 SCNetworkInterfaceRef   interface
; 
 165                 interface 
= _SCNetworkInterfaceCreateWithBSDName(NULL
, CFSTR("en0"), 
 166                                                                  kIncludeNoVirtualInterfaces
); 
 167                 if (interface 
!= NULL
) { 
 168                         CFMutableStringRef      en0_MAC
; 
 170                         en0_MAC 
= (CFMutableStringRef
)SCNetworkInterfaceGetHardwareAddressString(interface
); 
 171                         if (en0_MAC 
!= NULL
) { 
 174                                 // remove ":" characters from MAC address string 
 175                                 en0_MAC 
= CFStringCreateMutableCopy(NULL
, 0, en0_MAC
); 
 176                                 CFStringFindAndReplace(en0_MAC
, 
 179                                                        CFRangeMake(0, CFStringGetLength(en0_MAC
)), 
 183                                 // compute how may bytes (characters) to append 
 184                                 //    ... and limit that number to 6 
 186                                 //    NETBIOS_NAME_LEN  max length 
 187                                 //      -1              the last byte is reserved 
 191                                 n 
= ((NETBIOS_NAME_LEN 
- 1 - n 
- 1) / 2) * 2; 
 196                                 // remove what we don't want 
 197                                 en0_MAC_len 
= CFStringGetLength(en0_MAC
); 
 198                                 if (en0_MAC_len 
> n
) { 
 199                                         CFStringDelete(en0_MAC
, CFRangeMake(0, en0_MAC_len 
- n
)); 
 203                                 CFStringAppendFormat(str
, NULL
, CFSTR("-%@"), en0_MAC
); 
 207                         CFRelease(interface
); 
 211         CFStringUppercase(str
, NULL
); 
 216 static CFDictionaryRef
 
 217 smb_copy_global_configuration(SCDynamicStoreRef store
) 
 219         CFDictionaryRef dict
; 
 222         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
 223                                                          kSCDynamicStoreDomainState
, 
 225         dict 
= SCDynamicStoreCopyValue(store
, key
); 
 229                 if (isA_CFDictionary(dict
)) { 
 236         dict 
= CFDictionaryCreate(NULL
,                 // allocator 
 240                                   &kCFTypeDictionaryKeyCallBacks
, 
 241                                   &kCFTypeDictionaryValueCallBacks
); 
 247 update_pref(SCPreferencesRef prefs
, CFStringRef key
, CFTypeRef newVal
, Boolean 
*changed
) 
 251         curVal 
= SCPreferencesGetValue(prefs
, key
); 
 252         if (!_SC_CFEqual(curVal
, newVal
)) { 
 253                 if (newVal 
!= NULL
) { 
 254                         SCPreferencesSetValue(prefs
, key
, newVal
); 
 256                         SCPreferencesRemoveValue(prefs
, key
); 
 267 smb_set_configuration(SCDynamicStoreRef store
, CFDictionaryRef dict
) 
 270         Boolean                 changed         
= FALSE
; 
 271         UInt32                  dosCodepage     
= 0; 
 272         CFStringEncoding        dosEncoding     
= 0; 
 273         CFStringEncoding        macEncoding     
= kCFStringEncodingMacRoman
; 
 274         uint32_t                macRegion       
= 0; 
 276         SCPreferencesRef        prefs
; 
 279         prefs 
= SCPreferencesCreate(NULL
, CFSTR("smb-configuration"), CFSTR(kSMBPreferencesAppID
)); 
 282                       CFSTR("smb_set_configuration: SCPreferencesCreate() failed: %s"), 
 283                       SCErrorString(SCError())); 
 287         ok 
= SCPreferencesLock(prefs
, TRUE
); 
 290                       CFSTR("smb_set_configuration: SCPreferencesLock() failed: %s"), 
 291                       SCErrorString(SCError())); 
 295         if (!isMacOSXServer()) { 
 296                 // Server description 
 297                 str 
= SCDynamicStoreCopyComputerName(store
, &macEncoding
); 
 298                 update_pref(prefs
, CFSTR(kSMBPrefServerDescription
), str
, &changed
); 
 302                         if (macEncoding 
== kCFStringEncodingMacRoman
) { 
 304                                 CFDictionaryRef dict
; 
 307                                 key 
= SCDynamicStoreKeyCreateComputerName(NULL
); 
 308                                 dict 
= SCDynamicStoreCopyValue(store
, key
); 
 311                                         if (isA_CFDictionary(dict
)) { 
 315                                                 num 
= CFDictionaryGetValue(dict
, kSCPropSystemComputerNameRegion
); 
 316                                                 if (isA_CFNumber(num
) && 
 317                                                     CFNumberGetValue(num
, kCFNumberSInt32Type
, &val
)) { 
 318                                                         macRegion 
= (uint32_t)val
; 
 328                         // Important: must have root acccess (eUID==0) to access the config file! 
 329                         __CFStringGetInstallationEncodingAndRegion((uint32_t *)&macEncoding
, &macRegion
); 
 331                 _SC_dos_encoding_and_codepage(macEncoding
, macRegion
, &dosEncoding
, &dosCodepage
); 
 332                 str 
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), dosCodepage
); 
 333                 update_pref(prefs
, CFSTR(kSMBPrefDOSCodePage
), str
, &changed
); 
 338         str 
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
); 
 339         str 
= isA_CFString(str
); 
 340         update_pref(prefs
, CFSTR(kSMBPrefNetBIOSName
), str
, &changed
); 
 343         str 
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSNodeType
); 
 344         str 
= isA_CFString(str
); 
 346                 if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeBroadcast
)) { 
 348                         str 
= CFSTR(kSMBPrefNetBIOSNodeBroadcast
); 
 349                 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypePeer
)) { 
 351                         str 
= CFSTR(kSMBPrefNetBIOSNodePeer
); 
 352                 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeMixed
)) { 
 354                         str 
= CFSTR(kSMBPrefNetBIOSNodeMixed
); 
 355                 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeHybrid
)) { 
 357                         str 
= CFSTR(kSMBPrefNetBIOSNodeHybrid
); 
 362         update_pref(prefs
, CFSTR(kSMBPrefNetBIOSNodeType
), str
, &changed
); 
 365         str 
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSScope
); 
 366         str 
= isA_CFString(str
); 
 367         update_pref(prefs
, CFSTR(kSMBPrefNetBIOSScope
), str
, &changed
); 
 370         array 
= CFDictionaryGetValue(dict
, kSCPropNetSMBWINSAddresses
); 
 371         array 
= isA_CFArray(array
); 
 372         update_pref(prefs
, CFSTR(kSMBPrefWINSServerAddressList
), array
, &changed
); 
 374         // Workgroup (or domain) 
 375         str 
= CFDictionaryGetValue(dict
, kSCPropNetSMBWorkgroup
); 
 376         str 
= isA_CFString(str
); 
 377         update_pref(prefs
, CFSTR(kSMBPrefWorkgroup
), str
, &changed
); 
 380                 ok 
= SCPreferencesCommitChanges(prefs
); 
 382                         SCLog((SCError() != EROFS
), LOG_ERR
, 
 383                               CFSTR("smb_set_configuration: SCPreferencesCommitChanges() failed: %s"), 
 384                               SCErrorString(SCError())); 
 388                 ok 
= SCPreferencesApplyChanges(prefs
); 
 391                               CFSTR("smb_set_configuration: SCPreferencesApplyChanges() failed: %s"), 
 392                               SCErrorString(SCError())); 
 399         (void) SCPreferencesUnlock(prefs
); 
 406 copy_primary_service(SCDynamicStoreRef store
) 
 408         CFDictionaryRef dict
; 
 410         CFStringRef     serviceID       
= NULL
; 
 412         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
 413                                                          kSCDynamicStoreDomainState
, 
 415         dict 
= SCDynamicStoreCopyValue(store
, key
); 
 419                 if (isA_CFDictionary(dict
)) { 
 420                         serviceID 
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryService
); 
 421                         if (isA_CFString(serviceID
)) { 
 435 copy_primary_ip(SCDynamicStoreRef store
, CFStringRef serviceID
) 
 437         CFStringRef     address 
= NULL
; 
 438         CFDictionaryRef dict
; 
 441         key 
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, 
 442                                                           kSCDynamicStoreDomainState
, 
 445         dict 
= SCDynamicStoreCopyValue(store
, key
); 
 449                 if (isA_CFDictionary(dict
)) { 
 450                         CFArrayRef      addresses
; 
 452                         addresses 
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Addresses
); 
 453                         if (isA_CFArray(addresses
) && (CFArrayGetCount(addresses
) > 0)) { 
 454                                 address 
= CFArrayGetValueAtIndex(addresses
, 0); 
 455                                 if (isA_CFString(address
)) { 
 470 reverseDNSComplete(int32_t status
, char *host
, char *serv
, void *context
) 
 472         CFDictionaryRef         dict
; 
 473         struct timeval          dnsQueryComplete
; 
 474         struct timeval          dnsQueryElapsed
; 
 476         SCDynamicStoreRef       store   
= (SCDynamicStoreRef
)context
; 
 478         (void) gettimeofday(&dnsQueryComplete
, NULL
); 
 479         timersub(&dnsQueryComplete
, &dnsQueryStart
, &dnsQueryElapsed
); 
 480         SCLog(_verbose
, LOG_INFO
, 
 481               CFSTR("async DNS complete%s (query time = %d.%3.3d)"), 
 482               ((status 
== 0) && (host 
!= NULL
)) ? "" : ", host not found", 
 483               dnsQueryElapsed
.tv_sec
, 
 484               dnsQueryElapsed
.tv_usec 
/ 1000); 
 486         // get network configuration 
 487         dict 
= smb_copy_global_configuration(store
); 
 489         // use NetBIOS name from network configuration (if available) 
 490         name 
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
); 
 491         if ((name 
!= NULL
) && _SC_CFStringIsValidNetBIOSName(name
)) { 
 492                 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (network configuration) = %@"), name
); 
 496         // use reverse DNS name, if available 
 500                          * if [reverse] DNS query was successful 
 505                                 dot 
= strchr(host
, '.'); 
 506                                 name 
= CFStringCreateWithBytes(NULL
, 
 508                                                                (dot 
!= NULL
) ? dot 
- host 
: strlen(host
), 
 509                                                                kCFStringEncodingUTF8
, 
 512                                         if (_SC_CFStringIsValidNetBIOSName(name
)) { 
 513                                                 CFMutableDictionaryRef  newDict
; 
 515                                                 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (reverse DNS query) = %@"), name
); 
 516                                                 newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 517                                                 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
); 
 530 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 
 534                          * if no name available 
 542                         SCLog(TRUE
, LOG_ERR
, CFSTR("getnameinfo() failed: %s"), gai_strerror(status
)); 
 545         // try local (multicast DNS) name, if available 
 546         name 
= SCDynamicStoreCopyLocalHostName(store
); 
 548                 if (_SC_CFStringIsValidNetBIOSName(name
)) { 
 549                         CFMutableDictionaryRef  newDict
; 
 551                         SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (multicast DNS) = %@"), name
); 
 552                         newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 553                         CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
); 
 562         // use "default" name 
 563         name 
= copy_default_name(); 
 565                 CFMutableDictionaryRef  newDict
; 
 567                 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (default) = %@"), name
); 
 568                 newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 569                 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
); 
 577         // update SMB configuration 
 578         smb_set_configuration(store
, dict
); 
 580         if (host 
!= NULL
)       free(host
); 
 581         if (dict 
!= NULL
)       CFRelease(dict
); 
 582         if (serv 
!= NULL
)       free(serv
); 
 589 replyMPCopyDescription(const void *info
) 
 591         SCDynamicStoreRef       store   
= (SCDynamicStoreRef
)info
; 
 593         return CFStringCreateWithFormat(NULL
, 
 595                                         CFSTR("<getnameinfo_async_start reply MP> {store = %p}"), 
 601 getnameinfo_async_handleCFReply(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
) 
 603         mach_port_t     mp      
= MACH_PORT_NULL
; 
 606         if (port 
!= dnsPort
) { 
 607                 // we've received a callback on the async DNS port but since the 
 608                 // associated CFMachPort doesn't match than the request must have 
 609                 // already been cancelled. 
 610                 SCLog(TRUE
, LOG_ERR
, CFSTR("getnameinfo_async_handleCFReply(): port != dnsPort")); 
 614         mp 
= CFMachPortGetPort(port
); 
 615         CFMachPortInvalidate(dnsPort
); 
 619         status 
= getnameinfo_async_handle_reply(msg
); 
 620         if ((status 
== 0) && dnsActive 
&& (mp 
!= MACH_PORT_NULL
)) { 
 621                 CFMachPortContext       context 
= { 0 
 625                                                   , replyMPCopyDescription
 
 627                 CFRunLoopSourceRef      rls
; 
 629                 // if request has been re-queued 
 630                 dnsPort 
= CFMachPortCreateWithPort(NULL
, 
 632                                                    getnameinfo_async_handleCFReply
, 
 635                 rls 
= CFMachPortCreateRunLoopSource(NULL
, dnsPort
, 0); 
 636                 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); 
 645 start_dns_query(SCDynamicStoreRef store
, CFStringRef address
) 
 648         SCNetworkReachabilityFlags      flags
; 
 652         struct sockaddr_in              sin
; 
 653         struct sockaddr_in6             sin6
; 
 655         if (_SC_cfstring_to_cstring(address
, addr
, sizeof(addr
), kCFStringEncodingASCII
) == NULL
) { 
 656                 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert [primary] address")); 
 660         bzero(&sin
, sizeof(sin
)); 
 661         sin
.sin_len    
= sizeof(sin
); 
 662         sin
.sin_family 
= AF_INET
; 
 664         bzero(&sin6
, sizeof(sin6
)); 
 665         sin6
.sin6_len    
= sizeof(sin6
); 
 666         sin6
.sin6_family 
= AF_INET6
; 
 668         if (inet_aton(addr
, &sin
.sin_addr
) == 1) { 
 672                 sa 
= (struct sockaddr 
*)&sin
; 
 673         } else if (inet_pton(AF_INET6
, addr
, &sin6
.sin6_addr
) == 1) { 
 679                 p 
= strchr(addr
, '%'); 
 681                         sin6
.sin6_scope_id 
= if_nametoindex(p 
+ 1); 
 684                 sa 
= (struct sockaddr 
*)&sin6
; 
 689         ok 
= _SC_checkResolverReachabilityByAddress(&store
, &flags
, &haveDNS
, sa
); 
 691                 if (!(flags 
& kSCNetworkReachabilityFlagsReachable
) || 
 692                     (flags 
& kSCNetworkReachabilityFlagsConnectionRequired
)) { 
 693                         // if not reachable *OR* connection required 
 699                 CFMachPortContext       context 
= { 0 
 703                                                   , replyMPCopyDescription
 
 707                 CFRunLoopSourceRef      rls
; 
 709                 (void) gettimeofday(&dnsQueryStart
, NULL
); 
 711                 error 
= getnameinfo_async_start(&mp
, 
 714                                                 NI_NAMEREQD
,    // flags 
 723                 dnsPort 
= CFMachPortCreateWithPort(NULL
, 
 725                                                    getnameinfo_async_handleCFReply
, 
 728                 rls 
= CFMachPortCreateRunLoopSource(NULL
, dnsPort
, 0); 
 729                 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); 
 740 smb_update_configuration(__unused CFRunLoopTimerRef _timer
, void *info
) 
 742         CFStringRef             address         
= NULL
; 
 743         CFDictionaryRef         dict
; 
 745         CFStringRef             serviceID       
= NULL
; 
 746         SCDynamicStoreRef       store           
= (SCDynamicStoreRef
)info
; 
 748         // get network configuration 
 749         dict 
= smb_copy_global_configuration(store
); 
 751         // use NetBIOS name from network configuration (if available) 
 752         name 
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
); 
 753         if ((name 
!= NULL
) && _SC_CFStringIsValidNetBIOSName(name
)) { 
 754                 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (network configuration) = %@"), name
); 
 758         // get primary service ID 
 759         serviceID 
= copy_primary_service(store
); 
 760         if (serviceID 
== NULL
) { 
 761                 // if no primary service 
 765         // get DNS name associated with primary IP, if available 
 766         address 
= copy_primary_ip(store
, serviceID
); 
 767         if (address 
!= NULL
) { 
 770                 // start reverse DNS query using primary IP address 
 771                 ok 
= start_dns_query(store
, address
); 
 780         // get local (multicast DNS) name, if available 
 782         name 
= SCDynamicStoreCopyLocalHostName(store
); 
 784                 if (_SC_CFStringIsValidNetBIOSName(name
)) { 
 785                         CFMutableDictionaryRef  newDict
; 
 787                         SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (multicast DNS) = %@"), name
); 
 788                         newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 789                         CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
); 
 798         // get "default" name 
 799         name 
= copy_default_name(); 
 801                 CFMutableDictionaryRef  newDict
; 
 803                 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (default) = %@"), name
); 
 804                 newDict 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 805                 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
); 
 813         // update SMB configuration 
 814         smb_set_configuration(store
, dict
); 
 818         if (address 
!= NULL
)    CFRelease(address
); 
 819         if (dict 
!= NULL
)       CFRelease(dict
); 
 820         if (serviceID 
!= NULL
)  CFRelease(serviceID
); 
 823                 CFRunLoopTimerInvalidate(timer
); 
 833 configuration_changed(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
) 
 835         CFRunLoopTimerContext   context 
= { 0, (void *)store
, CFRetain
, CFRelease
, NULL 
}; 
 836         CFAbsoluteTime          time_boot
; 
 837         CFAbsoluteTime          time_now 
; 
 839         // if active, cancel any in-progress attempt to resolve the primary IP address 
 840         if (dnsPort 
!= NULL
) { 
 841                 mach_port_t     mp      
= CFMachPortGetPort(dnsPort
); 
 843                 /* cancel the outstanding DNS query */ 
 844                 CFMachPortInvalidate(dnsPort
); 
 848                 getnameinfo_async_cancel(mp
); 
 851         // if active, cancel any queued configuration change 
 853                 CFRunLoopTimerInvalidate(timer
); 
 858         // queue configuration change 
 859         time_boot 
= boottime() + SMB_STARTUP_DELAY
; 
 860         time_now  
= CFAbsoluteTimeGetCurrent() + SMB_DEBOUNCE_DELAY
; 
 862         timer 
= CFRunLoopTimerCreate(NULL
, 
 863                                      time_now 
> time_boot 
? time_now 
: time_boot
, 
 867                                      smb_update_configuration
, 
 869         CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
); 
 877 load_smb_configuration(Boolean verbose
) 
 880         CFMutableArrayRef       keys            
= NULL
; 
 881         CFMutableArrayRef       patterns        
= NULL
; 
 887         /* initialize a few globals */ 
 889         store 
= SCDynamicStoreCreate(NULL
, CFSTR("smb-configuration"), configuration_changed
, NULL
); 
 892                       CFSTR("SCDynamicStoreCreate() failed: %s"), 
 893                       SCErrorString(SCError())); 
 897         /* establish notification keys and patterns */ 
 899         keys     
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 900         patterns 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 902         /* ...watch for primary service / interface changes */ 
 903         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
 904                                                          kSCDynamicStoreDomainState
, 
 906         CFArrayAppendValue(keys
, key
); 
 909         /* ...watch for DNS configuration changes */ 
 910         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
 911                                                          kSCDynamicStoreDomainState
, 
 913         CFArrayAppendValue(keys
, key
); 
 916         /* ...watch for SMB configuration changes */ 
 917         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
 918                                                          kSCDynamicStoreDomainState
, 
 920         CFArrayAppendValue(keys
, key
); 
 923         /* ...watch for ComputerName changes */ 
 924         key 
= SCDynamicStoreKeyCreateComputerName(NULL
); 
 925         CFArrayAppendValue(keys
, key
); 
 928         /* ...watch for local (multicast DNS) hostname changes */ 
 929         key 
= SCDynamicStoreKeyCreateHostNames(NULL
); 
 930         CFArrayAppendValue(keys
, key
); 
 933         /* register the keys/patterns */ 
 934         if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
)) { 
 936                       CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"), 
 937                       SCErrorString(SCError())); 
 941         rls 
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0); 
 944                       CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"), 
 945                       SCErrorString(SCError())); 
 948         CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); 
 956         if (keys 
!= NULL
)       CFRelease(keys
); 
 957         if (patterns 
!= NULL
)   CFRelease(patterns
); 
 958         if (store 
!= NULL
)      CFRelease(store
); 
 965 main(int argc
, char **argv
) 
 971         CFStringRef             serviceID
; 
 972         SCDynamicStoreRef       store
; 
 975         if ((argc 
> 1) && (strcmp(argv
[1], "-d") == 0)) { 
 981         store 
= SCDynamicStoreCreate(NULL
, CFSTR("smb-configuration"), NULL
, NULL
); 
 983                 SCPrint(TRUE
, stdout
, 
 984                         CFSTR("SCDynamicStoreCreate() failed: %s\n"), 
 985                         SCErrorString(SCError())); 
 989         // get "default" name 
 990         name 
= copy_default_name(); 
 992                 SCPrint(TRUE
, stdout
, CFSTR("default name = %@\n"), name
); 
 996         // get primary service 
 997         serviceID 
= copy_primary_service(store
); 
 998         if (serviceID 
!= NULL
) { 
 999                 SCPrint(TRUE
, stdout
, CFSTR("primary service ID = %@\n"), serviceID
); 
1001                 SCPrint(TRUE
, stdout
, CFSTR("No primary service\n")); 
1005         if ((argc 
== (2+1)) && (argv
[1][0] == 's')) { 
1006                 if (serviceID 
!= NULL
)  CFRelease(serviceID
); 
1007                 serviceID 
= CFStringCreateWithCString(NULL
, argv
[2], kCFStringEncodingUTF8
); 
1008                 SCPrint(TRUE
, stdout
, CFSTR("alternate service ID = %@\n"), serviceID
); 
1011         // get primary IP address 
1012         address 
= copy_primary_ip(store
, serviceID
); 
1013         CFRelease(serviceID
); 
1014         if (address 
!= NULL
) { 
1015                 SCPrint(TRUE
, stdout
, CFSTR("primary address = %@\n"), address
); 
1017                 if ((argc 
== (2+1)) && (argv
[1][0] == 'a')) { 
1018                         if (address 
!= NULL
)    CFRelease(address
); 
1019                         address 
= CFStringCreateWithCString(NULL
, argv
[2], kCFStringEncodingUTF8
); 
1020                         SCPrint(TRUE
, stdout
, CFSTR("alternate primary address = %@\n"), address
); 
1023                 // start reverse DNS query using primary IP address 
1024                 (void) start_dns_query(store
, address
); 
1030         smb_update_configuration(NULL
, (void *)store
); 
1039         _sc_verbose 
= (argc 
> 1) ? TRUE 
: FALSE
; 
1041         load_smb_configuration((argc 
> 1) ? TRUE 
: FALSE
);