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
);