DLDBListCFPref.cpp [plain text]
#include "DLDBListCFPref.h"
#include <Security/cssmapple.h>
#include <security_utilities/debugging.h>
#include <security_utilities/utilities.h>
#include <memory>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/param.h>
#include <copyfile.h>
#include <xpc/private.h>
#include <syslog.h>
#include <sandbox.h>
dispatch_once_t AppSandboxChecked;
xpc_object_t KeychainHomeFromXPC;
using namespace CssmClient;
static const double kDLDbListCFPrefRevertInterval = 30.0;
#define kKeyGUID CFSTR("GUID")
#define kKeySubserviceId CFSTR("SubserviceId")
#define kKeySubserviceType CFSTR("SubserviceType")
#define kKeyDbName CFSTR("DbName")
#define kKeyDbLocation CFSTR("DbLocation")
#define kKeyActive CFSTR("Active")
#define kKeyMajorVersion CFSTR("MajorVersion")
#define kKeyMinorVersion CFSTR("MinorVersion")
#define kDefaultDLDbListKey CFSTR("DLDBSearchList")
#define kDefaultKeychainKey CFSTR("DefaultKeychain")
#define kLoginKeychainKey CFSTR("LoginKeychain")
#define kUserDefaultPath "~/Library/Preferences/com.apple.security.plist"
#define kSystemDefaultPath "/Library/Preferences/com.apple.security.plist"
#define kCommonDefaultPath "/Library/Preferences/com.apple.security-common.plist"
#define kLoginKeychainPathPrefix "~/Library/Keychains/"
#define kUserLoginKeychainPath "~/Library/Keychains/login.keychain"
#define kSystemLoginKeychainPath "/Library/Keychains/System.keychain"
const time_t kPasswordCacheExpire = 30;
PasswordDBLookup::PasswordDBLookup () : mValid (false), mCurrent (0), mTime (0)
{
}
void PasswordDBLookup::lookupInfoOnUID (uid_t uid)
{
time_t currentTime = time (NULL);
if (!mValid || uid != mCurrent || currentTime - mTime >= kPasswordCacheExpire)
{
struct passwd* pw = getpwuid(uid);
if (pw == NULL)
{
UnixError::throwMe (EPERM);
}
mDirectory = pw->pw_dir;
mName = pw->pw_name;
mValid = true;
mCurrent = uid;
mTime = currentTime;
secdebug("secpref", "uid=%d caching home=%s", uid, pw->pw_dir);
endpwent();
}
}
PasswordDBLookup *DLDbListCFPref::mPdbLookup = NULL;
DLDbListCFPref::DLDbListCFPref(SecPreferencesDomain domain) : mDomain(domain), mPropertyList(NULL), mChanged(false),
mSearchListSet(false), mDefaultDLDbIdentifierSet(false), mLoginDLDbIdentifierSet(false)
{
secdebug("secpref", "New DLDbListCFPref %p for domain %d", this, domain);
loadPropertyList(true);
}
void DLDbListCFPref::set(SecPreferencesDomain domain)
{
save();
mDomain = domain;
secdebug("secpref", "DLDbListCFPref %p domain set to %d", this, domain);
if (loadPropertyList(true))
resetCachedValues();
}
DLDbListCFPref::~DLDbListCFPref()
{
save();
if (mPropertyList)
CFRelease(mPropertyList);
}
void
DLDbListCFPref::forceUserSearchListReread()
{
mPrefsTimeStamp = CFAbsoluteTimeGetCurrent() - kDLDbListCFPrefRevertInterval;
}
bool
DLDbListCFPref::loadPropertyList(bool force)
{
string prefsPath;
switch (mDomain)
{
case kSecPreferencesDomainUser:
prefsPath = ExpandTildesInPath(kUserDefaultPath);
break;
case kSecPreferencesDomainSystem:
prefsPath = kSystemDefaultPath;
break;
case kSecPreferencesDomainCommon:
prefsPath = kCommonDefaultPath;
break;
default:
MacOSError::throwMe(errSecInvalidPrefsDomain);
}
secdebug("secpref", "force=%s prefsPath=%s", force ? "true" : "false",
prefsPath.c_str());
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
if (mPrefsPath != prefsPath)
{
mPrefsPath = prefsPath;
if (mPropertyList)
{
CFRelease(mPropertyList);
mPropertyList = NULL;
}
mPrefsTimeStamp = now;
}
else if (!force)
{
if (now - mPrefsTimeStamp < kDLDbListCFPrefRevertInterval)
return false;
mPrefsTimeStamp = now;
}
struct stat st;
if (stat(mPrefsPath.c_str(), &st))
{
if (errno == ENOENT)
{
if (mPropertyList)
{
if (CFDictionaryGetCount(mPropertyList) == 0)
return false;
CFRelease(mPropertyList);
}
mPropertyList = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
return true;
}
}
else
{
if (mPropertyList)
{
if (mTimespec.tv_sec == st.st_mtimespec.tv_sec
&& mTimespec.tv_nsec == st.st_mtimespec.tv_nsec)
return false;
}
mTimespec = st.st_mtimespec;
}
CFMutableDictionaryRef thePropertyList = NULL;
CFMutableDataRef xmlData = NULL;
CFStringRef errorString = NULL;
int fd = -1;
do
{
fd = open(mPrefsPath.c_str(), O_RDONLY, 0);
if (fd < 0)
break;
off_t theSize = lseek(fd, 0, SEEK_END);
if (theSize <= 0)
break;
if (lseek(fd, 0, SEEK_SET))
break;
xmlData = CFDataCreateMutable(NULL, CFIndex(theSize));
if (!xmlData)
break;
CFDataSetLength(xmlData, CFIndex(theSize));
void *buffer = reinterpret_cast<void *>(CFDataGetMutableBytePtr(xmlData));
if (!buffer)
break;
ssize_t bytesRead = read(fd, buffer, theSize);
if (bytesRead != theSize)
break;
thePropertyList = CFMutableDictionaryRef(CFPropertyListCreateFromXMLData(NULL, xmlData, kCFPropertyListMutableContainers, &errorString));
if (!thePropertyList)
break;
if (CFGetTypeID(thePropertyList) != CFDictionaryGetTypeID())
{
CFRelease(thePropertyList);
thePropertyList = NULL;
break;
}
} while (0);
if (fd >= 0)
close(fd);
if (xmlData)
CFRelease(xmlData);
if (errorString)
CFRelease(errorString);
if (!thePropertyList)
{
thePropertyList = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
if (mPropertyList)
{
if (CFEqual(mPropertyList, thePropertyList))
{
CFRelease(thePropertyList);
return false;
}
CFRelease(mPropertyList);
}
mPropertyList = thePropertyList;
return true;
}
void
DLDbListCFPref::writePropertyList()
{
if (!mPropertyList || CFDictionaryGetCount(mPropertyList) == 0)
{
unlink(mPrefsPath.c_str());
}
else
{
if(testAndFixPropertyList())
return;
CFDataRef xmlData = CFPropertyListCreateXMLData(NULL, mPropertyList);
if (!xmlData)
return;
mode_t mode = 0666;
changeIdentity(UNPRIV);
int fd = open(mPrefsPath.c_str(), O_WRONLY|O_CREAT|O_TRUNC, mode);
changeIdentity(PRIV);
if (fd >= 0)
{
const void *buffer = CFDataGetBytePtr(xmlData);
size_t toWrite = CFDataGetLength(xmlData);
write(fd, buffer, toWrite);
fsync(fd);
struct stat st;
if (!fstat(fd, &st))
mTimespec = st.st_mtimespec;
close(fd);
}
CFRelease(xmlData);
}
mPrefsTimeStamp = CFAbsoluteTimeGetCurrent();
}
int
DLDbListCFPref::testAndFixPropertyList()
{
char *prefsPath = (char *)mPrefsPath.c_str();
int fd1, fd2, retval;
struct stat stbuf;
if((fd1 = open(prefsPath, O_RDONLY)) < 0) {
if (errno == ENOENT) return 0; else return -1;
}
if((retval = fstat(fd1, &stbuf)) == -1) return -1;
if(stbuf.st_uid != getuid()) {
char tempfile[MAXPATHLEN+1];
snprintf(tempfile, MAXPATHLEN, "%s.XXXXX", prefsPath);
mktemp(tempfile);
changeIdentity(UNPRIV);
if((fd2 = open(tempfile, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) {
retval = -1;
} else {
copyfile_state_t s = copyfile_state_alloc();
retval = fcopyfile(fd1, fd2, s, COPYFILE_DATA);
copyfile_state_free(s);
if(!retval) retval = ::unlink(prefsPath);
if(!retval) retval = ::rename(tempfile, prefsPath);
}
changeIdentity(PRIV);
close(fd2);
}
close(fd1);
return retval;
}
void
DLDbListCFPref::changeIdentity(ID_Direction toPriv)
{
if(toPriv == UNPRIV) {
savedEUID = geteuid();
savedEGID = getegid();
if(savedEGID != getgid()) setegid(getgid());
if(savedEUID != getuid()) seteuid(getuid());
} else {
if(savedEUID != getuid()) seteuid(savedEUID);
if(savedEGID != getgid()) setegid(savedEGID);
}
}
void
DLDbListCFPref::resetCachedValues()
{
mLoginDLDbIdentifier = mDefaultDLDbIdentifier = DLDbIdentifier();
mSearchList.clear();
changed(false);
mSearchListSet = mDefaultDLDbIdentifierSet = mLoginDLDbIdentifierSet = false;
mPrefsTimeStamp = CFAbsoluteTimeGetCurrent();
}
void DLDbListCFPref::save()
{
if (!hasChanged())
return;
loadPropertyList(true);
if (mSearchListSet)
{
if (mSearchList.size() == 1 && mSearchList[0] == defaultDLDbIdentifier() && mSearchList[0] == LoginDLDbIdentifier())
{
CFDictionaryRemoveValue(mPropertyList, kDefaultDLDbListKey);
}
else
{
CFMutableArrayRef searchArray = CFArrayCreateMutable(kCFAllocatorDefault, mSearchList.size(), &kCFTypeArrayCallBacks);
for (DLDbList::const_iterator ix=mSearchList.begin();ix!=mSearchList.end();ix++)
{
CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(*ix);
CFArrayAppendValue(searchArray, aDict);
CFRelease(aDict);
}
CFDictionarySetValue(mPropertyList, kDefaultDLDbListKey, searchArray);
CFRelease(searchArray);
}
}
if (mLoginDLDbIdentifierSet)
{
CFArrayRef loginArray = NULL;
if (!mLoginDLDbIdentifier)
{
loginArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks);
}
else if (!(mLoginDLDbIdentifier == LoginDLDbIdentifier()))
{
CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(mLoginDLDbIdentifier);
const void *value = reinterpret_cast<const void *>(aDict);
loginArray = CFArrayCreate(kCFAllocatorDefault, &value, 1, &kCFTypeArrayCallBacks);
CFRelease(aDict);
}
if (loginArray)
{
CFDictionarySetValue(mPropertyList, kLoginKeychainKey, loginArray);
CFRelease(loginArray);
}
else
CFDictionaryRemoveValue(mPropertyList, kLoginKeychainKey);
}
if (mDefaultDLDbIdentifierSet)
{
CFArrayRef defaultArray = NULL;
if (!mDefaultDLDbIdentifier)
{
defaultArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks);
}
else if (!(mDefaultDLDbIdentifier == LoginDLDbIdentifier()))
{
CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(mDefaultDLDbIdentifier);
const void *value = reinterpret_cast<const void *>(aDict);
defaultArray = CFArrayCreate(kCFAllocatorDefault, &value, 1, &kCFTypeArrayCallBacks);
CFRelease(aDict);
}
if (defaultArray)
{
CFDictionarySetValue(mPropertyList, kDefaultKeychainKey, defaultArray);
CFRelease(defaultArray);
}
else
CFDictionaryRemoveValue(mPropertyList, kDefaultKeychainKey);
}
writePropertyList();
changed(false);
}
DLDbIdentifier DLDbListCFPref::LoginDLDbIdentifier()
{
CSSM_VERSION theVersion={};
CssmSubserviceUid ssuid(gGuidAppleCSPDL,&theVersion,0,CSSM_SERVICE_DL|CSSM_SERVICE_CSP);
CssmNetAddress *dbLocation=NULL;
switch (mDomain) {
case kSecPreferencesDomainUser:
return DLDbIdentifier(ssuid, ExpandTildesInPath(kUserLoginKeychainPath).c_str(), dbLocation);
default:
assert(false);
case kSecPreferencesDomainSystem:
case kSecPreferencesDomainCommon:
return DLDbIdentifier(ssuid, kSystemLoginKeychainPath, dbLocation);
}
}
DLDbIdentifier DLDbListCFPref::JaguarLoginDLDbIdentifier()
{
CSSM_VERSION theVersion={};
CssmSubserviceUid ssuid(gGuidAppleCSPDL,&theVersion,0,CSSM_SERVICE_DL|CSSM_SERVICE_CSP);
CssmNetAddress *dbLocation=NULL;
switch (mDomain) {
case kSecPreferencesDomainUser:
{
string basepath = ExpandTildesInPath(kLoginKeychainPathPrefix) + getPwInfo(kUsername);
return DLDbIdentifier(ssuid,basepath.c_str(),dbLocation);
}
case kSecPreferencesDomainSystem:
case kSecPreferencesDomainCommon:
return DLDbIdentifier(ssuid, kSystemLoginKeychainPath, dbLocation);
default:
assert(false);
return DLDbIdentifier();
}
}
DLDbIdentifier DLDbListCFPref::makeDLDbIdentifier (const CSSM_GUID &guid, const CSSM_VERSION &version,
uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType,
const char* dbName, CSSM_NET_ADDRESS *dbLocation)
{
CssmSubserviceUid ssuid (guid, &version, subserviceId, subserviceType);
return DLDbIdentifier (ssuid, ExpandTildesInPath (dbName).c_str (), dbLocation);
}
DLDbIdentifier DLDbListCFPref::cfDictionaryRefToDLDbIdentifier(CFDictionaryRef theDict)
{
if (CFGetTypeID(theDict) != CFDictionaryGetTypeID())
throw std::logic_error("wrong type in property list");
CCFValue vGuid(::CFDictionaryGetValue(theDict,kKeyGUID));
string guidStr=vGuid;
const Guid guid(guidStr.c_str());
CSSM_VERSION theVersion={0,};
CCFValue vMajor(::CFDictionaryGetValue(theDict,kKeyMajorVersion));
theVersion.Major = vMajor;
CCFValue vMinor(::CFDictionaryGetValue(theDict,kKeyMinorVersion));
theVersion.Minor = vMinor;
CCFValue vSsid(::CFDictionaryGetValue(theDict,kKeySubserviceId));
uint32 subserviceId=sint32(vSsid);
CSSM_SERVICE_TYPE subserviceType=CSSM_SERVICE_DL;
CCFValue vSsType(::CFDictionaryGetValue(theDict,kKeySubserviceType));
subserviceType=vSsType;
CCFValue vDbName(::CFDictionaryGetValue(theDict,kKeyDbName));
string dbName=vDbName;
CssmNetAddress *dbLocation=NULL;
return makeDLDbIdentifier (guid, theVersion, subserviceId, subserviceType, dbName.c_str (), dbLocation);
}
void DLDbListCFPref::clearPWInfo ()
{
if (mPdbLookup != NULL)
{
delete mPdbLookup;
mPdbLookup = NULL;
}
}
string DLDbListCFPref::getPwInfo(PwInfoType type)
{
const char *value;
switch (type)
{
case kHomeDir:
if (KeychainHomeFromXPC) {
value = xpc_string_get_string_ptr(KeychainHomeFromXPC);
} else {
value = getenv("HOME");
}
if (value)
return value;
break;
case kUsername:
value = getenv("USER");
if (value)
return value;
break;
}
uid_t uid = geteuid();
if (!uid) uid = getuid();
if (mPdbLookup == NULL)
{
mPdbLookup = new PasswordDBLookup ();
}
mPdbLookup->lookupInfoOnUID (uid);
string result;
switch (type)
{
case kHomeDir:
result = mPdbLookup->getDirectory ();
break;
case kUsername:
result = mPdbLookup->getName ();
break;
}
return result;
}
static void check_app_sandbox()
{
if (!_xpc_runtime_is_app_sandboxed()) {
return;
}
extern xpc_object_t xpc_create_with_format(const char * format, ...);
xpc_connection_t con = xpc_connection_create("com.apple.security.XPCKeychainSandboxCheck", NULL);
xpc_connection_set_event_handler(con, ^(xpc_object_t event) {
xpc_type_t xtype = xpc_get_type(event);
if (XPC_TYPE_ERROR == xtype) {
syslog(LOG_ERR, "Keychain sandbox connection error: %s\n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
} else {
syslog(LOG_ERR, "Keychain sandbox unexpected connection event %p\n", event);
}
});
xpc_connection_resume(con);
xpc_object_t message = xpc_create_with_format("{op: GrantKeychainPaths}");
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(con, message);
xpc_type_t xtype = xpc_get_type(reply);
if (XPC_TYPE_DICTIONARY == xtype) {
#if 0
char *debug = xpc_copy_description(reply);
syslog(LOG_ERR, "DEBUG (KCsandbox) %s\n", debug);
free(debug);
#endif
xpc_object_t extensions_array = xpc_dictionary_get_value(reply, "extensions");
xpc_array_apply(extensions_array, ^(size_t index, xpc_object_t extension) {
char pbuf[MAXPATHLEN];
char *path = pbuf;
int status = sandbox_consume_fs_extension(xpc_string_get_string_ptr(extension), &path);
if (status) {
syslog(LOG_ERR, "Keychain sandbox consume extension error: s=%d p=%s %m\n", status, path);
}
return (bool)true;
});
KeychainHomeFromXPC = xpc_dictionary_get_value(reply, "keychain-home");
xpc_retain(KeychainHomeFromXPC);
xpc_release(con);
} else if (XPC_TYPE_ERROR == xtype) {
syslog(LOG_ERR, "Keychain sandbox message error: %s\n", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
} else {
syslog(LOG_ERR, "Keychain sandbox unexpected message reply type %p\n", xtype);
}
xpc_release(message);
xpc_release(reply);
}
string DLDbListCFPref::ExpandTildesInPath(const string &inPath)
{
dispatch_once(&AppSandboxChecked, ^{
check_app_sandbox();
});
if ((short)inPath.find("~/",0,2) == 0)
return getPwInfo(kHomeDir) + inPath.substr(1);
else
return inPath;
}
string DLDbListCFPref::StripPathStuff(const string &inPath)
{
if (inPath.find("/private/var/automount/Network/",0,31) == 0)
return inPath.substr(22);
if (inPath.find("/private/automount/Servers/",0,27) == 0)
return "/Network" + inPath.substr(18);
if (inPath.find("/automount/Servers/",0,19) == 0)
return "/Network" + inPath.substr(10);
if (inPath.find("/private/automount/Network/",0,27) == 0)
return inPath.substr(18);
if (inPath.find("/automount/Network/",0,19) == 0)
return inPath.substr(10);
if (inPath.find("/private/Network/",0,17) == 0)
return inPath.substr(8);
return inPath;
}
string DLDbListCFPref::AbbreviatedPath(const string &inPath)
{
string path = StripPathStuff(inPath);
string home = StripPathStuff(getPwInfo(kHomeDir) + "/");
size_t homeLen = home.length();
if (homeLen > 1 && path.find(home.c_str(), 0, homeLen) == 0)
return "~" + path.substr(homeLen - 1);
else
return path;
}
CFDictionaryRef DLDbListCFPref::dlDbIdentifierToCFDictionaryRef(const DLDbIdentifier& dldbIdentifier)
{
CFRef<CFMutableDictionaryRef> aDict(CFDictionaryCreateMutable(kCFAllocatorDefault,0,
&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks));
if (!aDict)
throw ::std::bad_alloc();
char buffer[Guid::stringRepLength+1];
const CssmSubserviceUid& ssuid=dldbIdentifier.ssuid();
const Guid &theGuid = Guid::overlay(ssuid.Guid);
CFRef<CFStringRef> stringGuid(::CFStringCreateWithCString(kCFAllocatorDefault,
theGuid.toString(buffer),kCFStringEncodingMacRoman));
if (stringGuid)
::CFDictionarySetValue(aDict,kKeyGUID,stringGuid);
if (ssuid.SubserviceId!=0)
{
CFRef<CFNumberRef> subserviceId(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceId));
if (subserviceId)
::CFDictionarySetValue(aDict,kKeySubserviceId,subserviceId);
}
if (ssuid.SubserviceType!=0)
{
CFRef<CFNumberRef> subserviceType(CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceType));
if (subserviceType)
::CFDictionarySetValue(aDict,kKeySubserviceType,subserviceType);
}
if (ssuid.Version.Major!=0 && ssuid.Version.Minor!=0)
{
CFRef<CFNumberRef> majorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Major));
if (majorVersion)
::CFDictionarySetValue(aDict,kKeyMajorVersion,majorVersion);
CFRef<CFNumberRef> minorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Minor));
if (minorVersion)
::CFDictionarySetValue(aDict,kKeyMinorVersion,minorVersion);
}
const char *dbName=dldbIdentifier.dbName();
if (dbName)
{
CFRef<CFStringRef> theDbName(::CFStringCreateWithCString(kCFAllocatorDefault,AbbreviatedPath(dbName).c_str(),kCFStringEncodingUTF8));
::CFDictionarySetValue(aDict,kKeyDbName,theDbName);
}
const CSSM_NET_ADDRESS *dbLocation=dldbIdentifier.dbLocation();
if (dbLocation!=NULL && dbLocation->AddressType!=CSSM_ADDR_NONE)
{
CFRef<CFDataRef> theData(::CFDataCreate(kCFAllocatorDefault,dbLocation->Address.Data,dbLocation->Address.Length));
if (theData)
::CFDictionarySetValue(aDict,kKeyDbLocation,theData);
}
::CFRetain(aDict);
return aDict;
}
bool DLDbListCFPref::revert(bool force)
{
if (!loadPropertyList(force))
return false;
resetCachedValues();
return true;
}
void
DLDbListCFPref::add(const DLDbIdentifier &dldbIdentifier)
{
std::string canon = ExpandTildesInPath(AbbreviatedPath(dldbIdentifier.dbName()).c_str());
DLDbIdentifier localIdentifier (dldbIdentifier.ssuid(), canon.c_str(), dldbIdentifier.dbLocation ());
if (member(localIdentifier))
return;
mSearchList.push_back(localIdentifier);
changed(true);
}
void
DLDbListCFPref::remove(const DLDbIdentifier &dldbIdentifier)
{
searchList();
for (vector<DLDbIdentifier>::iterator ix = mSearchList.begin(); ix != mSearchList.end(); ++ix)
{
if (*ix==dldbIdentifier) {
mSearchList.erase(ix);
changed(true);
break;
}
}
}
void
DLDbListCFPref::rename(const DLDbIdentifier &oldId, const DLDbIdentifier &newId)
{
searchList();
for (vector<DLDbIdentifier>::iterator ix = mSearchList.begin();
ix != mSearchList.end(); ++ix)
{
if (*ix==oldId)
{
*ix = newId;
changed(true);
}
else if (*ix==newId)
{
mSearchList.erase(ix);
changed(true);
}
}
}
bool
DLDbListCFPref::member(const DLDbIdentifier &dldbIdentifier)
{
for (vector<DLDbIdentifier>::const_iterator ix = searchList().begin(); ix != mSearchList.end(); ++ix)
{
if (ix->mImpl == NULL)
{
continue;
}
if (ix->ssuid() == dldbIdentifier.ssuid())
{
char localPath[PATH_MAX],
inPath[PATH_MAX];
const char* localPathPtr = cached_realpath(ix->dbName(), localPath);
const char* inPathPtr = cached_realpath(dldbIdentifier.dbName(), inPath);
if (localPathPtr == NULL)
{
localPathPtr = ix->dbName();
}
if (inPathPtr == NULL)
{
inPathPtr = dldbIdentifier.dbName();
}
if (strcmp(localPathPtr, inPathPtr) == 0)
{
return true;
}
}
}
return false;
}
const vector<DLDbIdentifier> &
DLDbListCFPref::searchList()
{
if (!mSearchListSet)
{
CFArrayRef searchList = reinterpret_cast<CFArrayRef>(CFDictionaryGetValue(mPropertyList, kDefaultDLDbListKey));
if (searchList && CFGetTypeID(searchList) != CFArrayGetTypeID())
searchList = NULL;
if (searchList)
{
CFIndex top = CFArrayGetCount(searchList);
for (CFIndex idx = 0; idx < top; ++idx)
{
CFDictionaryRef theDict = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(searchList, idx));
try
{
mSearchList.push_back(cfDictionaryRefToDLDbIdentifier(theDict));
}
catch (...)
{
}
}
if (top > 0 && mSearchList.size() == 0)
searchList = NULL;
}
if (!searchList && static_cast<bool>(defaultDLDbIdentifier()))
mSearchList.push_back(mDefaultDLDbIdentifier);
mSearchListSet = true;
}
return mSearchList;
}
void
DLDbListCFPref::searchList(const vector<DLDbIdentifier> &searchList)
{
vector<DLDbIdentifier> newList(searchList);
mSearchList.swap(newList);
mSearchListSet = true;
changed(true);
}
void
DLDbListCFPref::defaultDLDbIdentifier(const DLDbIdentifier &dlDbIdentifier)
{
if (!(defaultDLDbIdentifier() == dlDbIdentifier))
{
mDefaultDLDbIdentifier = dlDbIdentifier;
changed(true);
}
}
const DLDbIdentifier &
DLDbListCFPref::defaultDLDbIdentifier()
{
if (!mDefaultDLDbIdentifierSet)
{
CFArrayRef defaultArray = reinterpret_cast<CFArrayRef>(CFDictionaryGetValue(mPropertyList, kDefaultKeychainKey));
if (defaultArray && CFGetTypeID(defaultArray) != CFArrayGetTypeID())
defaultArray = NULL;
if (defaultArray && CFArrayGetCount(defaultArray) > 0)
{
CFDictionaryRef defaultDict = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(defaultArray, 0));
try
{
secdebug("secpref", "getting default DLDbIdentifier from defaultDict");
mDefaultDLDbIdentifier = cfDictionaryRefToDLDbIdentifier(defaultDict);
secdebug("secpref", "now we think the default keychain is %s", (mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() : "<NULL>");
}
catch (...)
{
defaultArray = NULL;
}
}
if (!defaultArray)
{
mDefaultDLDbIdentifier = loginDLDbIdentifier();
secdebug("secpref", "now we think the default keychain is: %s", (mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() :
"Name doesn't exist");
struct stat st;
int st_result = stat(mDefaultDLDbIdentifier.dbName(), &st);
if (st_result)
{
secdebug("secpref", "stat(%s) -> %d", mDefaultDLDbIdentifier.dbName(), st_result);
mDefaultDLDbIdentifier = DLDbIdentifier(); secdebug("secpref", "after DLDbIdentifier(), we think the default keychain is %s", static_cast<bool>(mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() : "<NULL>");
}
}
mDefaultDLDbIdentifierSet = true;
}
return mDefaultDLDbIdentifier;
}
void
DLDbListCFPref::loginDLDbIdentifier(const DLDbIdentifier &dlDbIdentifier)
{
if (!(loginDLDbIdentifier() == dlDbIdentifier))
{
mLoginDLDbIdentifier = dlDbIdentifier;
changed(true);
}
}
const DLDbIdentifier &
DLDbListCFPref::loginDLDbIdentifier()
{
if (!mLoginDLDbIdentifierSet)
{
CFArrayRef loginArray = reinterpret_cast<CFArrayRef>(CFDictionaryGetValue(mPropertyList, kLoginKeychainKey));
if (loginArray && CFGetTypeID(loginArray) != CFArrayGetTypeID())
loginArray = NULL;
if (loginArray && CFArrayGetCount(loginArray) > 0)
{
CFDictionaryRef loginDict = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(loginArray, 0));
try
{
secdebug("secpref", "Getting login DLDbIdentifier from loginDict");
mLoginDLDbIdentifier = cfDictionaryRefToDLDbIdentifier(loginDict);
secdebug("secpref", "we think the login keychain is %s", static_cast<bool>(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : "<NULL>");
}
catch (...)
{
loginArray = NULL;
}
}
if (!loginArray)
{
mLoginDLDbIdentifier = LoginDLDbIdentifier();
secdebug("secpref", "after LoginDLDbIdentifier(), we think the login keychain is %s", static_cast<bool>(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : "<NULL>");
}
mLoginDLDbIdentifierSet = true;
}
return mLoginDLDbIdentifier;
}