+++ /dev/null
-/*
- * 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 <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;
-
-// 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<void *>(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<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)
- {
- // 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<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);
-}
-
-
-//----------------------------------------------------------------------
-// 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<CFMutableDictionaryRef> 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<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);
- }
-
- // Put DbName in dictionary
- const char *dbName=dldbIdentifier.dbName();
- if (dbName)
- {
- CFRef<CFStringRef> 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<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 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<DLDbIdentifier>::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<DLDbIdentifier>::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<DLDbIdentifier>::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<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);
- // Each entry is a CFDictionary; peel it off & add it to the array
- for (CFIndex idx = 0; idx < top; ++idx)
- {
- CFDictionaryRef theDict = reinterpret_cast<CFDictionaryRef>(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<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 (...)
- {
- // 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<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 (...)
- {
- // 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<bool>(mLoginDLDbIdentifier) ? mLoginDLDbIdentifier.dbName() : "<NULL>");
- }
-
- mLoginDLDbIdentifierSet = true;
- }
-
- return mLoginDLDbIdentifier;
-}