2 * Copyright (c) 2006-2012 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 #include "ip_plugin.h"
56 #define HW_MODEL_LEN 64 // Note: must be >= NETBIOS_NAME_LEN (below)
58 #define NETBIOS_NAME_LEN 16
60 #define SMB_STARTUP_DELAY 60.0
61 #define SMB_DEBOUNCE_DELAY 5.0
63 static SCDynamicStoreRef store
= NULL
;
64 static CFRunLoopSourceRef rls
= NULL
;
66 static Boolean dnsActive
= FALSE
;
67 static CFMachPortRef dnsPort
= NULL
;
68 static struct timeval dnsQueryStart
;
70 static CFRunLoopTimerRef timer
= NULL
;
72 static Boolean _verbose
= FALSE
;
78 static enum { Unknown
, Client
, Server
} isServer
= Unknown
;
80 if (isServer
== Unknown
) {
84 ret
= stat("/System/Library/CoreServices/ServerVersion.plist", &statbuf
);
85 isServer
= (ret
== 0) ? Server
: Client
;
88 return (isServer
== Server
) ? TRUE
: FALSE
;
95 static CFAbsoluteTime bt
= 0;
98 int mib
[2] = { CTL_KERN
, KERN_BOOTTIME
};
100 size_t tv_len
= sizeof(tv
);
102 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &tv
, &tv_len
, NULL
, 0) == -1) {
103 my_log(LOG_ERR
, "sysctl() CTL_KERN/KERN_BOOTTIME failed: %s", strerror(errno
));
104 return kCFAbsoluteTimeIntervalSince1970
;
107 // Note: we need to convert from Unix time to CF time.
108 bt
= (CFTimeInterval
)tv
.tv_sec
- kCFAbsoluteTimeIntervalSince1970
;
109 bt
+= (1.0E-6 * (CFTimeInterval
)tv
.tv_usec
);
117 copy_default_name(void)
120 char hwModel
[HW_MODEL_LEN
];
121 int mib
[] = { CTL_HW
, HW_MODEL
};
122 size_t n
= sizeof(hwModel
);
124 CFMutableStringRef str
;
127 bzero(&hwModel
, sizeof(hwModel
));
128 ret
= sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &hwModel
, &n
, NULL
, 0);
130 my_log(LOG_ERR
, "sysctl() CTL_HW/HW_MODEL failed: %s", strerror(errno
));
135 hwModel
[NETBIOS_NAME_LEN
- 1] = '\0';
137 // trim everything after (and including) a comma
138 cp
= index(hwModel
, ',');
143 // trim any trailing digits
146 if (!isdigit(hwModel
[n
- 1])) {
152 // start off with the [trunated] HW model
153 str
= CFStringCreateMutable(NULL
, 0);
154 CFStringAppendFormat(str
, NULL
, CFSTR("%s"), hwModel
);
157 // if there is room for at least one byte (two hex characters)
158 // of the MAC address than append that to the NetBIOS name.
160 // NETBIOS_NAME_LEN max length
161 // -1 the last byte is reserved
164 if (n
< (NETBIOS_NAME_LEN
- 1 - 3)) {
165 SCNetworkInterfaceRef interface
;
167 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, CFSTR("en0"),
168 kIncludeNoVirtualInterfaces
);
169 if (interface
!= NULL
) {
170 CFMutableStringRef en0_MAC
;
172 en0_MAC
= (CFMutableStringRef
)SCNetworkInterfaceGetHardwareAddressString(interface
);
173 if (en0_MAC
!= NULL
) {
176 // remove ":" characters from MAC address string
177 en0_MAC
= CFStringCreateMutableCopy(NULL
, 0, en0_MAC
);
178 CFStringFindAndReplace(en0_MAC
,
181 CFRangeMake(0, CFStringGetLength(en0_MAC
)),
185 // compute how may bytes (characters) to append
186 // ... and limit that number to 6
188 // NETBIOS_NAME_LEN max length
189 // -1 the last byte is reserved
193 n
= ((NETBIOS_NAME_LEN
- 1 - n
- 1) / 2) * 2;
198 // remove what we don't want
199 en0_MAC_len
= CFStringGetLength(en0_MAC
);
200 if (en0_MAC_len
> n
) {
201 CFStringDelete(en0_MAC
, CFRangeMake(0, en0_MAC_len
- n
));
205 CFStringAppendFormat(str
, NULL
, CFSTR("-%@"), en0_MAC
);
209 CFRelease(interface
);
213 CFStringUppercase(str
, NULL
);
218 static CFDictionaryRef
219 smb_copy_global_configuration(SCDynamicStoreRef store
)
221 CFDictionaryRef dict
;
224 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
225 kSCDynamicStoreDomainState
,
227 dict
= SCDynamicStoreCopyValue(store
, key
);
231 if (isA_CFDictionary(dict
)) {
238 dict
= CFDictionaryCreate(NULL
, // allocator
242 &kCFTypeDictionaryKeyCallBacks
,
243 &kCFTypeDictionaryValueCallBacks
);
249 update_pref(SCPreferencesRef prefs
, CFStringRef key
, CFTypeRef newVal
, Boolean
*changed
)
253 curVal
= SCPreferencesGetValue(prefs
, key
);
254 if (!_SC_CFEqual(curVal
, newVal
)) {
255 if (newVal
!= NULL
) {
256 SCPreferencesSetValue(prefs
, key
, newVal
);
258 SCPreferencesRemoveValue(prefs
, key
);
269 smb_set_configuration(SCDynamicStoreRef store
, CFDictionaryRef dict
)
272 Boolean changed
= FALSE
;
273 UInt32 dosCodepage
= 0;
274 CFStringEncoding dosEncoding
= 0;
275 CFStringEncoding macEncoding
= kCFStringEncodingMacRoman
;
276 uint32_t macRegion
= 0;
278 SCPreferencesRef prefs
;
281 prefs
= SCPreferencesCreate(NULL
, CFSTR("smb-configuration"), CFSTR(kSMBPreferencesAppID
));
284 "smb_set_configuration: SCPreferencesCreate() failed: %s",
285 SCErrorString(SCError()));
289 ok
= SCPreferencesLock(prefs
, TRUE
);
292 "smb_set_configuration: SCPreferencesLock() failed: %s",
293 SCErrorString(SCError()));
297 if (!isMacOSXServer()) {
298 // Server description
299 str
= SCDynamicStoreCopyComputerName(store
, &macEncoding
);
300 update_pref(prefs
, CFSTR(kSMBPrefServerDescription
), str
, &changed
);
304 if (macEncoding
== kCFStringEncodingMacRoman
) {
306 CFDictionaryRef dict
;
309 key
= SCDynamicStoreKeyCreateComputerName(NULL
);
310 dict
= SCDynamicStoreCopyValue(store
, key
);
313 if (isA_CFDictionary(dict
)) {
317 num
= CFDictionaryGetValue(dict
, kSCPropSystemComputerNameRegion
);
318 if (isA_CFNumber(num
) &&
319 CFNumberGetValue(num
, kCFNumberSInt32Type
, &val
)) {
320 macRegion
= (uint32_t)val
;
330 // Important: must have root acccess (eUID==0) to access the config file!
331 __CFStringGetInstallationEncodingAndRegion((uint32_t *)&macEncoding
, &macRegion
);
333 _SC_dos_encoding_and_codepage(macEncoding
, macRegion
, &dosEncoding
, &dosCodepage
);
334 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), (unsigned int)dosCodepage
);
336 update_pref(prefs
, CFSTR(kSMBPrefDOSCodePage
), str
, &changed
);
341 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
);
342 str
= isA_CFString(str
);
343 update_pref(prefs
, CFSTR(kSMBPrefNetBIOSName
), str
, &changed
);
346 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSNodeType
);
347 str
= isA_CFString(str
);
349 if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeBroadcast
)) {
351 str
= CFSTR(kSMBPrefNetBIOSNodeBroadcast
);
352 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypePeer
)) {
354 str
= CFSTR(kSMBPrefNetBIOSNodePeer
);
355 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeMixed
)) {
357 str
= CFSTR(kSMBPrefNetBIOSNodeMixed
);
358 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeHybrid
)) {
360 str
= CFSTR(kSMBPrefNetBIOSNodeHybrid
);
365 update_pref(prefs
, CFSTR(kSMBPrefNetBIOSNodeType
), str
, &changed
);
367 #ifdef ADD_NETBIOS_SCOPE
369 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSScope
);
370 str
= isA_CFString(str
);
371 update_pref(prefs
, CFSTR(kSMBPrefNetBIOSScope
), str
, &changed
);
372 #endif // ADD_NETBIOS_SCOPE
375 array
= CFDictionaryGetValue(dict
, kSCPropNetSMBWINSAddresses
);
376 array
= isA_CFArray(array
);
377 update_pref(prefs
, CFSTR(kSMBPrefWINSServerAddressList
), array
, &changed
);
379 // Workgroup (or domain)
380 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBWorkgroup
);
381 str
= isA_CFString(str
);
382 update_pref(prefs
, CFSTR(kSMBPrefWorkgroup
), str
, &changed
);
385 ok
= SCPreferencesCommitChanges(prefs
);
387 if ((SCError() != EROFS
)) {
389 "smb_set_configuration: SCPreferencesCommitChanges() failed: %s",
390 SCErrorString(SCError()));
395 ok
= SCPreferencesApplyChanges(prefs
);
398 "smb_set_configuration: SCPreferencesApplyChanges() failed: %s",
399 SCErrorString(SCError()));
406 (void) SCPreferencesUnlock(prefs
);
413 copy_primary_service(SCDynamicStoreRef store
)
415 CFDictionaryRef dict
;
417 CFStringRef serviceID
= NULL
;
419 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
420 kSCDynamicStoreDomainState
,
422 dict
= SCDynamicStoreCopyValue(store
, key
);
426 if (isA_CFDictionary(dict
)) {
427 serviceID
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryService
);
428 if (isA_CFString(serviceID
)) {
442 copy_primary_ip(SCDynamicStoreRef store
, CFStringRef serviceID
)
444 CFStringRef address
= NULL
;
445 CFDictionaryRef dict
;
448 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
449 kSCDynamicStoreDomainState
,
452 dict
= SCDynamicStoreCopyValue(store
, key
);
456 if (isA_CFDictionary(dict
)) {
457 CFArrayRef addresses
;
459 addresses
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Addresses
);
460 if (isA_CFArray(addresses
) && (CFArrayGetCount(addresses
) > 0)) {
461 address
= CFArrayGetValueAtIndex(addresses
, 0);
462 if (isA_CFString(address
)) {
477 reverseDNSComplete(int32_t status
, char *host
, char *serv
, void *context
)
479 CFDictionaryRef dict
;
480 struct timeval dnsQueryComplete
;
481 struct timeval dnsQueryElapsed
;
483 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
485 (void) gettimeofday(&dnsQueryComplete
, NULL
);
486 timersub(&dnsQueryComplete
, &dnsQueryStart
, &dnsQueryElapsed
);
489 "async DNS complete%s (query time = %d.%3.3d)",
490 ((status
== 0) && (host
!= NULL
)) ? "" : ", host not found",
491 dnsQueryElapsed
.tv_sec
,
492 dnsQueryElapsed
.tv_usec
/ 1000);
495 // get network configuration
496 dict
= smb_copy_global_configuration(store
);
498 // use NetBIOS name from network configuration (if available)
499 name
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
);
500 if ((name
!= NULL
) && _SC_CFStringIsValidNetBIOSName(name
)) {
501 my_log(LOG_INFO
, "NetBIOS name (network configuration) = %@", name
);
505 // use reverse DNS name, if available
509 * if [reverse] DNS query was successful
514 dot
= strchr(host
, '.');
515 name
= CFStringCreateWithBytes(NULL
,
517 (dot
!= NULL
) ? dot
- host
: strlen(host
),
518 kCFStringEncodingUTF8
,
521 if (_SC_CFStringIsValidNetBIOSName(name
)) {
522 CFMutableDictionaryRef newDict
;
524 my_log(LOG_INFO
, "NetBIOS name (reverse DNS query) = %@", name
);
525 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
526 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
539 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
543 * if no name available
551 my_log(LOG_ERR
,"getnameinfo() failed: %s", gai_strerror(status
));
554 // try local (multicast DNS) name, if available
555 name
= SCDynamicStoreCopyLocalHostName(store
);
557 if (_SC_CFStringIsValidNetBIOSName(name
)) {
558 CFMutableDictionaryRef newDict
;
560 my_log(LOG_INFO
, "NetBIOS name (multicast DNS) = %@", name
);
561 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
562 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
571 // use "default" name
572 name
= copy_default_name();
574 CFMutableDictionaryRef newDict
;
576 my_log(LOG_INFO
, "NetBIOS name (default) = %@", name
);
577 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
578 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
586 // update SMB configuration
587 smb_set_configuration(store
, dict
);
589 if (host
!= NULL
) free(host
);
590 if (dict
!= NULL
) CFRelease(dict
);
591 if (serv
!= NULL
) free(serv
);
598 replyMPCopyDescription(const void *info
)
600 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
602 return CFStringCreateWithFormat(NULL
,
604 CFSTR("<getnameinfo_async_start reply MP> {store = %p}"),
610 getnameinfo_async_handleCFReply(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
612 mach_port_t mp
= MACH_PORT_NULL
;
615 if (port
!= dnsPort
) {
616 // we've received a callback on the async DNS port but since the
617 // associated CFMachPort doesn't match than the request must have
618 // already been cancelled.
619 my_log(LOG_ERR
, "getnameinfo_async_handleCFReply(): port != dnsPort");
623 mp
= CFMachPortGetPort(port
);
624 CFMachPortInvalidate(dnsPort
);
628 status
= getnameinfo_async_handle_reply(msg
);
629 if ((status
== 0) && dnsActive
&& (mp
!= MACH_PORT_NULL
)) {
630 CFMachPortContext context
= { 0
634 , replyMPCopyDescription
636 CFRunLoopSourceRef rls
;
638 // if request has been re-queued
639 dnsPort
= _SC_CFMachPortCreateWithPort("IPMonitor/smb-configuration/re-queue",
641 getnameinfo_async_handleCFReply
,
643 rls
= CFMachPortCreateRunLoopSource(NULL
, dnsPort
, 0);
644 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
653 start_dns_query(SCDynamicStoreRef store
, CFStringRef address
)
657 struct sockaddr_in sin
;
658 struct sockaddr_in6 sin6
;
661 SCNetworkReachabilityFlags flags
;
665 if (_SC_cfstring_to_cstring(address
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
666 my_log(LOG_ERR
, "could not convert [primary] address");
670 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
671 /* if not an IP[v6] address */
672 my_log(LOG_ERR
, "could not parse [primary] address");
676 ok
= _SC_checkResolverReachabilityByAddress(&store
, &flags
, &haveDNS
, &addr
.sa
);
678 if (!(flags
& kSCNetworkReachabilityFlagsReachable
) ||
679 (flags
& kSCNetworkReachabilityFlagsConnectionRequired
)) {
680 // if not reachable *OR* connection required
686 CFMachPortContext context
= { 0
690 , replyMPCopyDescription
694 CFRunLoopSourceRef rls
;
696 (void) gettimeofday(&dnsQueryStart
, NULL
);
698 error
= getnameinfo_async_start(&mp
,
701 NI_NAMEREQD
, // flags
710 dnsPort
= _SC_CFMachPortCreateWithPort("IPMonitor/smb-configuration",
712 getnameinfo_async_handleCFReply
,
714 rls
= CFMachPortCreateRunLoopSource(NULL
, dnsPort
, 0);
715 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
726 smb_update_configuration(__unused CFRunLoopTimerRef _timer
, void *info
)
728 CFStringRef address
= NULL
;
729 CFDictionaryRef dict
;
731 CFStringRef serviceID
= NULL
;
732 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
734 // get network configuration
735 dict
= smb_copy_global_configuration(store
);
737 // use NetBIOS name from network configuration (if available)
738 name
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
);
739 if ((name
!= NULL
) && _SC_CFStringIsValidNetBIOSName(name
)) {
740 my_log(LOG_INFO
, "NetBIOS name (network configuration) = %@", name
);
744 // get primary service ID
745 serviceID
= copy_primary_service(store
);
746 if (serviceID
== NULL
) {
747 // if no primary service
751 // get DNS name associated with primary IP, if available
752 address
= copy_primary_ip(store
, serviceID
);
753 if (address
!= NULL
) {
756 // start reverse DNS query using primary IP address
757 ok
= start_dns_query(store
, address
);
766 // get local (multicast DNS) name, if available
768 name
= SCDynamicStoreCopyLocalHostName(store
);
770 if (_SC_CFStringIsValidNetBIOSName(name
)) {
771 CFMutableDictionaryRef newDict
;
773 my_log(LOG_INFO
, "NetBIOS name (multicast DNS) = %@", name
);
774 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
775 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
784 // get "default" name
785 name
= copy_default_name();
787 CFMutableDictionaryRef newDict
;
789 my_log(LOG_INFO
, "NetBIOS name (default) = %@", name
);
790 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
791 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
799 // update SMB configuration
800 smb_set_configuration(store
, dict
);
804 if (address
!= NULL
) CFRelease(address
);
805 if (dict
!= NULL
) CFRelease(dict
);
806 if (serviceID
!= NULL
) CFRelease(serviceID
);
809 CFRunLoopTimerInvalidate(timer
);
819 configuration_changed(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
821 CFRunLoopTimerContext context
= { 0, (void *)store
, CFRetain
, CFRelease
, NULL
};
822 CFAbsoluteTime time_boot
;
823 CFAbsoluteTime time_now
;
825 // if active, cancel any in-progress attempt to resolve the primary IP address
826 if (dnsPort
!= NULL
) {
827 mach_port_t mp
= CFMachPortGetPort(dnsPort
);
829 /* cancel the outstanding DNS query */
830 CFMachPortInvalidate(dnsPort
);
834 getnameinfo_async_cancel(mp
);
837 // if active, cancel any queued configuration change
839 CFRunLoopTimerInvalidate(timer
);
844 // queue configuration change
845 time_boot
= boottime() + SMB_STARTUP_DELAY
;
846 time_now
= CFAbsoluteTimeGetCurrent() + SMB_DEBOUNCE_DELAY
;
848 timer
= CFRunLoopTimerCreate(NULL
,
849 time_now
> time_boot
? time_now
: time_boot
,
853 smb_update_configuration
,
855 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
863 load_smb_configuration(Boolean verbose
)
866 CFMutableArrayRef keys
= NULL
;
867 CFMutableArrayRef patterns
= NULL
;
873 /* initialize a few globals */
875 store
= SCDynamicStoreCreate(NULL
, CFSTR("smb-configuration"), configuration_changed
, NULL
);
878 "SCDynamicStoreCreate() failed: %s",
879 SCErrorString(SCError()));
883 /* establish notification keys and patterns */
885 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
886 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
888 /* ...watch for primary service / interface changes */
889 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
890 kSCDynamicStoreDomainState
,
892 CFArrayAppendValue(keys
, key
);
895 /* ...watch for DNS configuration changes */
896 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
897 kSCDynamicStoreDomainState
,
899 CFArrayAppendValue(keys
, key
);
902 /* ...watch for SMB configuration changes */
903 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
904 kSCDynamicStoreDomainState
,
906 CFArrayAppendValue(keys
, key
);
909 /* ...watch for ComputerName changes */
910 key
= SCDynamicStoreKeyCreateComputerName(NULL
);
911 CFArrayAppendValue(keys
, key
);
914 /* ...watch for local (multicast DNS) hostname changes */
915 key
= SCDynamicStoreKeyCreateHostNames(NULL
);
916 CFArrayAppendValue(keys
, key
);
919 /* register the keys/patterns */
920 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
)) {
922 "SCDynamicStoreSetNotificationKeys() failed: %s",
923 SCErrorString(SCError()));
927 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
930 "SCDynamicStoreCreateRunLoopSource() failed: %s",
931 SCErrorString(SCError()));
934 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
942 if (keys
!= NULL
) CFRelease(keys
);
943 if (patterns
!= NULL
) CFRelease(patterns
);
944 if (store
!= NULL
) CFRelease(store
);
951 main(int argc
, char **argv
)
957 CFStringRef serviceID
;
958 SCDynamicStoreRef store
;
961 if ((argc
> 1) && (strcmp(argv
[1], "-d") == 0)) {
967 store
= SCDynamicStoreCreate(NULL
, CFSTR("smb-configuration"), NULL
, NULL
);
969 SCPrint(TRUE
, stdout
,
970 CFSTR("SCDynamicStoreCreate() failed: %s\n"),
971 SCErrorString(SCError()));
975 // get "default" name
976 name
= copy_default_name();
978 SCPrint(TRUE
, stdout
, CFSTR("default name = %@\n"), name
);
982 // get primary service
983 serviceID
= copy_primary_service(store
);
984 if (serviceID
!= NULL
) {
985 SCPrint(TRUE
, stdout
, CFSTR("primary service ID = %@\n"), serviceID
);
987 SCPrint(TRUE
, stdout
, CFSTR("No primary service\n"));
991 if ((argc
== (2+1)) && (argv
[1][0] == 's')) {
992 if (serviceID
!= NULL
) CFRelease(serviceID
);
993 serviceID
= CFStringCreateWithCString(NULL
, argv
[2], kCFStringEncodingUTF8
);
994 SCPrint(TRUE
, stdout
, CFSTR("alternate service ID = %@\n"), serviceID
);
997 // get primary IP address
998 address
= copy_primary_ip(store
, serviceID
);
999 CFRelease(serviceID
);
1000 if (address
!= NULL
) {
1001 SCPrint(TRUE
, stdout
, CFSTR("primary address = %@\n"), address
);
1003 if ((argc
== (2+1)) && (argv
[1][0] == 'a')) {
1004 if (address
!= NULL
) CFRelease(address
);
1005 address
= CFStringCreateWithCString(NULL
, argv
[2], kCFStringEncodingUTF8
);
1006 SCPrint(TRUE
, stdout
, CFSTR("alternate primary address = %@\n"), address
);
1009 // start reverse DNS query using primary IP address
1010 (void) start_dns_query(store
, address
);
1016 smb_update_configuration(NULL
, (void *)store
);
1025 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1027 load_smb_configuration((argc
> 1) ? TRUE
: FALSE
);