2 * Copyright (c) 2006, 2007 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>
37 #include <sys/sysctl.h>
40 #include <net/if_dl.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb_async.h>
45 #include <smb_server_prefs.h>
47 #include <CoreFoundation/CoreFoundation.h>
48 #include <CoreFoundation/CFStringDefaultEncoding.h> // for __CFStringGetInstallationEncodingAndRegion()
49 #include <SystemConfiguration/SystemConfiguration.h>
50 #include <SystemConfiguration/SCValidation.h>
51 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
53 #define SMB_STARTUP_DELAY 60.0
54 #define SMB_DEBOUNCE_DELAY 5.0
56 /* SPI (from SCNetworkReachability.c) */
58 _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef
*storeP
,
59 SCNetworkConnectionFlags
*flags
,
64 static SCDynamicStoreRef store
= NULL
;
65 static CFRunLoopSourceRef rls
= NULL
;
67 static Boolean dnsActive
= FALSE
;
68 static CFMachPortRef dnsPort
= NULL
;
69 static CFRunLoopSourceRef dnsRLS
= NULL
;
70 static struct timeval dnsQueryStart
;
72 static CFRunLoopTimerRef timer
= NULL
;
74 static Boolean _verbose
= FALSE
;
80 static CFAbsoluteTime bt
= 0;
83 int mib
[2] = { CTL_KERN
, KERN_BOOTTIME
};
85 size_t tv_len
= sizeof(tv
);
87 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &tv
, &tv_len
, NULL
, 0) == -1) {
88 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() CTL_KERN/KERN_BOOTTIME failed: %s"), strerror(errno
));
89 return kCFAbsoluteTimeIntervalSince1970
;
92 // Note: we need to convert from Unix time to CF time.
93 bt
= (CFTimeInterval
)tv
.tv_sec
- kCFAbsoluteTimeIntervalSince1970
;
94 bt
+= (1.0E-6 * (CFTimeInterval
)tv
.tv_usec
);
102 copy_default_name(void)
105 SCNetworkInterfaceRef interface
;
106 CFMutableStringRef name
= NULL
;
108 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, CFSTR("en0"),
109 kIncludeNoVirtualInterfaces
);
110 if (interface
== NULL
) {
114 address
= SCNetworkInterfaceGetHardwareAddressString(interface
);
115 if (address
== NULL
) {
119 name
= CFStringCreateMutableCopy(NULL
, 0, address
);
120 CFStringFindAndReplace(name
,
123 CFRangeMake(0, CFStringGetLength(name
)),
125 CFStringInsert(name
, 0, CFSTR("MAC"));
126 CFStringUppercase(name
, NULL
);
130 if (interface
!= NULL
) CFRelease(interface
);
135 static CFDictionaryRef
136 smb_copy_global_configuration(SCDynamicStoreRef store
)
138 CFDictionaryRef dict
;
141 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
142 kSCDynamicStoreDomainState
,
144 dict
= SCDynamicStoreCopyValue(store
, key
);
148 if (isA_CFDictionary(dict
)) {
155 dict
= CFDictionaryCreate(NULL
, // allocator
159 &kCFTypeDictionaryKeyCallBacks
,
160 &kCFTypeDictionaryValueCallBacks
);
166 update_pref(SCPreferencesRef prefs
, CFStringRef key
, CFTypeRef newVal
, Boolean
*changed
)
170 curVal
= SCPreferencesGetValue(prefs
, key
);
171 if (!_SC_CFEqual(curVal
, newVal
)) {
172 if (newVal
!= NULL
) {
173 SCPreferencesSetValue(prefs
, key
, newVal
);
175 SCPreferencesRemoveValue(prefs
, key
);
186 smb_set_configuration(SCDynamicStoreRef store
, CFDictionaryRef dict
)
189 Boolean changed
= FALSE
;
190 UInt32 dosCodepage
= 0;
191 CFStringEncoding dosEncoding
= 0;
192 CFStringEncoding macEncoding
= kCFStringEncodingMacRoman
;
193 uint32_t macRegion
= 0;
195 SCPreferencesRef prefs
;
198 prefs
= SCPreferencesCreate(NULL
, CFSTR("smb-configuration"), CFSTR(kSMBPreferencesAppID
));
201 CFSTR("smb_set_configuration: SCPreferencesCreate() failed: %s"),
202 SCErrorString(SCError()));
206 ok
= SCPreferencesLock(prefs
, TRUE
);
209 CFSTR("smb_set_configuration: SCPreferencesLock() failed: %s"),
210 SCErrorString(SCError()));
214 // Server description
215 str
= SCDynamicStoreCopyComputerName(store
, &macEncoding
);
216 update_pref(prefs
, CFSTR(kSMBPrefServerDescription
), str
, &changed
);
220 if (macEncoding
== kCFStringEncodingMacRoman
) {
222 CFDictionaryRef dict
;
225 key
= SCDynamicStoreKeyCreateComputerName(NULL
);
226 dict
= SCDynamicStoreCopyValue(store
, key
);
229 if (isA_CFDictionary(dict
)) {
233 num
= CFDictionaryGetValue(dict
, kSCPropSystemComputerNameRegion
);
234 if (isA_CFNumber(num
) &&
235 CFNumberGetValue(num
, kCFNumberSInt32Type
, &val
)) {
236 macRegion
= (uint32_t)val
;
246 // Important: must have root acccess (eUID==0) to access the config file!
247 __CFStringGetInstallationEncodingAndRegion((uint32_t *)&macEncoding
, &macRegion
);
249 _SC_dos_encoding_and_codepage(macEncoding
, macRegion
, &dosEncoding
, &dosCodepage
);
250 str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), dosCodepage
);
251 update_pref(prefs
, CFSTR(kSMBPrefDOSCodePage
), str
, &changed
);
255 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
);
256 str
= isA_CFString(str
);
257 update_pref(prefs
, CFSTR(kSMBPrefNetBIOSName
), str
, &changed
);
260 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSNodeType
);
261 str
= isA_CFString(str
);
263 if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeBroadcast
)) {
265 str
= CFSTR(kSMBPrefNetBIOSNodeBroadcast
);
266 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypePeer
)) {
268 str
= CFSTR(kSMBPrefNetBIOSNodePeer
);
269 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeMixed
)) {
271 str
= CFSTR(kSMBPrefNetBIOSNodeMixed
);
272 } else if (CFEqual(str
, kSCValNetSMBNetBIOSNodeTypeHybrid
)) {
274 str
= CFSTR(kSMBPrefNetBIOSNodeHybrid
);
279 update_pref(prefs
, CFSTR(kSMBPrefNetBIOSNodeType
), str
, &changed
);
282 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSScope
);
283 str
= isA_CFString(str
);
284 update_pref(prefs
, CFSTR(kSMBPrefNetBIOSScope
), str
, &changed
);
287 array
= CFDictionaryGetValue(dict
, kSCPropNetSMBWINSAddresses
);
288 array
= isA_CFArray(array
);
289 update_pref(prefs
, CFSTR(kSMBPrefWINSServerAddressList
), array
, &changed
);
291 // Workgroup (or domain)
292 str
= CFDictionaryGetValue(dict
, kSCPropNetSMBWorkgroup
);
293 str
= isA_CFString(str
);
294 update_pref(prefs
, CFSTR(kSMBPrefWorkgroup
), str
, &changed
);
297 ok
= SCPreferencesCommitChanges(prefs
);
299 SCLog((SCError() != EROFS
), LOG_ERR
,
300 CFSTR("smb_set_configuration: SCPreferencesCommitChanges() failed: %s"),
301 SCErrorString(SCError()));
305 ok
= SCPreferencesApplyChanges(prefs
);
308 CFSTR("smb_set_configuration: SCPreferencesApplyChanges() failed: %s"),
309 SCErrorString(SCError()));
316 (void) SCPreferencesUnlock(prefs
);
323 copy_primary_service(SCDynamicStoreRef store
)
325 CFDictionaryRef dict
;
327 CFStringRef serviceID
= NULL
;
329 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
330 kSCDynamicStoreDomainState
,
332 dict
= SCDynamicStoreCopyValue(store
, key
);
336 if (isA_CFDictionary(dict
)) {
337 serviceID
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryService
);
338 if (isA_CFString(serviceID
)) {
352 copy_primary_ip(SCDynamicStoreRef store
, CFStringRef serviceID
)
354 CFStringRef address
= NULL
;
355 CFDictionaryRef dict
;
358 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
359 kSCDynamicStoreDomainState
,
362 dict
= SCDynamicStoreCopyValue(store
, key
);
366 if (isA_CFDictionary(dict
)) {
367 CFArrayRef addresses
;
369 addresses
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Addresses
);
370 if (isA_CFArray(addresses
) && (CFArrayGetCount(addresses
) > 0)) {
371 address
= CFArrayGetValueAtIndex(addresses
, 0);
372 if (isA_CFString(address
)) {
387 reverseDNSComplete(int32_t status
, char *host
, char *serv
, void *context
)
389 CFDictionaryRef dict
;
390 struct timeval dnsQueryComplete
;
391 struct timeval dnsQueryElapsed
;
393 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
395 (void) gettimeofday(&dnsQueryComplete
, NULL
);
396 timersub(&dnsQueryComplete
, &dnsQueryStart
, &dnsQueryElapsed
);
397 SCLog(_verbose
, LOG_INFO
,
398 CFSTR("async DNS complete%s (query time = %d.%3.3d)"),
399 ((status
== 0) && (host
!= NULL
)) ? "" : ", host not found",
400 dnsQueryElapsed
.tv_sec
,
401 dnsQueryElapsed
.tv_usec
/ 1000);
403 // get network configuration
404 dict
= smb_copy_global_configuration(store
);
406 // use NetBIOS name from network configuration (if available)
407 name
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
);
408 if ((name
!= NULL
) && _SC_CFStringIsValidNetBIOSName(name
)) {
409 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (network configuration) = %@"), name
);
413 // use reverse DNS name, if available
417 * if [reverse] DNS query was successful
422 dot
= strchr(host
, '.');
423 name
= CFStringCreateWithBytes(NULL
,
425 (dot
!= NULL
) ? dot
- host
: strlen(host
),
426 kCFStringEncodingUTF8
,
429 if (_SC_CFStringIsValidNetBIOSName(name
)) {
430 CFMutableDictionaryRef newDict
;
432 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (reverse DNS query) = %@"), name
);
433 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
434 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
447 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
451 * if no name available
459 SCLog(TRUE
, LOG_ERR
, CFSTR("getnameinfo() failed: %s"), gai_strerror(status
));
462 // try local (multicast DNS) name, if available
463 name
= SCDynamicStoreCopyLocalHostName(store
);
465 if (_SC_CFStringIsValidNetBIOSName(name
)) {
466 CFMutableDictionaryRef newDict
;
468 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (multicast DNS) = %@"), name
);
469 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
470 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
479 // use "default" name
480 name
= copy_default_name();
482 CFMutableDictionaryRef newDict
;
484 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (default) = %@"), name
);
485 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
486 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
494 // update SMB configuration
495 smb_set_configuration(store
, dict
);
497 if (host
!= NULL
) free(host
);
498 if (dict
!= NULL
) CFRelease(dict
);
499 if (serv
!= NULL
) free(serv
);
506 getnameinfo_async_handleCFReply(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
510 status
= getnameinfo_async_handle_reply(msg
);
511 if ((status
== 0) && dnsActive
) {
512 // if request has been re-queued
516 if (port
== dnsPort
) {
517 CFRunLoopSourceInvalidate(dnsRLS
);
529 replyMPCopyDescription(const void *info
)
531 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
533 return CFStringCreateWithFormat(NULL
,
535 CFSTR("<getnameinfo_async_start reply MP> {store = %p}"),
541 start_dns_query(SCDynamicStoreRef store
, CFStringRef address
)
544 SCNetworkConnectionFlags flags
;
548 struct sockaddr_in sin
;
549 struct sockaddr_in6 sin6
;
551 if (_SC_cfstring_to_cstring(address
, addr
, sizeof(addr
), kCFStringEncodingASCII
) == NULL
) {
552 SCLog(TRUE
, LOG_ERR
, CFSTR("could not convert [primary] address"));
556 bzero(&sin
, sizeof(sin
));
557 sin
.sin_len
= sizeof(sin
);
558 sin
.sin_family
= AF_INET
;
560 bzero(&sin6
, sizeof(sin6
));
561 sin6
.sin6_len
= sizeof(sin6
);
562 sin6
.sin6_family
= AF_INET6
;
564 if (inet_aton(addr
, &sin
.sin_addr
) == 1) {
568 sa
= (struct sockaddr
*)&sin
;
569 } else if (inet_pton(AF_INET6
, addr
, &sin6
.sin6_addr
) == 1) {
575 p
= strchr(addr
, '%');
577 sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
580 sa
= (struct sockaddr
*)&sin6
;
585 ok
= _SC_checkResolverReachabilityByAddress(&store
, &flags
, &haveDNS
, sa
);
587 if (!(flags
& kSCNetworkFlagsReachable
) ||
588 (flags
& kSCNetworkFlagsConnectionRequired
)) {
589 // if not reachable *OR* connection required
595 CFMachPortContext context
= { 0
599 , replyMPCopyDescription
604 (void) gettimeofday(&dnsQueryStart
, NULL
);
606 error
= getnameinfo_async_start(&port
,
609 NI_NAMEREQD
, // flags
618 dnsPort
= CFMachPortCreateWithPort(NULL
,
620 getnameinfo_async_handleCFReply
,
623 dnsRLS
= CFMachPortCreateRunLoopSource(NULL
, dnsPort
, 0);
624 CFRunLoopAddSource(CFRunLoopGetCurrent(), dnsRLS
, kCFRunLoopDefaultMode
);
634 smb_update_configuration(__unused CFRunLoopTimerRef _timer
, void *info
)
636 CFStringRef address
= NULL
;
637 CFDictionaryRef dict
;
639 CFStringRef serviceID
= NULL
;
640 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
642 // get network configuration
643 dict
= smb_copy_global_configuration(store
);
645 // use NetBIOS name from network configuration (if available)
646 name
= CFDictionaryGetValue(dict
, kSCPropNetSMBNetBIOSName
);
647 if ((name
!= NULL
) && _SC_CFStringIsValidNetBIOSName(name
)) {
648 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (network configuration) = %@"), name
);
652 // get primary service ID
653 serviceID
= copy_primary_service(store
);
654 if (serviceID
== NULL
) {
655 // if no primary service
659 // get DNS name associated with primary IP, if available
660 address
= copy_primary_ip(store
, serviceID
);
661 if (address
!= NULL
) {
664 // start reverse DNS query using primary IP address
665 ok
= start_dns_query(store
, address
);
674 // get local (multicast DNS) name, if available
676 name
= SCDynamicStoreCopyLocalHostName(store
);
678 if (_SC_CFStringIsValidNetBIOSName(name
)) {
679 CFMutableDictionaryRef newDict
;
681 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (multicast DNS) = %@"), name
);
682 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
683 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
692 // get "default" name
693 name
= copy_default_name();
695 CFMutableDictionaryRef newDict
;
697 SCLog(TRUE
, LOG_INFO
, CFSTR("NetBIOS name (default) = %@"), name
);
698 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
699 CFDictionarySetValue(newDict
, kSCPropNetSMBNetBIOSName
, name
);
707 // update SMB configuration
708 smb_set_configuration(store
, dict
);
712 if (address
!= NULL
) CFRelease(address
);
713 if (dict
!= NULL
) CFRelease(dict
);
714 if (serviceID
!= NULL
) CFRelease(serviceID
);
717 CFRunLoopTimerInvalidate(timer
);
727 configuration_changed(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
729 CFRunLoopTimerContext context
= { 0, (void *)store
, CFRetain
, CFRelease
, NULL
};
730 CFAbsoluteTime time_boot
;
731 CFAbsoluteTime time_now
;
733 // if active, cancel any in-progress attempt to resolve the primary IP address
734 if (dnsPort
!= NULL
) {
735 /* cancel the outstanding DNS query */
736 getnameinfo_async_cancel(CFMachPortGetPort(dnsPort
));
737 CFRunLoopSourceInvalidate(dnsRLS
);
744 // if active, cancel any queued configuration change
746 CFRunLoopTimerInvalidate(timer
);
751 // queue configuration change
752 time_boot
= boottime() + SMB_STARTUP_DELAY
;
753 time_now
= CFAbsoluteTimeGetCurrent() + SMB_DEBOUNCE_DELAY
;
755 timer
= CFRunLoopTimerCreate(NULL
,
756 time_now
> time_boot
? time_now
: time_boot
,
760 smb_update_configuration
,
762 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
770 load_smb_configuration(Boolean verbose
)
773 CFMutableArrayRef keys
= NULL
;
774 CFMutableArrayRef patterns
= NULL
;
780 /* initialize a few globals */
782 store
= SCDynamicStoreCreate(NULL
, CFSTR("smb-configuration"), configuration_changed
, NULL
);
785 CFSTR("SCDynamicStoreCreate() failed: %s"),
786 SCErrorString(SCError()));
790 /* establish notification keys and patterns */
792 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
793 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
795 /* ...watch for primary service / interface changes */
796 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
797 kSCDynamicStoreDomainState
,
799 CFArrayAppendValue(keys
, key
);
802 /* ...watch for DNS configuration changes */
803 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
804 kSCDynamicStoreDomainState
,
806 CFArrayAppendValue(keys
, key
);
809 /* ...watch for SMB configuration changes */
810 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
811 kSCDynamicStoreDomainState
,
813 CFArrayAppendValue(keys
, key
);
816 /* ...watch for ComputerName changes */
817 key
= SCDynamicStoreKeyCreateComputerName(NULL
);
818 CFArrayAppendValue(keys
, key
);
821 /* ...watch for local (multicast DNS) hostname changes */
822 key
= SCDynamicStoreKeyCreateHostNames(NULL
);
823 CFArrayAppendValue(keys
, key
);
826 /* register the keys/patterns */
827 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
)) {
829 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
830 SCErrorString(SCError()));
834 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
837 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
838 SCErrorString(SCError()));
841 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
849 if (keys
!= NULL
) CFRelease(keys
);
850 if (patterns
!= NULL
) CFRelease(patterns
);
851 if (store
!= NULL
) CFRelease(store
);
858 main(int argc
, char **argv
)
864 CFStringRef serviceID
;
865 SCDynamicStoreRef store
;
868 if ((argc
> 1) && (strcmp(argv
[1], "-d") == 0)) {
874 store
= SCDynamicStoreCreate(NULL
, CFSTR("smb-configuration"), NULL
, NULL
);
876 SCPrint(TRUE
, stdout
,
877 CFSTR("SCDynamicStoreCreate() failed: %s\n"),
878 SCErrorString(SCError()));
882 // get "default" name
883 name
= copy_default_name();
885 SCPrint(TRUE
, stdout
, CFSTR("default name = %@\n"), name
);
889 // get primary service
890 serviceID
= copy_primary_service(store
);
891 if (serviceID
!= NULL
) {
892 SCPrint(TRUE
, stdout
, CFSTR("primary service ID = %@\n"), serviceID
);
894 SCPrint(TRUE
, stdout
, CFSTR("No primary service\n"));
898 if ((argc
== (2+1)) && (argv
[1][0] == 's')) {
899 if (serviceID
!= NULL
) CFRelease(serviceID
);
900 serviceID
= CFStringCreateWithCString(NULL
, argv
[2], kCFStringEncodingUTF8
);
901 SCPrint(TRUE
, stdout
, CFSTR("alternate service ID = %@\n"), serviceID
);
904 // get primary IP address
905 address
= copy_primary_ip(store
, serviceID
);
906 CFRelease(serviceID
);
907 if (address
!= NULL
) {
908 SCPrint(TRUE
, stdout
, CFSTR("primary address = %@\n"), address
);
910 if ((argc
== (2+1)) && (argv
[1][0] == 'a')) {
911 if (address
!= NULL
) CFRelease(address
);
912 address
= CFStringCreateWithCString(NULL
, argv
[2], kCFStringEncodingUTF8
);
913 SCPrint(TRUE
, stdout
, CFSTR("alternate primary address = %@\n"), address
);
916 // start reverse DNS query using primary IP address
917 (void) start_dns_query(store
, address
);
923 smb_update_configuration(NULL
, store
);
932 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
934 load_smb_configuration((argc
> 1) ? TRUE
: FALSE
);