X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_keychain/lib/DLDBListCFPref.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/DLDBListCFPref.cpp b/Security/libsecurity_keychain/lib/DLDBListCFPref.cpp deleted file mode 100644 index 4836f4dc..00000000 --- a/Security/libsecurity_keychain/lib/DLDBListCFPref.cpp +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * Copyright (c) 2000-2004,2011-2014 Apple 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@ - */ - - -/* - DLDBListCFPref.cpp -*/ - -#include "DLDBListCFPref.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -dispatch_once_t AppSandboxChecked; -xpc_object_t KeychainHomeFromXPC; - -using namespace CssmClient; - -static const double kDLDbListCFPrefRevertInterval = 30.0; - -// normal debug calls, which get stubbed out for deployment builds - -#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" - - -// A utility class for managing password database lookups - -const time_t kPasswordCacheExpire = 30; // number of seconds cached password db info is valid - -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; - -//------------------------------------------------------------------------------------- -// -// Lists of DL/DBs, with CFPreferences backing store -// -//------------------------------------------------------------------------------------- - -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() -{ - // set mPrefsTimeStamp so that it will "expire" the next time loadPropertyList is called - 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 for some reason the prefs file path has changed, blow away the old plist and force an update - 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(CFDataGetMutableBytePtr(xmlData)); - if (!buffer) - break; - ssize_t bytesRead = read(fd, buffer, (size_t)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)) - { - // The new property list is the same as the old one, so nothing has changed. - CFRelease(thePropertyList); - return false; - } - CFRelease(mPropertyList); - } - - mPropertyList = thePropertyList; - return true; -} - -void -DLDbListCFPref::writePropertyList() -{ - if (!mPropertyList || CFDictionaryGetCount(mPropertyList) == 0) - { - // There is nothing in the mPropertyList dictionary, - // so we don't need a prefs file. - unlink(mPrefsPath.c_str()); - } - else - { - if(testAndFixPropertyList()) - return; - - CFDataRef xmlData = CFPropertyListCreateXMLData(NULL, mPropertyList); - if (!xmlData) - return; // Bad out of memory or something evil happened let's act like CF and do nothing. - - // The prefs file should at least be made readable by user/group/other and writable by the owner. - // Change from euid to ruid if needed for the duration of the new prefs file creat. - - 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); - /* ssize_t bytesWritten = */ write(fd, buffer, toWrite); - // Emulate CFPreferences by not checking for any errors. - - fsync(fd); - struct stat st; - if (!fstat(fd, &st)) - mTimespec = st.st_mtimespec; - - close(fd); - } - - CFRelease(xmlData); - } - - mPrefsTimeStamp = CFAbsoluteTimeGetCurrent(); -} - -// This function can clean up some problems caused by setuid clients. We've had instances where the -// Keychain search list has become owned by root, but is still able to be re-written by the user because -// of the permissions on the directory above. We'll take advantage of that fact to recreate the file with -// the correct ownership by copying it. - -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; // Doesn't exist - the default case - 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; -} - -// Encapsulated process uid/gid change routine. -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() -{ - // Unset the login and default Keychain. - mLoginDLDbIdentifier = mDefaultDLDbIdentifier = DLDbIdentifier(); - - // Clear the searchList. - mSearchList.clear(); - - changed(false); - - // Note that none of our cached values are valid - mSearchListSet = mDefaultDLDbIdentifierSet = mLoginDLDbIdentifierSet = false; - - mPrefsTimeStamp = CFAbsoluteTimeGetCurrent(); -} - -void DLDbListCFPref::save() -{ - if (!hasChanged()) - return; - - // Resync from disc to make sure we don't clobber anyone elses changes. - // @@@ This is probably already done by the next layer up so we don't - // really need to do it here again. - loadPropertyList(true); - - // Do the searchList first since it might end up invoking defaultDLDbIdentifier() which can set - // mLoginDLDbIdentifierSet and mDefaultDLDbIdentifierSet to true. - if (mSearchListSet) - { - // Make a temporary CFArray with the contents of the vector - if (mSearchList.size() == 1 && mSearchList[0] == defaultDLDbIdentifier() && mSearchList[0] == LoginDLDbIdentifier()) - { - // The only element in the search list is the default keychain, which is a - // post Jaguar style login keychain, so omit the entry from the prefs file. - 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) - { - // Make a temporary CFArray with the login keychain - CFArrayRef loginArray = NULL; - if (!mLoginDLDbIdentifier) - { - loginArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks); - } - else if (!(mLoginDLDbIdentifier == LoginDLDbIdentifier())) - { - CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(mLoginDLDbIdentifier); - const void *value = reinterpret_cast(aDict); - loginArray = CFArrayCreate(kCFAllocatorDefault, &value, 1, &kCFTypeArrayCallBacks); - CFRelease(aDict); - } - - if (loginArray) - { - CFDictionarySetValue(mPropertyList, kLoginKeychainKey, loginArray); - CFRelease(loginArray); - } - else - CFDictionaryRemoveValue(mPropertyList, kLoginKeychainKey); - } - - if (mDefaultDLDbIdentifierSet) - { - // Make a temporary CFArray with the default keychain - CFArrayRef defaultArray = NULL; - if (!mDefaultDLDbIdentifier) - { - defaultArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks); - } - else if (!(mDefaultDLDbIdentifier == LoginDLDbIdentifier())) - { - CFDictionaryRef aDict = dlDbIdentifierToCFDictionaryRef(mDefaultDLDbIdentifier); - const void *value = reinterpret_cast(aDict); - defaultArray = CFArrayCreate(kCFAllocatorDefault, &value, 1, &kCFTypeArrayCallBacks); - CFRelease(aDict); - } - - if (defaultArray) - { - CFDictionarySetValue(mPropertyList, kDefaultKeychainKey, defaultArray); - CFRelease(defaultArray); - } - else - CFDictionaryRemoveValue(mPropertyList, kDefaultKeychainKey); - } - - writePropertyList(); - changed(false); -} - - -//---------------------------------------------------------------------- -// Conversions -//---------------------------------------------------------------------- - -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) -{ - // We must get individual values from the dictionary and store in basic types - if (CFGetTypeID(theDict) != CFDictionaryGetTypeID()) - throw std::logic_error("wrong type in property list"); - - // GUID - CCFValue vGuid(::CFDictionaryGetValue(theDict,kKeyGUID)); - string guidStr=vGuid; - const Guid guid(guidStr.c_str()); - - //CSSM_VERSION - CSSM_VERSION theVersion={0,}; - CCFValue vMajor(::CFDictionaryGetValue(theDict,kKeyMajorVersion)); - theVersion.Major = vMajor; - CCFValue vMinor(::CFDictionaryGetValue(theDict,kKeyMinorVersion)); - theVersion.Minor = vMinor; - - //subserviceId - CCFValue vSsid(::CFDictionaryGetValue(theDict,kKeySubserviceId)); - uint32 subserviceId=sint32(vSsid); - - //CSSM_SERVICE_TYPE - CSSM_SERVICE_TYPE subserviceType=CSSM_SERVICE_DL; - CCFValue vSsType(::CFDictionaryGetValue(theDict,kKeySubserviceType)); - subserviceType=vSsType; - - // Get DbName from dictionary - CCFValue vDbName(::CFDictionaryGetValue(theDict,kKeyDbName)); - string dbName=vDbName; - - // jch Get DbLocation from dictionary - 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; - } - - // Get our effective uid - uid_t uid = geteuid(); - // If we are setuid root use the real uid instead - if (!uid) uid = getuid(); - - // get the password entries - 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()) { - // We are not in a sandbox, no work to do here - 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 - // This is useful for debugging. - 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); - } - status = sandbox_release_fs_extension(xpc_string_get_string_ptr(extension)); - if (status) { - syslog(LOG_ERR, "Keychain sandbox release 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, inPath.length() - 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 aDict(CFDictionaryCreateMutable(kCFAllocatorDefault,0, - &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks)); - if (!aDict) - throw ::std::bad_alloc(); - - // Put SUBSERVICE_UID in dictionary - char buffer[Guid::stringRepLength+1]; - const CssmSubserviceUid& ssuid=dldbIdentifier.ssuid(); - const Guid &theGuid = Guid::overlay(ssuid.Guid); - CFRef stringGuid(::CFStringCreateWithCString(kCFAllocatorDefault, - theGuid.toString(buffer),kCFStringEncodingMacRoman)); - if (stringGuid) - ::CFDictionarySetValue(aDict,kKeyGUID,stringGuid); - - if (ssuid.SubserviceId!=0) - { - CFRef subserviceId(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceId)); - if (subserviceId) - ::CFDictionarySetValue(aDict,kKeySubserviceId,subserviceId); - } - if (ssuid.SubserviceType!=0) - { - CFRef subserviceType(CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.SubserviceType)); - if (subserviceType) - ::CFDictionarySetValue(aDict,kKeySubserviceType,subserviceType); - } - if (ssuid.Version.Major!=0 && ssuid.Version.Minor!=0) - { - CFRef majorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Major)); - if (majorVersion) - ::CFDictionarySetValue(aDict,kKeyMajorVersion,majorVersion); - CFRef minorVersion(::CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&ssuid.Version.Minor)); - if (minorVersion) - ::CFDictionarySetValue(aDict,kKeyMinorVersion,minorVersion); - } - - // Put DbName in dictionary - const char *dbName=dldbIdentifier.dbName(); - if (dbName) - { - CFRef theDbName(::CFStringCreateWithCString(kCFAllocatorDefault,AbbreviatedPath(dbName).c_str(),kCFStringEncodingUTF8)); - ::CFDictionarySetValue(aDict,kKeyDbName,theDbName); - } - // Put DbLocation in dictionary - const CSSM_NET_ADDRESS *dbLocation=dldbIdentifier.dbLocation(); - if (dbLocation!=NULL && dbLocation->AddressType!=CSSM_ADDR_NONE) - { - CFRef 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 the prefs have not been refreshed in the last kDLDbListCFPrefRevertInterval - // seconds or we are asked to force a reload, then reload. - if (!loadPropertyList(force)) - return false; - - resetCachedValues(); - return true; -} - -void -DLDbListCFPref::add(const DLDbIdentifier &dldbIdentifier) -{ - // convert the location specified in dldbIdentifier to a standard form - // make a canonical form of the database name - 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) -{ - // Make sure mSearchList is set - searchList(); - for (vector::iterator ix = mSearchList.begin(); ix != mSearchList.end(); ++ix) - { - if (*ix==dldbIdentifier) // found in list - { - mSearchList.erase(ix); - changed(true); - break; - } - } -} - -void -DLDbListCFPref::rename(const DLDbIdentifier &oldId, const DLDbIdentifier &newId) -{ - // Make sure mSearchList is set - searchList(); - for (vector::iterator ix = mSearchList.begin(); - ix != mSearchList.end(); ++ix) - { - if (*ix==oldId) - { - // replace oldId with newId - *ix = newId; - changed(true); - } - else if (*ix==newId) - { - // remove newId except where we just inserted it - mSearchList.erase(ix); - changed(true); - } - } -} - -bool -DLDbListCFPref::member(const DLDbIdentifier &dldbIdentifier) -{ - if (dldbIdentifier.IsImplEmpty()) - { - return false; - } - - for (vector::const_iterator ix = searchList().begin(); ix != mSearchList.end(); ++ix) - { - if (ix->mImpl == NULL) - { - continue; - } - - // compare the dldbIdentifiers based on the full, real path to the keychain - if (ix->ssuid() == dldbIdentifier.ssuid()) - { - char localPath[PATH_MAX], - inPath[PATH_MAX]; - - // try to resolve these down to a canonical form - const char* localPathPtr = cached_realpath(ix->dbName(), localPath); - const char* inPathPtr = cached_realpath(dldbIdentifier.dbName(), inPath); - - // if either of the paths didn't resolve for some reason, use the originals - if (localPathPtr == NULL) - { - localPathPtr = ix->dbName(); - } - - if (inPathPtr == NULL) - { - inPathPtr = dldbIdentifier.dbName(); - } - - if (strcmp(localPathPtr, inPathPtr) == 0) - { - return true; - } - } - } - - return false; -} - -const vector & -DLDbListCFPref::searchList() -{ - if (!mSearchListSet) - { - CFArrayRef searchList = reinterpret_cast(CFDictionaryGetValue(mPropertyList, kDefaultDLDbListKey)); - if (searchList && CFGetTypeID(searchList) != CFArrayGetTypeID()) - searchList = NULL; - - if (searchList) - { - CFIndex top = CFArrayGetCount(searchList); - // Each entry is a CFDictionary; peel it off & add it to the array - for (CFIndex idx = 0; idx < top; ++idx) - { - CFDictionaryRef theDict = reinterpret_cast(CFArrayGetValueAtIndex(searchList, idx)); - try - { - mSearchList.push_back(cfDictionaryRefToDLDbIdentifier(theDict)); - } - catch (...) - { - // Drop stuff that doesn't parse on the floor. - } - } - - // If there were entries specified, but they were invalid revert to using the - // default keychain in the searchlist. - if (top > 0 && mSearchList.size() == 0) - searchList = NULL; - } - - // The default when no search list is specified is to only search the - // default keychain. - if (!searchList && static_cast(defaultDLDbIdentifier())) - mSearchList.push_back(mDefaultDLDbIdentifier); - - mSearchListSet = true; - } - - return mSearchList; -} - -void -DLDbListCFPref::searchList(const vector &searchList) -{ - vector 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(CFDictionaryGetValue(mPropertyList, kDefaultKeychainKey)); - if (defaultArray && CFGetTypeID(defaultArray) != CFArrayGetTypeID()) - defaultArray = NULL; - - if (defaultArray && CFArrayGetCount(defaultArray) > 0) - { - CFDictionaryRef defaultDict = reinterpret_cast(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() : ""); - } - catch (...) - { - // If defaultArray doesn't parse fall back on the default way of getting the default keychain - defaultArray = NULL; - } - } - - if (!defaultArray) - { - - // If the Panther style login keychain actually exists we use that otherwise no - // default is set. - 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 = -1; - - if (mDefaultDLDbIdentifier.mImpl != NULL) - { - st_result = stat(mDefaultDLDbIdentifier.dbName(), &st); - } - - if (st_result) - { - secdebug("secpref", "stat(%s) -> %d", mDefaultDLDbIdentifier.dbName(), st_result); - mDefaultDLDbIdentifier = DLDbIdentifier(); // initialize a NULL keychain - secdebug("secpref", "after DLDbIdentifier(), we think the default keychain is %s", static_cast(mDefaultDLDbIdentifier) ? mDefaultDLDbIdentifier.dbName() : ""); - } - } - - 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(CFDictionaryGetValue(mPropertyList, kLoginKeychainKey)); - if (loginArray && CFGetTypeID(loginArray) != CFArrayGetTypeID()) - loginArray = NULL; - - if (loginArray && CFArrayGetCount(loginArray) > 0) - { - CFDictionaryRef loginDict = reinterpret_cast(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(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : ""); - } - catch (...) - { - // If loginArray doesn't parse fall back on the default way of getting the login keychain. - loginArray = NULL; - } - } - - if (!loginArray) - { - mLoginDLDbIdentifier = LoginDLDbIdentifier(); - secdebug("secpref", "after LoginDLDbIdentifier(), we think the login keychain is %s", static_cast(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : ""); - } - - mLoginDLDbIdentifierSet = true; - } - - return mLoginDLDbIdentifier; -}