PasswordServerPrefs.m [plain text]
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#import <sys/param.h>
#import <sys/stat.h>
#import "PasswordServerPrefs.h"
#import "PSUtilitiesDefs.h"
// ----------------------------------------------------------------------------------------
// pwsf_SetSASLPluginState
//
// Returns: TRUE if the plugin list changed
// ----------------------------------------------------------------------------------------
bool pwsf_SetSASLPluginState( const char *inMechName, bool enable )
{
PasswordServerPrefsObject *prefsObj = [[PasswordServerPrefsObject alloc] init];
SASLPluginStatus mechState = kSASLPluginStateUnlisted;
BOOL changeMade = NO;
int index = -1;
char *pluginFileNamePtr = NULL;
PasswordServerPrefs prefs;
char fromPath[PATH_MAX];
char toPath[PATH_MAX];
struct stat sb;
int err;
if ( prefsObj == nil )
return NO;
mechState = [prefsObj getSASLPluginStatus:inMechName foundAtIndex:&index];
if ( enable && mechState != kSASLPluginStateAllowed )
{
// if the plug-in is disabled the old way (plug-in moved to the disabled
// folder) then move the plug-in file.
if ( pwsf_GetSASLMechInfo( inMechName, &pluginFileNamePtr, NULL ) )
{
sprintf( fromPath, " err = lstat( fromPath, &sb );
if ( err == 0 )
{
sprintf( toPath, "/usr/lib/sasl2/ rename( fromPath, toPath );
}
if ( pluginFileNamePtr != NULL )
free( pluginFileNamePtr );
}
// activate or add plug-in to active list
[prefsObj getPrefs:&prefs];
if ( index >= 0 )
{
prefs.saslPluginState[index].state = kSASLPluginStateAllowed;
}
else
{
// add to array
for ( index = 0; index <= kMaxSASLPlugins; index++ )
if ( prefs.saslPluginState[index].name[0] == '\0' )
break;
if ( index <= kMaxSASLPlugins )
{
strlcpy( prefs.saslPluginState[index].name, inMechName, SASL_MECHNAMEMAX + 1 );
prefs.saslPluginState[index].state = kSASLPluginStateAllowed;
}
}
[prefsObj setPrefs:&prefs];
[prefsObj savePrefs];
changeMade = YES;
}
else
if ( !enable && mechState != kSASLPluginStateDisabled )
{
// disable or add plug-in to disable list
[prefsObj getPrefs:&prefs];
if ( index >= 0 )
{
prefs.saslPluginState[index].state = kSASLPluginStateDisabled;
}
else
{
// add to array
for ( index = 0; index <= kMaxSASLPlugins; index++ )
if ( prefs.saslPluginState[index].name[0] == '\0' )
break;
if ( index <= kMaxSASLPlugins )
{
strlcpy( prefs.saslPluginState[index].name, inMechName, SASL_MECHNAMEMAX + 1 );
prefs.saslPluginState[index].state = kSASLPluginStateDisabled;
}
}
[prefsObj setPrefs:&prefs];
[prefsObj savePrefs];
changeMade = YES;
}
[prefsObj free];
return (bool)changeMade;
}
// ----------------------------------------------------------------------------------------
// ConvertCFDictToFlatArray
// ----------------------------------------------------------------------------------------
void ConvertCFDictToFlatArray(const void *key, const void *value, void *context);
void ConvertCFDictToFlatArray(const void *key, const void *value, void *context)
{
SASLPluginListConverterContext *text = NULL;
CFStringRef keyRef;
CFStringRef valueRef;
char keyStr[256];
if ( key == NULL || value == NULL || context == NULL )
return;
text = (SASLPluginListConverterContext *)context;
if ( text->arrayIndex >= kMaxSASLPlugins )
return;
keyRef = (CFStringRef)key;
valueRef = (CFStringRef)value;
if ( ! CFStringGetCString(keyRef, keyStr, sizeof(keyStr), kCFStringEncodingUTF8) )
strcpy( keyStr, "<none>" );
strlcpy( (text->saslPluginState)[text->arrayIndex].name, keyStr, SASL_MECHNAMEMAX + 1 );
if ( CFStringCompare(valueRef, CFSTR("ON"), kCFCompareCaseInsensitive) == kCFCompareEqualTo )
text->saslPluginState[text->arrayIndex].state = kSASLPluginStateAllowed;
else
text->saslPluginState[text->arrayIndex].state = kSASLPluginStateDisabled;
text->arrayIndex++;
}
inline void TransferItemToCFDictionary(CFMutableDictionaryRef inDict, CFStringRef inKey, CFTypeRef inValue )
{
if ( inValue != NULL )
{
CFDictionaryAddValue( inDict, inKey, inValue );
CFRelease( inValue );
}
}
@implementation PasswordServerPrefsObject
-(id)init
{
int idx = 0;
if ( (self = [super init]) != nil )
{
// set defaults
mPrefs.passiveReplicationOnly = NO;
mPrefs.provideReplicationOnly = NO;
mPrefs.badTrialDelay = 0;
mPrefs.timeSkewMaxSeconds = 8 * 60;
mPrefs.syncInterval = 60*60*24;
mPrefs.listenerPort[0] = 106;
mPrefs.listenerPort[1] = 3659;
mPrefs.listenerTypeFlags = kPWPrefsAll;
mPrefs.externalToolSet = NO;
mPrefs.externalToolPath[0] = '\0';
mPrefs.testSpillBucket = NO;
mPrefs.realmSet = NO;
mPrefs.realm[0] = '\0';
mPrefs.kerberosCacheLimit = kKerberosCacheScaleLimit;
mPrefs.syncSASLPluginList = YES;
mPrefs.prefsVersion = kPWPrefsVersion;
mPrefs.logOptions.changeList = NO;
mPrefs.logOptions.quit = NO;
mPrefs.deleteWait = 120; // 2 minutes
mPrefs.purgeWait = 20160 * 60; // 14 days
mPrefsDict = NULL;
mPrefsFileModDate.tv_sec = 0;
mPrefsFileModDate.tv_nsec = 0;
mExternalToolIllegalChars = CFCharacterSetCreateWithCharactersInString( kCFAllocatorDefault, CFSTR("/:") );
// leave a template behind if no preferences file present
if ( [self loadPrefs] != 0 || mPrefs.prefsVersion < kPWPrefsVersion )
{
// for old prefs files, update the interface
// list to include the UNIX domain socket
mPrefs.listenerTypeFlags = kPWPrefsAll;
// add new auth method
for ( idx = 0; mPrefs.saslPluginState[idx].name[0] != '\0' && idx < kMaxSASLPlugins; idx++ );
if ( idx < kMaxSASLPlugins )
{
strcpy( mPrefs.saslPluginState[idx].name, "PPS" );
mPrefs.saslPluginState[idx].state = kSASLPluginStateAllowed;
}
// set the current version
mPrefs.prefsVersion = kPWPrefsVersion;
[self savePrefs];
}
}
return self;
}
-free
{
if ( mPrefsDict != NULL )
CFRelease( mPrefsDict );
if ( mExternalToolIllegalChars != NULL )
CFRelease( mExternalToolIllegalChars );
return [super free];
}
// ---------------------------------------------------------------------------
// getPrefs
// ---------------------------------------------------------------------------
-(void)getPrefs:(PasswordServerPrefs *)outPrefs
{
if ( outPrefs != NULL )
memcpy( outPrefs, &mPrefs, sizeof(PasswordServerPrefs) );
}
// ---------------------------------------------------------------------------
// setPrefs
// ---------------------------------------------------------------------------
-(void)setPrefs:(PasswordServerPrefs *)inPrefs
{
if ( inPrefs != NULL )
memcpy( &mPrefs, inPrefs, sizeof(PasswordServerPrefs) );
}
// ---------------------------------------------------------------------------
// refreshIfNeeded
//
// Returns: void
// ---------------------------------------------------------------------------
-(void)refreshIfNeeded
{
struct timespec modDate;
bool refresh = NO;
if ( [self statPrefsFileAndGetModDate:&modDate] == 0 )
{
if ( modDate.tv_sec > mPrefsFileModDate.tv_sec )
refresh = true;
if ( modDate.tv_sec == mPrefsFileModDate.tv_sec && modDate.tv_nsec > mPrefsFileModDate.tv_nsec )
refresh = true;
if ( refresh )
[self loadPrefs];
}
}
-(int)loadPrefs
{
int result = -1;
CFIndex index = 0;
CFIndex arrayCount = 0;
CFArrayRef portArray = NULL;
CFTypeRef valueRef = NULL;
CFArrayRef interfaceArray = NULL;
uint16_t aShortValue = 0;
uint32_t aLongValue = 0;
result = [self loadXMLData];
if ( result == 0 )
{
mPrefs.passiveReplicationOnly = [self longValueForKey:CFSTR(kPWPrefsKey_PassiveReplicationOnly) inDictionary:mPrefsDict];
mPrefs.provideReplicationOnly = [self longValueForKey:CFSTR(kPWPrefsKey_ProvideReplicationOnly) inDictionary:mPrefsDict];
mPrefs.badTrialDelay = [self longValueForKey:CFSTR(kPWPrefsKey_BadTrialDelay) inDictionary:mPrefsDict];
mPrefs.timeSkewMaxSeconds = [self longValueForKey:CFSTR(kPWPrefsKey_TimeSkewMaxSeconds) inDictionary:mPrefsDict];
mPrefs.syncInterval = [self longValueForKey:CFSTR(kPWPrefsKey_SyncInterval) inDictionary:mPrefsDict];
mPrefs.prefsVersion = (int)[self longValueForKey:CFSTR(kPWPrefsKey_PrefsVersion) inDictionary:mPrefsDict];
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_ListenerPorts), (const void **)&portArray ) &&
CFGetTypeID(portArray) == CFArrayGetTypeID() )
{
bzero( mPrefs.listenerPort, sizeof(mPrefs.listenerPort) );
arrayCount = CFArrayGetCount( portArray );
if ( arrayCount > kMaxListenerPorts )
arrayCount = kMaxListenerPorts;
for ( index = 0; index < arrayCount; index++ )
{
valueRef = CFArrayGetValueAtIndex( portArray, index );
if ( valueRef == NULL )
break;
if ( CFGetTypeID(valueRef) != CFNumberGetTypeID() )
break;
if ( CFNumberGetValue( (CFNumberRef)valueRef, kCFNumberShortType, &aShortValue) )
mPrefs.listenerPort[index] = aShortValue;
}
}
mPrefs.testSpillBucket = [self longValueForKey:CFSTR(kPWPrefsKey_TestSpillBucket) inDictionary:mPrefsDict];
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_SASLRealm), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFStringGetTypeID() )
{
mPrefs.realmSet = CFStringGetCString( (CFStringRef)valueRef, mPrefs.realm, sizeof(mPrefs.realm), kCFStringEncodingUTF8 );
}
// External Command
mPrefs.externalToolSet = 0;
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_ExternalTool), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFStringGetTypeID() &&
CFStringCompare((CFStringRef)valueRef, CFSTR(kPWPrefsValue_ExternalToolNone), kCFCompareCaseInsensitive) != kCFCompareEqualTo )
{
CFRange searchResult;
char toolName[256] = {0,};
char toolPath[256] = {0,};
BOOL stillGood;
int err;
struct stat sb;
stillGood = CFStringGetCString( (CFStringRef)valueRef, toolName, sizeof(toolName), kCFStringEncodingUTF8 );
if ( stillGood )
stillGood = ! CFStringFindCharacterFromSet( (CFStringRef)valueRef,
mExternalToolIllegalChars,
CFRangeMake(0,CFStringGetLength((CFStringRef)valueRef)-1),
0, &searchResult );
if ( stillGood )
{
snprintf( toolPath, sizeof(toolPath), kPWExternalToolPath"/ err = stat( toolPath, &sb );
if ( err != 0 )
stillGood = NO;
}
if ( stillGood )
{
strcpy( mPrefs.externalToolPath, toolPath );
mPrefs.externalToolSet = 1;
}
}
// listener interfaces
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_ListenerInterfaces), (const void **)&interfaceArray ) &&
CFGetTypeID(interfaceArray) == CFArrayGetTypeID() )
{
mPrefs.listenerTypeFlags = kPWPrefsNoListeners;
arrayCount = CFArrayGetCount( interfaceArray );
for ( index = 0; index < arrayCount; index++ )
{
valueRef = CFArrayGetValueAtIndex( interfaceArray, index );
if ( valueRef == NULL )
break;
if ( CFGetTypeID(valueRef) != CFStringGetTypeID() )
break;
if ( CFStringCompare((CFStringRef)valueRef, CFSTR(kPWPrefsValue_ListenerEnet), kCFCompareCaseInsensitive) == kCFCompareEqualTo )
mPrefs.listenerTypeFlags = (ListenerTypes)((unsigned int)mPrefs.listenerTypeFlags | kPWPrefsEnet);
else
if ( CFStringCompare((CFStringRef)valueRef, CFSTR(kPWPrefsValue_ListenerLocal), kCFCompareCaseInsensitive) == kCFCompareEqualTo )
mPrefs.listenerTypeFlags = (ListenerTypes)((unsigned int)mPrefs.listenerTypeFlags | kPWPrefsLocal);
else
if ( CFStringCompare((CFStringRef)valueRef, CFSTR(kPWPrefsValue_ListenerUDSocket), kCFCompareCaseInsensitive) == kCFCompareEqualTo )
mPrefs.listenerTypeFlags = (ListenerTypes)((unsigned int)mPrefs.listenerTypeFlags | kPWPrefsUnixDomainSocket);
}
}
// kerberos cache limit for replication
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_KerberosCacheLimit), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFNumberGetTypeID() &&
CFNumberGetValue( (CFNumberRef)valueRef, kCFNumberLongType, &aLongValue) )
{
mPrefs.kerberosCacheLimit = (unsigned long)aLongValue;
}
// sync SASL plug-in list
mPrefs.syncSASLPluginList = [self longValueForKey:CFSTR(kPWPrefsKey_SyncSASLPluginList) inDictionary:mPrefsDict];
// get the SASL plug-in state list
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_SASLPluginList), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFDictionaryGetTypeID() )
{
SASLPluginListConverterContext context = { 0, &(mPrefs.saslPluginState[0]) };
CFDictionaryApplyFunction( (CFDictionaryRef)valueRef, ConvertCFDictToFlatArray, (void *)&context );
}
else
{
[self buildSASLMechPrefsFromCurrentSASLState];
}
// deleteWait
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_DeleteWaitInMinutes), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFNumberGetTypeID() &&
CFNumberGetValue( (CFNumberRef)valueRef, kCFNumberLongType, &aLongValue) )
{
mPrefs.deleteWait = MAX(aLongValue * 60, 60);
}
// purgeWait
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_PurgeInMinutes), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFNumberGetTypeID() &&
CFNumberGetValue( (CFNumberRef)valueRef, kCFNumberLongType, &aLongValue) )
{
mPrefs.purgeWait = MAX(aLongValue * 60, 120);
}
// debug log options
if ( CFDictionaryGetValueIfPresent( mPrefsDict, CFSTR(kPWPrefsKey_DebugLogOptions), (const void **)&valueRef ) &&
CFGetTypeID(valueRef) == CFDictionaryGetTypeID() )
{
mPrefs.logOptions.changeList = (BOOL)([self longValueForKey:CFSTR(kPWPrefsValue_LogChangeList)
inDictionary:(CFDictionaryRef)valueRef] != 0);
mPrefs.logOptions.quit = (BOOL)([self longValueForKey:CFSTR(kPWPrefsValue_LogQuit)
inDictionary:(CFDictionaryRef)valueRef] != 0);
}
}
else
{
[self buildSASLMechPrefsFromCurrentSASLState];
}
return result;
}
-(int)savePrefs
{
CFMutableDictionaryRef prefsDict;
CFMutableArrayRef portArray;
CFNumberRef listenerPortRef;
CFMutableArrayRef interfaceArray;
CFStringRef interfaceString;
int idx;
prefsDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if ( prefsDict == NULL )
return -1;
CFBooleanRef passiveReplicationRef = mPrefs.passiveReplicationOnly ? kCFBooleanTrue : kCFBooleanFalse;
CFBooleanRef provideReplicationRef = mPrefs.provideReplicationOnly ? kCFBooleanTrue : kCFBooleanFalse;
CFNumberRef badTrialRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &mPrefs.badTrialDelay );
CFNumberRef timeSkewRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &mPrefs.timeSkewMaxSeconds );
CFNumberRef syncIntervalRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &mPrefs.syncInterval );
CFNumberRef testSpillBucketRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &mPrefs.testSpillBucket );
CFNumberRef kerberosCacheLimitRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &mPrefs.kerberosCacheLimit );
CFNumberRef prefsVersionRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &mPrefs.prefsVersion );
CFBooleanRef syncSASLPluginListRef = mPrefs.syncSASLPluginList ? kCFBooleanTrue : kCFBooleanFalse;
CFStringRef realmRef = NULL;
CFStringRef externalToolRef = NULL;
long waitMins = mPrefs.deleteWait / 60;
CFNumberRef deleteWaitInMinutesRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &waitMins );
waitMins = mPrefs.purgeWait / 60;
CFNumberRef purgeInMinutesRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &waitMins );
if ( passiveReplicationRef != NULL )
CFDictionaryAddValue( prefsDict, CFSTR(kPWPrefsKey_PassiveReplicationOnly), passiveReplicationRef );
if ( provideReplicationRef != NULL )
CFDictionaryAddValue( prefsDict, CFSTR(kPWPrefsKey_ProvideReplicationOnly), provideReplicationRef );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_BadTrialDelay), badTrialRef );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_TimeSkewMaxSeconds), timeSkewRef );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_SyncInterval), syncIntervalRef );
portArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( portArray != NULL )
{
for ( idx = 0; idx < kMaxListenerPorts; idx++ )
{
if ( mPrefs.listenerPort[idx] != 0 )
{
listenerPortRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberShortType, &mPrefs.listenerPort[idx] );
if ( listenerPortRef != NULL )
{
CFArrayAppendValue( portArray, listenerPortRef );
CFRelease( listenerPortRef );
}
}
}
CFDictionaryAddValue( prefsDict, CFSTR(kPWPrefsKey_ListenerPorts), portArray );
CFRelease( portArray );
}
// interface list
interfaceArray = CFArrayCreateMutable( kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks );
if ( interfaceArray != NULL )
{
if ( (unsigned)mPrefs.listenerTypeFlags & kPWPrefsEnet )
{
interfaceString = CFStringCreateWithCString( kCFAllocatorDefault, kPWPrefsValue_ListenerEnet, kCFStringEncodingUTF8 );
if ( interfaceString != NULL )
{
CFArrayAppendValue( interfaceArray, interfaceString );
CFRelease( interfaceString );
}
}
if ( (unsigned)mPrefs.listenerTypeFlags & kPWPrefsLocal )
{
interfaceString = CFStringCreateWithCString( kCFAllocatorDefault, kPWPrefsValue_ListenerLocal, kCFStringEncodingUTF8 );
if ( interfaceString != NULL )
{
CFArrayAppendValue( interfaceArray, interfaceString );
CFRelease( interfaceString );
}
}
if ( (unsigned)mPrefs.listenerTypeFlags & kPWPrefsUnixDomainSocket )
{
interfaceString = CFStringCreateWithCString( kCFAllocatorDefault, kPWPrefsValue_ListenerUDSocket, kCFStringEncodingUTF8 );
if ( interfaceString != NULL )
{
CFArrayAppendValue( interfaceArray, interfaceString );
CFRelease( interfaceString );
}
}
CFDictionaryAddValue( prefsDict, CFSTR(kPWPrefsKey_ListenerInterfaces), interfaceArray );
CFRelease( interfaceArray );
}
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_TestSpillBucket), testSpillBucketRef );
if ( mPrefs.realmSet )
{
realmRef = CFStringCreateWithCString( kCFAllocatorDefault, mPrefs.realm, kCFStringEncodingUTF8 );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_SASLRealm), realmRef );
}
if ( mPrefs.externalToolPath[0] == '\0' )
mPrefs.externalToolSet = NO;
externalToolRef = CFStringCreateWithCString( kCFAllocatorDefault,
mPrefs.externalToolSet ? mPrefs.externalToolPath : kPWPrefsValue_ExternalToolNone,
kCFStringEncodingUTF8 );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_ExternalTool), externalToolRef );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_KerberosCacheLimit), kerberosCacheLimitRef );
if ( syncSASLPluginListRef != NULL )
CFDictionaryAddValue( prefsDict, CFSTR(kPWPrefsKey_SyncSASLPluginList), syncSASLPluginListRef );
CFDictionaryRef saslListDict = [self saslMechArrayToCFDictionary];
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_SASLPluginList), saslListDict );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_DeleteWaitInMinutes), deleteWaitInMinutesRef );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_PurgeInMinutes), purgeInMinutesRef );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_PrefsVersion), prefsVersionRef );
// debug log options
CFMutableDictionaryRef logOptionDictRef = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
if ( logOptionDictRef != NULL )
{
CFDictionaryAddValue( logOptionDictRef, CFSTR(kPWPrefsValue_LogChangeList),
mPrefs.logOptions.changeList ? kCFBooleanTrue : kCFBooleanFalse );
CFDictionaryAddValue( logOptionDictRef, CFSTR(kPWPrefsValue_LogQuit),
mPrefs.logOptions.quit ? kCFBooleanTrue : kCFBooleanFalse );
TransferItemToCFDictionary( prefsDict, CFSTR(kPWPrefsKey_DebugLogOptions), logOptionDictRef );
}
if ( mPrefsDict != NULL )
CFRelease( mPrefsDict );
mPrefsDict = prefsDict;
return [self saveXMLData];
}
-(void)setRealm:(const char *)inRealm
{
if ( inRealm != NULL ) {
mPrefs.realmSet = YES;
strlcpy( mPrefs.realm, inRealm, sizeof(mPrefs.realm) );
}
}
-(void)buildSASLMechPrefsFromCurrentSASLState
{
const char *knownMechList[] =
{ "APOP", "CRAM-MD5", "CRYPT", "DHX", "DIGEST-MD5", "GSSAPI", "KERBEROS_V4", "MS-CHAPv2", "NTLM", "OTP",
"PPS", "SMB-LAN-MANAGER", "SMB-NT", "SMB-NTLMv2", "TWOWAYRANDOM", "WEBDAV-DIGEST", NULL };
int idx;
char *pluginFileName = NULL;
BOOL requiresPlain = NO;
struct stat sb;
char path[PATH_MAX];
for ( idx = 0; knownMechList[idx] != NULL && idx < kMaxSASLPlugins; idx++ )
{
strlcpy( mPrefs.saslPluginState[idx].name, knownMechList[idx], SASL_MECHNAMEMAX + 1 );
mPrefs.saslPluginState[idx].state = kSASLPluginStateDisabled;
if ( pwsf_GetSASLMechInfo(knownMechList[idx], &pluginFileName, (bool *)&requiresPlain) )
{
snprintf( path, sizeof(path), "/usr/lib/sasl2/ if ( stat(path, &sb) == 0 )
mPrefs.saslPluginState[idx].state = kSASLPluginStateAllowed;
}
}
}
-(CFDictionaryRef)saslMechArrayToCFDictionary
{
CFMutableDictionaryRef cfDict = NULL;
CFStringRef keyString = NULL;
CFStringRef valueString = NULL;
int idx;
cfDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if ( cfDict != NULL )
{
for ( idx = 0; idx < kMaxSASLPlugins; idx++ )
{
if ( mPrefs.saslPluginState[idx].name[0] == '\0' )
break;
keyString = CFStringCreateWithCString( kCFAllocatorDefault, mPrefs.saslPluginState[idx].name, kCFStringEncodingUTF8 );
if ( keyString != NULL )
{
switch ( mPrefs.saslPluginState[idx].state )
{
case kSASLPluginStateAllowed:
valueString = CFSTR("ON");
break;
default:
valueString = CFSTR("OFF");
break;
}
CFDictionaryAddValue( cfDict, keyString, valueString );
CFRelease( keyString );
}
}
}
return cfDict;
}
-(SASLPluginStatus)getSASLPluginStatus:(const char *)inSASLPluginName foundAtIndex:(int *)outIndex
{
SASLPluginStatus result = kSASLPluginStateUnlisted;
int idx;
if ( outIndex != NULL )
*outIndex = -1;
// array size is (kMaxSASLPlugins + 1)
for ( idx = 0; idx <= kMaxSASLPlugins; idx++ )
{
if ( mPrefs.saslPluginState[idx].name[0] == '\0' )
break;
if ( strcmp(mPrefs.saslPluginState[idx].name, inSASLPluginName) == 0 )
{
result = mPrefs.saslPluginState[idx].state;
if ( outIndex != NULL )
*outIndex = idx;
break;
}
}
return result;
}
-(BOOL)methodExists:(const char *)method inArray:(CFArrayRef)inActivePluginArray
{
CFIndex methodCount = 0;
BOOL result = NO;
CFIndex index;
CFStringRef testString;
CFStringRef aString;
if ( inActivePluginArray == NULL )
return NO;
methodCount = CFArrayGetCount( inActivePluginArray );
if ( methodCount <= 0 )
return NO;
testString = CFStringCreateWithCString( NULL, method, kCFStringEncodingUTF8 );
if ( !testString )
return NO;
for ( index = 0; index < methodCount; index++ )
{
aString = (CFStringRef) CFArrayGetValueAtIndex( inActivePluginArray, index );
if ( aString && CFStringCompare( aString, testString, 0 ) == kCFCompareEqualTo )
{
result = YES;
break;
}
}
CFRelease( testString );
return result;
}
-(int)statPrefsFileAndGetModDate:(struct timespec *)outModDate
{
struct stat sb;
int result;
if ( outModDate != NULL ) {
outModDate->tv_sec = 0;
outModDate->tv_nsec = 0;
}
result = lstat( kPWPrefsFile, &sb );
if ( result == 0 && outModDate != NULL )
*outModDate = sb.st_mtimespec;
return result;
}
-(int)loadXMLData
{
CFStringRef myReplicaDataFilePathRef;
CFURLRef myReplicaDataFileRef;
CFReadStreamRef myReadStreamRef;
CFPropertyListRef myPropertyListRef;
CFStringRef errorString;
CFPropertyListFormat myPLFormat;
struct timespec modDate;
if ( [self statPrefsFileAndGetModDate:&modDate] != 0 )
return -1;
myReplicaDataFilePathRef = CFStringCreateWithCString( kCFAllocatorDefault, kPWPrefsFile, kCFStringEncodingUTF8 );
if ( myReplicaDataFilePathRef == NULL )
return -1;
myReplicaDataFileRef = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, myReplicaDataFilePathRef, kCFURLPOSIXPathStyle, NO );
CFRelease( myReplicaDataFilePathRef );
if ( myReplicaDataFileRef == NULL )
return -1;
myReadStreamRef = CFReadStreamCreateWithFile( kCFAllocatorDefault, myReplicaDataFileRef );
CFRelease( myReplicaDataFileRef );
if ( myReadStreamRef == NULL )
return -1;
if ( ! CFReadStreamOpen( myReadStreamRef ) )
{
CFRelease( myReadStreamRef );
return -1;
}
errorString = NULL;
myPLFormat = kCFPropertyListXMLFormat_v1_0;
myPropertyListRef = CFPropertyListCreateFromStream( kCFAllocatorDefault, myReadStreamRef, 0, kCFPropertyListMutableContainersAndLeaves, &myPLFormat, &errorString );
CFReadStreamClose( myReadStreamRef );
CFRelease( myReadStreamRef );
if ( errorString != NULL )
CFRelease( errorString );
if ( myPropertyListRef == NULL )
return -1;
if ( CFGetTypeID(myPropertyListRef) != CFDictionaryGetTypeID() )
{
CFRelease( myPropertyListRef );
return -1;
}
if ( mPrefsDict != NULL )
CFRelease( mPrefsDict );
mPrefsDict = (CFMutableDictionaryRef)myPropertyListRef;
mPrefsFileModDate = modDate;
return 0;
}
-(int)saveXMLData
{
CFStringRef myReplicaDataFilePathRef;
CFURLRef myReplicaDataFileRef;
CFWriteStreamRef myWriteStreamRef;
CFStringRef errorString;
myReplicaDataFilePathRef = CFStringCreateWithCString( kCFAllocatorDefault, kPWPrefsFile, kCFStringEncodingUTF8 );
if ( myReplicaDataFilePathRef == NULL )
return -1;
myReplicaDataFileRef = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, myReplicaDataFilePathRef, kCFURLPOSIXPathStyle, NO );
CFRelease( myReplicaDataFilePathRef );
if ( myReplicaDataFileRef == NULL )
return -1;
myWriteStreamRef = CFWriteStreamCreateWithFile( kCFAllocatorDefault, myReplicaDataFileRef );
CFRelease( myReplicaDataFileRef );
if ( myWriteStreamRef == NULL )
return -1;
if ( ! CFWriteStreamOpen( myWriteStreamRef ) )
{
CFRelease( myWriteStreamRef );
return -1;
}
errorString = NULL;
CFPropertyListWriteToStream( (CFPropertyListRef) mPrefsDict, myWriteStreamRef, kCFPropertyListXMLFormat_v1_0, &errorString );
CFWriteStreamClose( myWriteStreamRef );
CFRelease( myWriteStreamRef );
if ( errorString != NULL )
CFRelease( errorString );
[self statPrefsFileAndGetModDate:&mPrefsFileModDate];
return 0;
}
-(long)longValueForKey:(CFStringRef)key inDictionary:(CFDictionaryRef)dict
{
CFTypeRef valueRef = NULL;
long result = 0;
if ( CFDictionaryGetValueIfPresent( dict, key, (const void **)&valueRef ) )
{
if ( CFGetTypeID(valueRef) == CFBooleanGetTypeID() )
result = CFBooleanGetValue( (CFBooleanRef)valueRef );
else if ( CFGetTypeID(valueRef) == CFNumberGetTypeID() )
CFNumberGetValue( (CFNumberRef)valueRef, kCFNumberLongType, &result );
}
return result;
}
-(BOOL)passiveReplicationOnly { return mPrefs.passiveReplicationOnly; };
-(BOOL)provideReplicationOnly { return mPrefs.provideReplicationOnly; };
-(unsigned long)badTrialDelay { return mPrefs.badTrialDelay; };
-(unsigned long)maxTimeSkewForSync { return mPrefs.timeSkewMaxSeconds; };
-(unsigned long)syncInterval { return mPrefs.syncInterval; };
-(BOOL)localListenersOnly { return (mPrefs.listenerTypeFlags == kPWPrefsLocal); };
-(BOOL)testSpillBucket { return mPrefs.testSpillBucket; };
-(const char *)realm { return (mPrefs.realmSet ? mPrefs.realm : NULL); };
-(const char *)passwordToolPath { return (mPrefs.externalToolSet ? mPrefs.externalToolPath : NULL); };
-(unsigned long)kerberosCacheLimit { return mPrefs.kerberosCacheLimit; };
-(BOOL)syncSASLPluginList { return mPrefs.syncSASLPluginList; };
-(time_t)deleteWait { return mPrefs.deleteWait; };
-(time_t)purgeWait { return mPrefs.purgeWait; };
-(const PWSDebugLogOptions *)logOptions { return &mPrefs.logOptions; };
@end