smb-configuration.c [plain text]
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb_async.h>
#include <notify.h>
#include <smb_server_prefs.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFStringDefaultEncoding.h> // for __CFStringGetInstallationEncodingAndRegion()
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
#define HW_MODEL_LEN 64 // Note: must be >= NETBIOS_NAME_LEN (below)
#define NETBIOS_NAME_LEN 16
#define SMB_STARTUP_DELAY 60.0
#define SMB_DEBOUNCE_DELAY 5.0
static SCDynamicStoreRef store = NULL;
static CFRunLoopSourceRef rls = NULL;
static Boolean dnsActive = FALSE;
static CFMachPortRef dnsPort = NULL;
static struct timeval dnsQueryStart;
static CFRunLoopTimerRef timer = NULL;
static Boolean _verbose = FALSE;
static Boolean
isMacOSXServer()
{
static enum { Unknown, Client, Server } isServer = Unknown;
if (isServer == Unknown) {
int ret;
struct stat statbuf;
ret = stat("/System/Library/CoreServices/ServerVersion.plist", &statbuf);
isServer = (ret == 0) ? Server : Client;
}
return (isServer == Server) ? TRUE : FALSE;
}
static CFAbsoluteTime
boottime(void)
{
static CFAbsoluteTime bt = 0;
if (bt == 0) {
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
struct timeval tv;
size_t tv_len = sizeof(tv);
if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &tv, &tv_len, NULL, 0) == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("sysctl() CTL_KERN/KERN_BOOTTIME failed: %s"), strerror(errno));
return kCFAbsoluteTimeIntervalSince1970;
}
bt = (CFTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970;
bt += (1.0E-6 * (CFTimeInterval)tv.tv_usec);
}
return bt;
}
static CFStringRef
copy_default_name(void)
{
char *cp;
char hwModel[HW_MODEL_LEN];
int mib[] = { CTL_HW, HW_MODEL };
size_t n = sizeof(hwModel);
int ret;
CFMutableStringRef str;
bzero(&hwModel, sizeof(hwModel));
ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0);
if (ret != 0) {
SCLog(TRUE, LOG_ERR, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno));
return NULL;
}
hwModel[NETBIOS_NAME_LEN - 1] = '\0';
cp = index(hwModel, ',');
if (cp != NULL) {
*cp = '\0';
}
n = strlen(hwModel);
while (n > 0) {
if (!isdigit(hwModel[n - 1])) {
break;
}
hwModel[--n] = '\0';
}
str = CFStringCreateMutable(NULL, 0);
CFStringAppendFormat(str, NULL, CFSTR("%s"), hwModel);
if (n < (NETBIOS_NAME_LEN - 1 - 3)) {
SCNetworkInterfaceRef interface;
interface = _SCNetworkInterfaceCreateWithBSDName(NULL, CFSTR("en0"),
kIncludeNoVirtualInterfaces);
if (interface != NULL) {
CFMutableStringRef en0_MAC;
en0_MAC = (CFMutableStringRef)SCNetworkInterfaceGetHardwareAddressString(interface);
if (en0_MAC != NULL) {
CFIndex en0_MAC_len;
en0_MAC = CFStringCreateMutableCopy(NULL, 0, en0_MAC);
CFStringFindAndReplace(en0_MAC,
CFSTR(":"),
CFSTR(""),
CFRangeMake(0, CFStringGetLength(en0_MAC)),
0);
n = ((NETBIOS_NAME_LEN - 1 - n - 1) / 2) * 2;
if (n > 6) {
n = 6;
}
en0_MAC_len = CFStringGetLength(en0_MAC);
if (en0_MAC_len > n) {
CFStringDelete(en0_MAC, CFRangeMake(0, en0_MAC_len - n));
}
CFStringAppendFormat(str, NULL, CFSTR("-%@"), en0_MAC);
CFRelease(en0_MAC);
}
CFRelease(interface);
}
}
CFStringUppercase(str, NULL);
return str;
}
static CFDictionaryRef
smb_copy_global_configuration(SCDynamicStoreRef store)
{
CFDictionaryRef dict;
CFStringRef key;
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainState,
kSCEntNetSMB);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict != NULL) {
if (isA_CFDictionary(dict)) {
return dict;
}
CFRelease(dict);
}
dict = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
return dict;
}
static void
update_pref(SCPreferencesRef prefs, CFStringRef key, CFTypeRef newVal, Boolean *changed)
{
CFTypeRef curVal;
curVal = SCPreferencesGetValue(prefs, key);
if (!_SC_CFEqual(curVal, newVal)) {
if (newVal != NULL) {
SCPreferencesSetValue(prefs, key, newVal);
} else {
SCPreferencesRemoveValue(prefs, key);
}
*changed = TRUE;
}
return;
}
static void
smb_set_configuration(SCDynamicStoreRef store, CFDictionaryRef dict)
{
CFArrayRef array;
Boolean changed = FALSE;
UInt32 dosCodepage = 0;
CFStringEncoding dosEncoding = 0;
CFStringEncoding macEncoding = kCFStringEncodingMacRoman;
uint32_t macRegion = 0;
Boolean ok;
SCPreferencesRef prefs;
CFStringRef str;
prefs = SCPreferencesCreate(NULL, CFSTR("smb-configuration"), CFSTR(kSMBPreferencesAppID));
if (prefs == NULL) {
SCLog(TRUE, LOG_ERR,
CFSTR("smb_set_configuration: SCPreferencesCreate() failed: %s"),
SCErrorString(SCError()));
return;
}
ok = SCPreferencesLock(prefs, TRUE);
if (!ok) {
SCLog(TRUE, LOG_ERR,
CFSTR("smb_set_configuration: SCPreferencesLock() failed: %s"),
SCErrorString(SCError()));
goto done;
}
if (!isMacOSXServer()) {
str = SCDynamicStoreCopyComputerName(store, &macEncoding);
update_pref(prefs, CFSTR(kSMBPrefServerDescription), str, &changed);
if (str != NULL) {
if (macEncoding == kCFStringEncodingMacRoman) {
CFStringRef key;
CFDictionaryRef dict;
key = SCDynamicStoreKeyCreateComputerName(NULL);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict != NULL) {
if (isA_CFDictionary(dict)) {
CFNumberRef num;
SInt32 val;
num = CFDictionaryGetValue(dict, kSCPropSystemComputerNameRegion);
if (isA_CFNumber(num) &&
CFNumberGetValue(num, kCFNumberSInt32Type, &val)) {
macRegion = (uint32_t)val;
}
}
CFRelease(dict);
}
}
CFRelease(str);
} else {
__CFStringGetInstallationEncodingAndRegion((uint32_t *)&macEncoding, &macRegion);
}
_SC_dos_encoding_and_codepage(macEncoding, macRegion, &dosEncoding, &dosCodepage);
str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), dosCodepage);
update_pref(prefs, CFSTR(kSMBPrefDOSCodePage), str, &changed);
CFRelease(str);
}
str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName);
str = isA_CFString(str);
update_pref(prefs, CFSTR(kSMBPrefNetBIOSName), str, &changed);
str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSNodeType);
str = isA_CFString(str);
if (str != NULL) {
if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeBroadcast)) {
str = CFSTR(kSMBPrefNetBIOSNodeBroadcast);
} else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypePeer)) {
str = CFSTR(kSMBPrefNetBIOSNodePeer);
} else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeMixed)) {
str = CFSTR(kSMBPrefNetBIOSNodeMixed);
} else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeHybrid)) {
str = CFSTR(kSMBPrefNetBIOSNodeHybrid);
} else {
str = NULL;
}
}
update_pref(prefs, CFSTR(kSMBPrefNetBIOSNodeType), str, &changed);
#ifdef ADD_NETBIOS_SCOPE
str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSScope);
str = isA_CFString(str);
update_pref(prefs, CFSTR(kSMBPrefNetBIOSScope), str, &changed);
#endif // ADD_NETBIOS_SCOPE
array = CFDictionaryGetValue(dict, kSCPropNetSMBWINSAddresses);
array = isA_CFArray(array);
update_pref(prefs, CFSTR(kSMBPrefWINSServerAddressList), array, &changed);
str = CFDictionaryGetValue(dict, kSCPropNetSMBWorkgroup);
str = isA_CFString(str);
update_pref(prefs, CFSTR(kSMBPrefWorkgroup), str, &changed);
if (changed) {
ok = SCPreferencesCommitChanges(prefs);
if (!ok) {
SCLog((SCError() != EROFS), LOG_ERR,
CFSTR("smb_set_configuration: SCPreferencesCommitChanges() failed: %s"),
SCErrorString(SCError()));
goto done;
}
ok = SCPreferencesApplyChanges(prefs);
if (!ok) {
SCLog(TRUE, LOG_ERR,
CFSTR("smb_set_configuration: SCPreferencesApplyChanges() failed: %s"),
SCErrorString(SCError()));
goto done;
}
}
done :
(void) SCPreferencesUnlock(prefs);
CFRelease(prefs);
return;
}
static CFStringRef
copy_primary_service(SCDynamicStoreRef store)
{
CFDictionaryRef dict;
CFStringRef key;
CFStringRef serviceID = NULL;
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainState,
kSCEntNetIPv4);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict != NULL) {
if (isA_CFDictionary(dict)) {
serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
if (isA_CFString(serviceID)) {
CFRetain(serviceID);
} else {
serviceID = NULL;
}
}
CFRelease(dict);
}
return serviceID;
}
static CFStringRef
copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID)
{
CFStringRef address = NULL;
CFDictionaryRef dict;
CFStringRef key;
key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainState,
serviceID,
kSCEntNetIPv4);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict != NULL) {
if (isA_CFDictionary(dict)) {
CFArrayRef addresses;
addresses = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses);
if (isA_CFArray(addresses) && (CFArrayGetCount(addresses) > 0)) {
address = CFArrayGetValueAtIndex(addresses, 0);
if (isA_CFString(address)) {
CFRetain(address);
} else {
address = NULL;
}
}
}
CFRelease(dict);
}
return address;
}
static void
reverseDNSComplete(int32_t status, char *host, char *serv, void *context)
{
CFDictionaryRef dict;
struct timeval dnsQueryComplete;
struct timeval dnsQueryElapsed;
CFStringRef name;
SCDynamicStoreRef store = (SCDynamicStoreRef)context;
(void) gettimeofday(&dnsQueryComplete, NULL);
timersub(&dnsQueryComplete, &dnsQueryStart, &dnsQueryElapsed);
SCLog(_verbose, LOG_INFO,
CFSTR("async DNS complete%s (query time = %d.%3.3d)"),
((status == 0) && (host != NULL)) ? "" : ", host not found",
dnsQueryElapsed.tv_sec,
dnsQueryElapsed.tv_usec / 1000);
dict = smb_copy_global_configuration(store);
name = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName);
if ((name != NULL) && _SC_CFStringIsValidNetBIOSName(name)) {
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (network configuration) = %@"), name);
goto set;
}
switch (status) {
case 0 :
if (host != NULL) {
char *dot;
dot = strchr(host, '.');
name = CFStringCreateWithBytes(NULL,
(UInt8 *)host,
(dot != NULL) ? dot - host : strlen(host),
kCFStringEncodingUTF8,
FALSE);
if (name != NULL) {
if (_SC_CFStringIsValidNetBIOSName(name)) {
CFMutableDictionaryRef newDict;
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (reverse DNS query) = %@"), name);
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name);
CFRelease(dict);
dict = newDict;
CFRelease(name);
goto set;
}
CFRelease(name);
}
}
break;
case EAI_NONAME :
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
case EAI_NODATA:
#endif
break;
default :
SCLog(TRUE, LOG_ERR, CFSTR("getnameinfo() failed: %s"), gai_strerror(status));
}
name = SCDynamicStoreCopyLocalHostName(store);
if (name != NULL) {
if (_SC_CFStringIsValidNetBIOSName(name)) {
CFMutableDictionaryRef newDict;
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (multicast DNS) = %@"), name);
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name);
CFRelease(dict);
dict = newDict;
CFRelease(name);
goto set;
}
CFRelease(name);
}
name = copy_default_name();
if (name != NULL) {
CFMutableDictionaryRef newDict;
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (default) = %@"), name);
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name);
CFRelease(dict);
dict = newDict;
CFRelease(name);
}
set :
smb_set_configuration(store, dict);
if (host != NULL) free(host);
if (dict != NULL) CFRelease(dict);
if (serv != NULL) free(serv);
dnsActive = FALSE;
return;
}
static CFStringRef
replyMPCopyDescription(const void *info)
{
SCDynamicStoreRef store = (SCDynamicStoreRef)info;
return CFStringCreateWithFormat(NULL,
NULL,
CFSTR("<getnameinfo_async_start reply MP> {store = %p}"),
store);
}
static void
getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
mach_port_t mp = MACH_PORT_NULL;
int32_t status;
if (port != dnsPort) {
SCLog(TRUE, LOG_ERR, CFSTR("getnameinfo_async_handleCFReply(): port != dnsPort"));
return;
}
mp = CFMachPortGetPort(port);
CFMachPortInvalidate(dnsPort);
CFRelease(dnsPort);
dnsPort = NULL;
status = getnameinfo_async_handle_reply(msg);
if ((status == 0) && dnsActive && (mp != MACH_PORT_NULL)) {
CFMachPortContext context = { 0
, (void *)store
, CFRetain
, CFRelease
, replyMPCopyDescription
};
CFRunLoopSourceRef rls;
dnsPort = _SC_CFMachPortCreateWithPort("IPMonitor/smb-configuration/re-queue",
mp,
getnameinfo_async_handleCFReply,
&context);
rls = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
}
return;
}
static Boolean
start_dns_query(SCDynamicStoreRef store, CFStringRef address)
{
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} addr;
char buf[64];
SCNetworkReachabilityFlags flags;
Boolean haveDNS;
Boolean ok = FALSE;
if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
SCLog(TRUE, LOG_ERR, CFSTR("could not convert [primary] address"));
return FALSE;
}
if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
SCLog(TRUE, LOG_ERR, CFSTR("could not parse [primary] address"));
return FALSE;
}
ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa);
if (ok) {
if (!(flags & kSCNetworkReachabilityFlagsReachable) ||
(flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
ok = FALSE;
}
}
if (ok) {
CFMachPortContext context = { 0
, (void *)store
, CFRetain
, CFRelease
, replyMPCopyDescription
};
int32_t error;
mach_port_t mp;
CFRunLoopSourceRef rls;
(void) gettimeofday(&dnsQueryStart, NULL);
error = getnameinfo_async_start(&mp,
&addr.sa,
addr.sa.sa_len,
NI_NAMEREQD, reverseDNSComplete,
(void *)store);
if (error != 0) {
ok = FALSE;
goto done;
}
dnsActive = TRUE;
dnsPort = _SC_CFMachPortCreateWithPort("IPMonitor/smb-configuration",
mp,
getnameinfo_async_handleCFReply,
&context);
rls = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
}
done :
return ok;
}
static void
smb_update_configuration(__unused CFRunLoopTimerRef _timer, void *info)
{
CFStringRef address = NULL;
CFDictionaryRef dict;
CFStringRef name;
CFStringRef serviceID = NULL;
SCDynamicStoreRef store = (SCDynamicStoreRef)info;
dict = smb_copy_global_configuration(store);
name = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName);
if ((name != NULL) && _SC_CFStringIsValidNetBIOSName(name)) {
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (network configuration) = %@"), name);
goto set;
}
serviceID = copy_primary_service(store);
if (serviceID == NULL) {
goto mDNS;
}
address = copy_primary_ip(store, serviceID);
if (address != NULL) {
Boolean ok;
ok = start_dns_query(store, address);
if (ok) {
goto done;
}
}
mDNS :
name = SCDynamicStoreCopyLocalHostName(store);
if (name != NULL) {
if (_SC_CFStringIsValidNetBIOSName(name)) {
CFMutableDictionaryRef newDict;
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (multicast DNS) = %@"), name);
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name);
CFRelease(dict);
dict = newDict;
CFRelease(name);
goto set;
}
CFRelease(name);
}
name = copy_default_name();
if (name != NULL) {
CFMutableDictionaryRef newDict;
SCLog(TRUE, LOG_INFO, CFSTR("NetBIOS name (default) = %@"), name);
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
CFDictionarySetValue(newDict, kSCPropNetSMBNetBIOSName, name);
CFRelease(dict);
dict = newDict;
CFRelease(name);
}
set :
smb_set_configuration(store, dict);
done :
if (address != NULL) CFRelease(address);
if (dict != NULL) CFRelease(dict);
if (serviceID != NULL) CFRelease(serviceID);
if (timer != NULL) {
CFRunLoopTimerInvalidate(timer);
CFRelease(timer);
timer = NULL;
}
return;
}
static void
configuration_changed(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
{
CFRunLoopTimerContext context = { 0, (void *)store, CFRetain, CFRelease, NULL };
CFAbsoluteTime time_boot;
CFAbsoluteTime time_now ;
if (dnsPort != NULL) {
mach_port_t mp = CFMachPortGetPort(dnsPort);
CFMachPortInvalidate(dnsPort);
CFRelease(dnsPort);
dnsPort = NULL;
getnameinfo_async_cancel(mp);
}
if (timer != NULL) {
CFRunLoopTimerInvalidate(timer);
CFRelease(timer);
timer = NULL;
}
time_boot = boottime() + SMB_STARTUP_DELAY;
time_now = CFAbsoluteTimeGetCurrent() + SMB_DEBOUNCE_DELAY;
timer = CFRunLoopTimerCreate(NULL,
time_now > time_boot ? time_now : time_boot,
0,
0,
0,
smb_update_configuration,
&context);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
return;
}
__private_extern__
void
load_smb_configuration(Boolean verbose)
{
CFStringRef key;
CFMutableArrayRef keys = NULL;
CFMutableArrayRef patterns = NULL;
if (verbose) {
_verbose = TRUE;
}
store = SCDynamicStoreCreate(NULL, CFSTR("smb-configuration"), configuration_changed, NULL);
if (store == NULL) {
SCLog(TRUE, LOG_ERR,
CFSTR("SCDynamicStoreCreate() failed: %s"),
SCErrorString(SCError()));
goto error;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainState,
kSCEntNetIPv4);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainState,
kSCEntNetDNS);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainState,
kSCEntNetSMB);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateComputerName(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateHostNames(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
SCLog(TRUE, LOG_ERR,
CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
SCErrorString(SCError()));
goto error;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (!rls) {
SCLog(TRUE, LOG_ERR,
CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
SCErrorString(SCError()));
goto error;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(keys);
CFRelease(patterns);
return;
error :
if (keys != NULL) CFRelease(keys);
if (patterns != NULL) CFRelease(patterns);
if (store != NULL) CFRelease(store);
return;
}
#ifdef MAIN
int
main(int argc, char **argv)
{
#ifdef DEBUG
CFStringRef address;
CFStringRef name;
CFStringRef serviceID;
SCDynamicStoreRef store;
_sc_log = FALSE;
if ((argc > 1) && (strcmp(argv[1], "-d") == 0)) {
_sc_verbose = TRUE;
argv++;
argc--;
}
store = SCDynamicStoreCreate(NULL, CFSTR("smb-configuration"), NULL, NULL);
if (store == NULL) {
SCPrint(TRUE, stdout,
CFSTR("SCDynamicStoreCreate() failed: %s\n"),
SCErrorString(SCError()));
exit(1);
}
name = copy_default_name();
if (name != NULL) {
SCPrint(TRUE, stdout, CFSTR("default name = %@\n"), name);
CFRelease(name);
}
serviceID = copy_primary_service(store);
if (serviceID != NULL) {
SCPrint(TRUE, stdout, CFSTR("primary service ID = %@\n"), serviceID);
} else {
SCPrint(TRUE, stdout, CFSTR("No primary service\n"));
goto done;
}
if ((argc == (2+1)) && (argv[1][0] == 's')) {
if (serviceID != NULL) CFRelease(serviceID);
serviceID = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
SCPrint(TRUE, stdout, CFSTR("alternate service ID = %@\n"), serviceID);
}
address = copy_primary_ip(store, serviceID);
CFRelease(serviceID);
if (address != NULL) {
SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address);
if ((argc == (2+1)) && (argv[1][0] == 'a')) {
if (address != NULL) CFRelease(address);
address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address);
}
(void) start_dns_query(store, address);
CFRelease(address);
}
done :
smb_update_configuration(NULL, (void *)store);
CFRelease(store);
CFRunLoopRun();
#else
_sc_log = FALSE;
_sc_verbose = (argc > 1) ? TRUE : FALSE;
load_smb_configuration((argc > 1) ? TRUE : FALSE);
CFRunLoopRun();
#endif
exit(0);
return 0;
}
#endif