]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_keychain/lib/StorageManager.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_keychain / lib / StorageManager.cpp
diff --git a/Security/libsecurity_keychain/lib/StorageManager.cpp b/Security/libsecurity_keychain/lib/StorageManager.cpp
deleted file mode 100644 (file)
index f5d16ae..0000000
+++ /dev/null
@@ -1,1975 +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@
- */
-
-
-/*
-       File:           StorageManager.cpp
-
-       Contains:       Working with multiple keychains
-
-*/
-
-#include "StorageManager.h"
-#include "KCEventNotifier.h"
-
-#include <Security/cssmapple.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <syslog.h>
-#include <pwd.h>
-#include <algorithm>
-#include <string>
-#include <stdio.h>
-//#include <Security/AuthorizationTags.h>
-//#include <Security/AuthSession.h>
-#include <security_utilities/debugging.h>
-#include <security_keychain/SecCFTypes.h>
-//#include <Security/SecurityAgentClient.h>
-#include <securityd_client/ssclient.h>
-#include <Security/AuthorizationTags.h>
-#include <Security/AuthorizationTagsPriv.h>
-#include <Security/SecTask.h>
-#include <security_keychain/SecCFTypes.h>
-#include "TrustSettingsSchema.h"
-#include <security_cdsa_client/wrapkey.h>
-
-//%%% add this to AuthorizationTagsPriv.h later
-#ifndef AGENT_HINT_LOGIN_KC_SUPPRESS_RESET_PANEL
-#define AGENT_HINT_LOGIN_KC_SUPPRESS_RESET_PANEL "loginKCCreate:suppressResetPanel"
-#endif
-
-#include "KCCursor.h"
-#include "Globals.h"
-
-
-using namespace CssmClient;
-using namespace KeychainCore;
-
-#define kLoginKeychainPathPrefix "~/Library/Keychains/"
-#define kUserLoginKeychainPath "~/Library/Keychains/login.keychain"
-#define kEmptyKeychainSizeInBytes   20460
-
-//-----------------------------------------------------------------------------------
-
-static SecPreferencesDomain defaultPreferenceDomain()
-{
-       SessionAttributeBits sessionAttrs;
-       if (gServerMode) {
-               secdebug("servermode", "StorageManager initialized in server mode");
-               sessionAttrs = sessionIsRoot;
-       } else {
-               MacOSError::check(SessionGetInfo(callerSecuritySession, NULL, &sessionAttrs));
-       }
-
-       // If this is the root session, use system preferences.
-       // (In SecurityServer debug mode, you'll get a (fake) root session
-       // that has graphics access. Ignore that to help testing.)
-       if ((sessionAttrs & sessionIsRoot)
-                       IFDEBUG( && !(sessionAttrs & sessionHasGraphicAccess))) {
-               secdebug("storagemgr", "using system preferences");
-               return kSecPreferencesDomainSystem;
-       }
-
-       // otherwise, use normal (user) preferences
-       return kSecPreferencesDomainUser;
-}
-
-static bool isAppSandboxed()
-{
-       bool result = false;
-       SecTaskRef task = SecTaskCreateFromSelf(NULL);
-       if(task != NULL) {
-               CFTypeRef appSandboxValue = SecTaskCopyValueForEntitlement(task,
-                       CFSTR("com.apple.security.app-sandbox"), NULL);
-               if(appSandboxValue != NULL) {
-                       result = true;
-                       CFRelease(appSandboxValue);
-               }
-               CFRelease(task);
-       }
-       return result;
-}
-
-static bool shouldAddToSearchList(const DLDbIdentifier &dLDbIdentifier)
-{
-       // Creation of a private keychain should not modify the search list: rdar://13529331
-       // However, we want to ensure the login and System keychains are in
-       // the search list if that is not the case when they are created.
-       // Note that App Sandbox apps may not modify the list in either case.
-
-       bool loginOrSystemKeychain = false;
-       const char *dbname = dLDbIdentifier.dbName();
-       if (dbname) {
-               if ((!strcmp(dbname, "/Library/Keychains/System.keychain")) ||
-                       (strstr(dbname, "/login.keychain")) ) {
-                       loginOrSystemKeychain = true;
-               }
-       }
-       return (loginOrSystemKeychain && !isAppSandboxed());
-}
-
-
-StorageManager::StorageManager() :
-       mSavedList(defaultPreferenceDomain()),
-       mCommonList(kSecPreferencesDomainCommon),
-       mDomain(kSecPreferencesDomainUser),
-       mMutex(Mutex::recursive)
-{
-}
-
-
-Mutex*
-StorageManager::getStorageManagerMutex()
-{
-       return &mKeychainMapMutex;
-}
-
-
-Keychain
-StorageManager::keychain(const DLDbIdentifier &dLDbIdentifier)
-{
-       StLock<Mutex>_(mKeychainMapMutex);
-
-       if (!dLDbIdentifier)
-               return Keychain();
-
-    KeychainMap::iterator it = mKeychains.find(dLDbIdentifier);
-    if (it != mKeychains.end())
-       {
-               if (it->second == NULL) // cleared by weak reference?
-               {
-                       mKeychains.erase(it);
-               }
-               else
-               {
-                       return it->second;
-               }
-       }
-
-       if (gServerMode) {
-               secdebug("servermode", "keychain reference in server mode");
-               return Keychain();
-       }
-
-       // The keychain is not in our cache.  Create it.
-       Module module(dLDbIdentifier.ssuid().guid());
-       DL dl;
-       if (dLDbIdentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP)
-               dl = SSCSPDL(module);
-       else
-               dl = DL(module);
-
-       dl->subserviceId(dLDbIdentifier.ssuid().subserviceId());
-       dl->version(dLDbIdentifier.ssuid().version());
-       Db db(dl, dLDbIdentifier.dbName());
-
-       Keychain keychain(db);
-       // Add the keychain to the cache.
-       mKeychains.insert(KeychainMap::value_type(dLDbIdentifier, &*keychain));
-       keychain->inCache(true);
-
-       return keychain;
-}
-
-void
-StorageManager::removeKeychain(const DLDbIdentifier &dLDbIdentifier,
-       KeychainImpl *keychainImpl)
-{
-       // Lock the recursive mutex
-
-       StLock<Mutex>_(mKeychainMapMutex);
-
-       KeychainMap::iterator it = mKeychains.find(dLDbIdentifier);
-       if (it != mKeychains.end() && (KeychainImpl*) it->second == keychainImpl)
-               mKeychains.erase(it);
-
-       keychainImpl->inCache(false);
-}
-
-void
-StorageManager::didRemoveKeychain(const DLDbIdentifier &dLDbIdentifier)
-{
-       // Lock the recursive mutex
-
-       StLock<Mutex>_(mKeychainMapMutex);
-
-       KeychainMap::iterator it = mKeychains.find(dLDbIdentifier);
-       if (it != mKeychains.end())
-       {
-               if (it->second != NULL) // did we get zapped by weak reference destruction
-               {
-                       KeychainImpl *keychainImpl = it->second;
-                       keychainImpl->inCache(false);
-               }
-
-               mKeychains.erase(it);
-       }
-}
-
-// Create keychain if it doesn't exist, and optionally add it to the search list.
-Keychain
-StorageManager::makeKeychain(const DLDbIdentifier &dLDbIdentifier, bool add)
-{
-       StLock<Mutex>_(mKeychainMapMutex);
-
-       Keychain theKeychain = keychain(dLDbIdentifier);
-       bool post = false;
-       bool updateList = (add && shouldAddToSearchList(dLDbIdentifier));
-
-       if (updateList)
-       {
-               mSavedList.revert(false);
-               DLDbList searchList = mSavedList.searchList();
-               if (find(searchList.begin(), searchList.end(), dLDbIdentifier) != searchList.end())
-                       return theKeychain;  // theKeychain is already in the searchList.
-
-               mCommonList.revert(false);
-               searchList = mCommonList.searchList();
-               if (find(searchList.begin(), searchList.end(), dLDbIdentifier) != searchList.end())
-                       return theKeychain;  // theKeychain is already in the commonList don't add it to the searchList.
-
-               // If theKeychain doesn't exist don't bother adding it to the search list yet.
-               if (!theKeychain->exists())
-                       return theKeychain;
-
-               // theKeychain exists and is not in our search list, so add it to the
-               // search list.
-               mSavedList.revert(true);
-               mSavedList.add(dLDbIdentifier);
-               mSavedList.save();
-               post = true;
-       }
-
-       if (post)
-       {
-               // Make sure we are not holding mStorageManagerLock anymore when we
-               // post this event.
-               KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-       }
-
-       return theKeychain;
-}
-
-// Be notified a Keychain just got created.
-void
-StorageManager::created(const Keychain &keychain)
-{
-       StLock<Mutex>_(mKeychainMapMutex);
-
-    DLDbIdentifier dLDbIdentifier = keychain->dlDbIdentifier();
-       bool defaultChanged = false;
-       bool updateList = shouldAddToSearchList(dLDbIdentifier);
-
-       if (updateList)
-       {
-               mSavedList.revert(true);
-               // If we don't have a default Keychain yet.  Make the newly created
-               // keychain the default.
-               if (!mSavedList.defaultDLDbIdentifier())
-               {
-                       mSavedList.defaultDLDbIdentifier(dLDbIdentifier);
-                       defaultChanged = true;
-               }
-
-               // Add the keychain to the search list prefs.
-               mSavedList.add(dLDbIdentifier);
-               mSavedList.save();
-
-               // Make sure we are not holding mLock when we post these events.
-               KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-       }
-
-       if (defaultChanged)
-       {
-               KCEventNotifier::PostKeychainEvent(kSecDefaultChangedEvent, dLDbIdentifier);
-       }
-}
-
-KCCursor
-StorageManager::createCursor(SecItemClass itemClass,
-       const SecKeychainAttributeList *attrList)
-{
-       StLock<Mutex>_(mMutex);
-
-       KeychainList searchList;
-       getSearchList(searchList);
-       return KCCursor(searchList, itemClass, attrList);
-}
-
-KCCursor
-StorageManager::createCursor(const SecKeychainAttributeList *attrList)
-{
-       StLock<Mutex>_(mMutex);
-
-       KeychainList searchList;
-       getSearchList(searchList);
-       return KCCursor(searchList, attrList);
-}
-
-void
-StorageManager::lockAll()
-{
-       StLock<Mutex>_(mMutex);
-
-    SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
-    ss.lockAll (false);
-}
-
-Keychain
-StorageManager::defaultKeychain()
-{
-       StLock<Mutex>_(mMutex);
-
-       Keychain theKeychain;
-    CFTypeRef ref;
-
-       {
-               mSavedList.revert(false);
-               DLDbIdentifier defaultDLDbIdentifier(mSavedList.defaultDLDbIdentifier());
-               if (defaultDLDbIdentifier)
-               {
-                       theKeychain = keychain(defaultDLDbIdentifier);
-            ref = theKeychain->handle(false);
-               }
-       }
-
-       if (theKeychain /* && theKeychain->exists() */)
-               return theKeychain;
-
-       MacOSError::throwMe(errSecNoDefaultKeychain);
-}
-
-void
-StorageManager::defaultKeychain(const Keychain &keychain)
-{
-       StLock<Mutex>_(mMutex);
-
-       // Only set a keychain as the default if we own it and can read/write it,
-       // and our uid allows modifying the directory for that preference domain.
-       if (!keychainOwnerPermissionsValidForDomain(keychain->name(), mDomain))
-               MacOSError::throwMe(errSecWrPerm);
-
-       DLDbIdentifier oldDefaultId;
-       DLDbIdentifier newDefaultId(keychain->dlDbIdentifier());
-       {
-               oldDefaultId = mSavedList.defaultDLDbIdentifier();
-               mSavedList.revert(true);
-               mSavedList.defaultDLDbIdentifier(newDefaultId);
-               mSavedList.save();
-       }
-
-       if (!(oldDefaultId == newDefaultId))
-       {
-               // Make sure we are not holding mLock when we post this event.
-               KCEventNotifier::PostKeychainEvent(kSecDefaultChangedEvent, newDefaultId);
-       }
-}
-
-Keychain
-StorageManager::defaultKeychain(SecPreferencesDomain domain)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       if (domain == mDomain)
-               return defaultKeychain();
-       else
-       {
-               DLDbIdentifier defaultDLDbIdentifier(DLDbListCFPref(domain).defaultDLDbIdentifier());
-               if (defaultDLDbIdentifier)
-                       return keychain(defaultDLDbIdentifier);
-
-               MacOSError::throwMe(errSecNoDefaultKeychain);
-       }
-}
-
-void
-StorageManager::defaultKeychain(SecPreferencesDomain domain, const Keychain &keychain)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       if (domain == mDomain)
-               defaultKeychain(keychain);
-       else
-               DLDbListCFPref(domain).defaultDLDbIdentifier(keychain->dlDbIdentifier());
-}
-
-Keychain
-StorageManager::loginKeychain()
-{
-       StLock<Mutex>_(mMutex);
-
-       Keychain theKeychain;
-       {
-               mSavedList.revert(false);
-               DLDbIdentifier loginDLDbIdentifier(mSavedList.loginDLDbIdentifier());
-               if (loginDLDbIdentifier)
-               {
-                       theKeychain = keychain(loginDLDbIdentifier);
-               }
-       }
-
-       if (theKeychain && theKeychain->exists())
-               return theKeychain;
-
-       MacOSError::throwMe(errSecNoSuchKeychain);
-}
-
-void
-StorageManager::loginKeychain(Keychain keychain)
-{
-       StLock<Mutex>_(mMutex);
-
-       mSavedList.revert(true);
-       mSavedList.loginDLDbIdentifier(keychain->dlDbIdentifier());
-       mSavedList.save();
-}
-
-size_t
-StorageManager::size()
-{
-       StLock<Mutex>_(mMutex);
-
-    mSavedList.revert(false);
-       mCommonList.revert(false);
-       return mSavedList.searchList().size() + mCommonList.searchList().size();
-}
-
-Keychain
-StorageManager::at(unsigned int ix)
-{
-       StLock<Mutex>_(mMutex);
-
-       mSavedList.revert(false);
-       DLDbList dLDbList = mSavedList.searchList();
-       if (ix < dLDbList.size())
-       {
-               return keychain(dLDbList[ix]);
-       }
-       else
-       {
-               ix -= dLDbList.size();
-               mCommonList.revert(false);
-               DLDbList commonList = mCommonList.searchList();
-               if (ix >= commonList.size())
-                       MacOSError::throwMe(errSecInvalidKeychain);
-
-               return keychain(commonList[ix]);
-       }
-}
-
-Keychain
-StorageManager::operator[](unsigned int ix)
-{
-       StLock<Mutex>_(mMutex);
-
-    return at(ix);
-}
-
-void StorageManager::rename(Keychain keychain, const char* newName)
-{
-
-       StLock<Mutex>_(mKeychainMapMutex);
-
-    bool changedDefault = false;
-       DLDbIdentifier newDLDbIdentifier;
-       {
-               mSavedList.revert(true);
-               DLDbIdentifier defaultId = mSavedList.defaultDLDbIdentifier();
-
-        // Find the keychain object for the given ref
-        DLDbIdentifier dLDbIdentifier = keychain->dlDbIdentifier();
-
-               // Actually rename the database on disk.
-        keychain->database()->rename(newName);
-
-        if (dLDbIdentifier == defaultId)
-            changedDefault=true;
-
-               newDLDbIdentifier = keychain->dlDbIdentifier();
-        // Rename the keychain in the search list.
-        mSavedList.rename(dLDbIdentifier, newDLDbIdentifier);
-
-               // If this was the default keychain change it accordingly
-               if (changedDefault)
-                       mSavedList.defaultDLDbIdentifier(newDLDbIdentifier);
-
-               mSavedList.save();
-
-               // we aren't worried about a weak reference here, because we have to
-               // hold a lock on an item in order to do the rename
-
-               // Now update the Keychain cache
-               if (keychain->inCache())
-               {
-                       KeychainMap::iterator it = mKeychains.find(dLDbIdentifier);
-                       if (it != mKeychains.end() && (KeychainImpl*) it->second == keychain.get())
-                       {
-                               // Remove the keychain from the cache under its old
-                               // dLDbIdentifier
-                               mKeychains.erase(it);
-                       }
-               }
-
-               // If we renamed this keychain on top of an existing one we should
-               // drop the old one from the cache.
-               KeychainMap::iterator it = mKeychains.find(newDLDbIdentifier);
-               if (it != mKeychains.end())
-               {
-                       Keychain oldKeychain(it->second);
-                       oldKeychain->inCache(false);
-                       // @@@ Ideally we should invalidate or fault this keychain object.
-               }
-
-               if (keychain->inCache())
-               {
-                       // If the keychain wasn't in the cache to being with let's not put
-                       // it there now.  There was probably a good reason it wasn't in it.
-                       // If the keychain was in the cache, update it to use
-                       // newDLDbIdentifier.
-                       mKeychains.insert(KeychainMap::value_type(newDLDbIdentifier,
-                               keychain));
-               }
-       }
-
-       // Make sure we are not holding mLock when we post these events.
-       KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-
-       if (changedDefault)
-               KCEventNotifier::PostKeychainEvent(kSecDefaultChangedEvent,
-                       newDLDbIdentifier);
-}
-
-void StorageManager::renameUnique(Keychain keychain, CFStringRef newName)
-{
-       StLock<Mutex>_(mMutex);
-
-    bool doneCreating = false;
-    int index = 1;
-    do
-    {
-        char newNameCString[MAXPATHLEN];
-        if ( CFStringGetCString(newName, newNameCString, MAXPATHLEN, kCFStringEncodingUTF8) )  // make sure it fits in MAXPATHLEN, etc.
-        {
-            // Construct the new name...
-            //
-            CFMutableStringRef newNameCFStr = NULL;
-            newNameCFStr = CFStringCreateMutable(NULL, MAXPATHLEN);
-            if ( newNameCFStr )
-            {
-                CFStringAppendFormat(newNameCFStr, NULL, CFSTR("%s%d"), newNameCString, index);
-                CFStringAppend(newNameCFStr, CFSTR(kKeychainSuffix));  // add .keychain
-                char toUseBuff2[MAXPATHLEN];
-                if ( CFStringGetCString(newNameCFStr, toUseBuff2, MAXPATHLEN, kCFStringEncodingUTF8) ) // make sure it fits in MAXPATHLEN, etc.
-                {
-                    struct stat filebuf;
-                    if ( lstat(toUseBuff2, &filebuf) )
-                    {
-                        rename(keychain, toUseBuff2);
-                                               KeychainList kcList;
-                                               kcList.push_back(keychain);
-                                               remove(kcList, false);
-                        doneCreating = true;
-                    }
-                    else
-                        index++;
-                }
-                else
-                    doneCreating = true;       // failure to get c string.
-                CFRelease(newNameCFStr);
-            }
-            else
-                doneCreating = false; // failure to create mutable string.
-        }
-        else
-            doneCreating = false; // failure to get the string (i.e. > MAXPATHLEN?)
-    }
-    while (!doneCreating && index != INT_MAX);
-}
-
-#define KEYCHAIN_SYNC_KEY CFSTR("KeychainSyncList")
-#define KEYCHAIN_SYNC_DOMAIN CFSTR("com.apple.keychainsync")
-
-static CFStringRef MakeExpandedPath (const char* path)
-{
-       std::string name = DLDbListCFPref::ExpandTildesInPath (std::string (path));
-       CFStringRef expanded = CFStringCreateWithCString (NULL, name.c_str (), 0);
-       return expanded;
-}
-
-void StorageManager::removeKeychainFromSyncList (const DLDbIdentifier &id)
-{
-       StLock<Mutex>_(mMutex);
-
-       // make a CFString of our identifier
-       const char* idname = id.dbName ();
-       if (idname == NULL)
-       {
-               return;
-       }
-
-       CFRef<CFStringRef> idString = MakeExpandedPath (idname);
-
-       // check and see if this keychain is in the keychain syncing list
-       CFArrayRef value =
-               (CFArrayRef) CFPreferencesCopyValue (KEYCHAIN_SYNC_KEY,
-                                                                                        KEYCHAIN_SYNC_DOMAIN,
-                                                                                        kCFPreferencesCurrentUser,
-                                                                                        kCFPreferencesAnyHost);
-       if (value == NULL)
-       {
-               return;
-       }
-
-       // make a mutable copy of the dictionary
-       CFRef<CFMutableArrayRef> mtValue = CFArrayCreateMutableCopy (NULL, 0, value);
-       CFRelease (value);
-
-       // walk the array, looking for the value
-       CFIndex i;
-       CFIndex limit = CFArrayGetCount (mtValue.get());
-       bool found = false;
-
-       for (i = 0; i < limit; ++i)
-       {
-               CFDictionaryRef idx = (CFDictionaryRef) CFArrayGetValueAtIndex (mtValue.get(), i);
-               CFStringRef v = (CFStringRef) CFDictionaryGetValue (idx, CFSTR("DbName"));
-               if (v == NULL)
-               {
-                       return; // something is really wrong if this is taken
-               }
-
-        char* stringBuffer = NULL;
-        const char* pathString = CFStringGetCStringPtr(v, 0);
-        if (pathString == 0)
-        {
-            CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(v), kCFStringEncodingUTF8) + 1;
-            stringBuffer = (char*) malloc(maxLen);
-            CFStringGetCString(v, stringBuffer, maxLen, kCFStringEncodingUTF8);
-            pathString = stringBuffer;
-        }
-        
-               CFStringRef vExpanded = MakeExpandedPath(pathString);
-               CFComparisonResult result = CFStringCompare (vExpanded, idString.get(), 0);
-        if (stringBuffer != NULL)
-        {
-            free(stringBuffer);
-        }
-        
-               CFRelease (vExpanded);
-
-               if (result == 0)
-               {
-                       CFArrayRemoveValueAtIndex (mtValue.get(), i);
-                       found = true;
-                       break;
-               }
-       }
-
-       if (found)
-       {
-#ifndef NDEBUG
-               CFShow (mtValue.get());
-#endif
-
-               CFPreferencesSetValue (KEYCHAIN_SYNC_KEY,
-                                                          mtValue,
-                                                          KEYCHAIN_SYNC_DOMAIN,
-                                                          kCFPreferencesCurrentUser,
-                                                          kCFPreferencesAnyHost);
-               CFPreferencesSynchronize (KEYCHAIN_SYNC_DOMAIN, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
-       }
-}
-
-void StorageManager::remove(const KeychainList &kcsToRemove, bool deleteDb)
-{
-       StLock<Mutex>_(mMutex);
-
-       bool unsetDefault = false;
-       bool updateList = (!isAppSandboxed());
-
-       if (updateList)
-       {
-               mSavedList.revert(true);
-               DLDbIdentifier defaultId = mSavedList.defaultDLDbIdentifier();
-               for (KeychainList::const_iterator ix = kcsToRemove.begin();
-                       ix != kcsToRemove.end(); ++ix)
-               {
-                       // Find the keychain object for the given ref
-                       Keychain theKeychain = *ix;
-                       DLDbIdentifier dLDbIdentifier = theKeychain->dlDbIdentifier();
-
-                       // Remove it from the saved list
-                       mSavedList.remove(dLDbIdentifier);
-                       if (dLDbIdentifier == defaultId)
-                               unsetDefault=true;
-
-                       if (deleteDb)
-                       {
-                               removeKeychainFromSyncList (dLDbIdentifier);
-
-                               // Now remove it from the cache
-                               removeKeychain(dLDbIdentifier, theKeychain.get());
-                       }
-               }
-
-               if (unsetDefault)
-                       mSavedList.defaultDLDbIdentifier(DLDbIdentifier());
-
-               mSavedList.save();
-       }
-
-       if (deleteDb)
-       {
-               // Delete the actual databases without holding any locks.
-               for (KeychainList::const_iterator ix = kcsToRemove.begin();
-                       ix != kcsToRemove.end(); ++ix)
-               {
-                       (*ix)->database()->deleteDb();
-               }
-       }
-
-       if (updateList) {
-               // Make sure we are not holding mLock when we post these events.
-               KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-       }
-
-       if (unsetDefault)
-               KCEventNotifier::PostKeychainEvent(kSecDefaultChangedEvent);
-}
-
-void
-StorageManager::getSearchList(KeychainList &keychainList)
-{
-       // hold the global lock since we make keychain objects in this function
-
-       // to do:  each of the items in this list must be retained, otherwise mayhem will occur
-       StLock<Mutex>_(mMutex);
-
-       if (gServerMode) {
-               keychainList.clear();
-               return;
-       }
-
-    mSavedList.revert(false);
-       mCommonList.revert(false);
-
-       // Merge mSavedList, mDynamicList and mCommonList
-       DLDbList dLDbList = mSavedList.searchList();
-       DLDbList dynamicList = mDynamicList.searchList();
-       DLDbList commonList = mCommonList.searchList();
-       KeychainList result;
-       result.reserve(dLDbList.size() + dynamicList.size() + commonList.size());
-
-       {
-               for (DLDbList::const_iterator it = dynamicList.begin();
-                       it != dynamicList.end(); ++it)
-               {
-                       Keychain k = keychain(*it);
-                       result.push_back(k);
-               }
-
-               for (DLDbList::const_iterator it = dLDbList.begin();
-                       it != dLDbList.end(); ++it)
-               {
-                       Keychain k = keychain(*it);
-                       result.push_back(k);
-               }
-
-               for (DLDbList::const_iterator it = commonList.begin();
-                       it != commonList.end(); ++it)
-               {
-                       Keychain k = keychain(*it);
-                       result.push_back(k);
-               }
-       }
-
-       keychainList.swap(result);
-}
-
-void
-StorageManager::setSearchList(const KeychainList &keychainList)
-{
-       StLock<Mutex>_(mMutex);
-
-       DLDbList commonList = mCommonList.searchList();
-
-       // Strip out the common list part from the end of the search list.
-       KeychainList::const_iterator it_end = keychainList.end();
-       DLDbList::const_reverse_iterator end_common = commonList.rend();
-       for (DLDbList::const_reverse_iterator it_common = commonList.rbegin(); it_common != end_common; ++it_common)
-       {
-               // Eliminate common entries from the end of the passed in keychainList.
-               if (it_end == keychainList.begin())
-                       break;
-
-               --it_end;
-               if (!((*it_end)->dlDbIdentifier() == *it_common))
-               {
-                       ++it_end;
-                       break;
-               }
-       }
-
-       /* it_end now points one past the last element in keychainList which is not in commonList. */
-       DLDbList searchList, oldSearchList(mSavedList.searchList());
-       for (KeychainList::const_iterator it = keychainList.begin(); it != it_end; ++it)
-       {
-               searchList.push_back((*it)->dlDbIdentifier());
-       }
-
-       {
-               // Set the current searchlist to be what was passed in, the old list will be freed
-               // upon exit of this stackframe.
-               mSavedList.revert(true);
-               mSavedList.searchList(searchList);
-       mSavedList.save();
-       }
-
-       if (!(oldSearchList == searchList))
-       {
-               // Make sure we are not holding mLock when we post this event.
-               KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-       }
-}
-
-void
-StorageManager::getSearchList(SecPreferencesDomain domain, KeychainList &keychainList)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (gServerMode) {
-               keychainList.clear();
-               return;
-       }
-
-       if (domain == kSecPreferencesDomainDynamic)
-       {
-               convertList(keychainList, mDynamicList.searchList());
-       }
-       else if (domain == mDomain)
-       {
-               mSavedList.revert(false);
-               convertList(keychainList, mSavedList.searchList());
-       }
-       else
-       {
-               convertList(keychainList, DLDbListCFPref(domain).searchList());
-       }
-}
-
-void StorageManager::forceUserSearchListReread()
-{
-       mSavedList.forceUserSearchListReread();
-}
-
-void
-StorageManager::setSearchList(SecPreferencesDomain domain, const KeychainList &keychainList)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       DLDbList searchList;
-       convertList(searchList, keychainList);
-
-       if (domain == mDomain)
-       {
-               DLDbList oldSearchList(mSavedList.searchList());
-               {
-                       // Set the current searchlist to be what was passed in, the old list will be freed
-                       // upon exit of this stackframe.
-                       mSavedList.revert(true);
-                       mSavedList.searchList(searchList);
-                       mSavedList.save();
-               }
-
-               if (!(oldSearchList == searchList))
-               {
-                       KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-               }
-       }
-       else
-       {
-               DLDbListCFPref(domain).searchList(searchList);
-       }
-}
-
-void
-StorageManager::domain(SecPreferencesDomain domain)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       if (domain == mDomain)
-               return; // no change
-
-#if !defined(NDEBUG)
-       switch (domain)
-       {
-       case kSecPreferencesDomainSystem:
-               secdebug("storagemgr", "switching to system domain"); break;
-       case kSecPreferencesDomainUser:
-               secdebug("storagemgr", "switching to user domain (uid %d)", getuid()); break;
-       default:
-               secdebug("storagemgr", "switching to weird prefs domain %d", domain); break;
-       }
-#endif
-
-       mDomain = domain;
-       mSavedList.set(domain);
-}
-
-void
-StorageManager::optionalSearchList(CFTypeRef keychainOrArray, KeychainList &keychainList)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (!keychainOrArray)
-               getSearchList(keychainList);
-       else
-       {
-               CFTypeID typeID = CFGetTypeID(keychainOrArray);
-               if (typeID == CFArrayGetTypeID())
-                       convertToKeychainList(CFArrayRef(keychainOrArray), keychainList);
-               else if (typeID == gTypes().KeychainImpl.typeID)
-                       keychainList.push_back(KeychainImpl::required(SecKeychainRef(keychainOrArray)));
-               else
-                       MacOSError::throwMe(errSecParam);
-       }
-}
-
-// static methods.
-void
-StorageManager::convertToKeychainList(CFArrayRef keychainArray, KeychainList &keychainList)
-{
-       CFIndex count = CFArrayGetCount(keychainArray);
-       if (!(count > 0))
-               return;
-
-       KeychainList keychains(count);
-       for (CFIndex ix = 0; ix < count; ++ix)
-       {
-               keychains[ix] = KeychainImpl::required(SecKeychainRef(CFArrayGetValueAtIndex(keychainArray, ix)));
-       }
-
-       keychainList.swap(keychains);
-}
-
-CFArrayRef
-StorageManager::convertFromKeychainList(const KeychainList &keychainList)
-{
-       CFRef<CFMutableArrayRef> keychainArray(CFArrayCreateMutable(NULL, keychainList.size(), &kCFTypeArrayCallBacks));
-
-       for (KeychainList::const_iterator ix = keychainList.begin(); ix != keychainList.end(); ++ix)
-       {
-               SecKeychainRef keychainRef = (*ix)->handle();
-               CFArrayAppendValue(keychainArray, keychainRef);
-               CFRelease(keychainRef);
-       }
-
-       // Counter the CFRelease that CFRef<> is about to do when keychainArray goes out of scope.
-       CFRetain(keychainArray);
-       return keychainArray;
-}
-
-void StorageManager::convertList(DLDbList &ids, const KeychainList &kcs)
-{
-       DLDbList result;
-       result.reserve(kcs.size());
-       for (KeychainList::const_iterator ix = kcs.begin(); ix != kcs.end(); ++ix)
-       {
-               result.push_back((*ix)->dlDbIdentifier());
-       }
-       ids.swap(result);
-}
-
-void StorageManager::convertList(KeychainList &kcs, const DLDbList &ids)
-{
-       StLock<Mutex>_(mMutex);
-
-       KeychainList result;
-    result.reserve(ids.size());
-       {
-               for (DLDbList::const_iterator ix = ids.begin(); ix != ids.end(); ++ix)
-                       result.push_back(keychain(*ix));
-       }
-    kcs.swap(result);
-}
-
-#pragma mark ____ Login Functions ____
-
-void StorageManager::login(AuthorizationRef authRef, UInt32 nameLength, const char* name)
-{
-       StLock<Mutex>_(mMutex);
-
-    AuthorizationItemSet* info = NULL;
-    OSStatus result = AuthorizationCopyInfo(authRef, NULL, &info);     // get the results of the copy rights call.
-    Boolean created = false;
-    if ( result == errSecSuccess && info->count )
-    {
-        // Grab the password from the auth context (info) and create the keychain...
-        //
-        AuthorizationItem* currItem = info->items;
-        for (UInt32 index = 1; index <= info->count; index++) //@@@plugin bug won't return a specific context.
-        {
-            if (strcmp(currItem->name, kAuthorizationEnvironmentPassword) == 0)
-            {
-                // creates the login keychain with the specified password
-                try
-                {
-                    login(nameLength, name, (UInt32)currItem->valueLength, currItem->value);
-                    created = true;
-                }
-                catch(...)
-                {
-                }
-                break;
-            }
-            currItem++;
-        }
-    }
-    if ( info )
-        AuthorizationFreeItemSet(info);
-
-    if ( !created )
-        MacOSError::throwMe(errAuthorizationInternal);
-}
-
-void StorageManager::login(ConstStringPtr name, ConstStringPtr password)
-{
-       StLock<Mutex>_(mMutex);
-
-    if ( name == NULL || password == NULL )
-        MacOSError::throwMe(errSecParam);
-
-       login(name[0], name + 1, password[0], password + 1);
-}
-
-void StorageManager::login(UInt32 nameLength, const void *name,
-       UInt32 passwordLength, const void *password)
-{
-       if (passwordLength != 0 && password == NULL)
-       {
-               secdebug("KCLogin", "StorageManager::login: invalid argument (NULL password)");
-               MacOSError::throwMe(errSecParam);
-       }
-
-       DLDbIdentifier loginDLDbIdentifier;
-       {
-               mSavedList.revert(true);
-               loginDLDbIdentifier = mSavedList.loginDLDbIdentifier();
-       }
-
-       secdebug("KCLogin", "StorageManager::login: loginDLDbIdentifier is %s", (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-       if (!loginDLDbIdentifier)
-               MacOSError::throwMe(errSecNoSuchKeychain);
-
-
-    //***************************************************************
-    // gather keychain information
-    //***************************************************************
-
-    // user name
-    int uid = geteuid();
-    struct passwd *pw = getpwuid(uid);
-    if (pw == NULL) {
-        secdebug("KCLogin", "StorageManager::login: invalid argument (NULL uid)");
-        MacOSError::throwMe(errSecParam);
-    }
-    char *userName = pw->pw_name;
-
-    // make keychain path strings
-    std::string keychainPath = DLDbListCFPref::ExpandTildesInPath(kLoginKeychainPathPrefix);
-    std::string shortnameKeychain = keychainPath + userName;
-    std::string shortnameDotKeychain = shortnameKeychain + ".keychain";
-    std::string loginDotKeychain = keychainPath + "login.keychain";
-    std::string loginRenamed1Keychain = keychainPath + "login_renamed1.keychain";
-
-    // check for existence of keychain files
-    bool shortnameKeychainExists = false;
-    bool shortnameDotKeychainExists = false;
-    bool loginKeychainExists = false;
-    bool loginRenamed1KeychainExists = false;
-    {
-        struct stat st;
-        int stat_result;
-        stat_result = ::stat(shortnameKeychain.c_str(), &st);
-        shortnameKeychainExists = (stat_result == 0);
-        stat_result = ::stat(shortnameDotKeychain.c_str(), &st);
-        shortnameDotKeychainExists = (stat_result == 0);
-        stat_result = ::stat(loginDotKeychain.c_str(), &st);
-        loginKeychainExists = (stat_result == 0);
-        stat_result = ::stat(loginRenamed1Keychain.c_str(), &st);
-        loginRenamed1KeychainExists = (stat_result == 0);
-    }
-
-    bool loginUnlocked = false;
-
-    // make the keychain identifiers
-    CSSM_VERSION version = {0, 0};
-    DLDbIdentifier shortnameDLDbIdentifier = DLDbListCFPref::makeDLDbIdentifier(gGuidAppleCSPDL, version, 0, CSSM_SERVICE_CSP | CSSM_SERVICE_DL, shortnameKeychain.c_str(), NULL);
-    DLDbIdentifier shortnameDotDLDbIdentifier = DLDbListCFPref::makeDLDbIdentifier(gGuidAppleCSPDL, version, 0, CSSM_SERVICE_CSP | CSSM_SERVICE_DL, shortnameDotKeychain.c_str(), NULL);
-    DLDbIdentifier loginRenamed1DLDbIdentifier = DLDbListCFPref::makeDLDbIdentifier(gGuidAppleCSPDL, version, 0, CSSM_SERVICE_CSP | CSSM_SERVICE_DL, loginRenamed1Keychain.c_str(), NULL);
-
-    //***************************************************************
-    // make file renaming changes first
-    //***************************************************************
-
-    // if "~/Library/Keychains/shortname" exists, we need to migrate it forward;
-    // either to login.keychain if there isn't already one, otherwise to shortname.keychain
-    if (shortnameKeychainExists) {
-        int rename_stat = 0;
-        if (loginKeychainExists) {
-            struct stat st;
-            int tmp_result = ::stat(loginDotKeychain.c_str(), &st);
-            if (tmp_result == 0) {
-                if (st.st_size <= kEmptyKeychainSizeInBytes) {
-                    tmp_result = ::unlink(loginDotKeychain.c_str());
-                    rename_stat = ::rename(shortnameKeychain.c_str(), loginDotKeychain.c_str());
-                    shortnameKeychainExists = (rename_stat != 0);
-                }
-            }
-        }
-        if (shortnameKeychainExists) {
-            if (loginKeychainExists && !shortnameDotKeychainExists) {
-                rename_stat = ::rename(shortnameKeychain.c_str(), shortnameDotKeychain.c_str());
-                shortnameDotKeychainExists = (rename_stat == 0);
-            } else if (!loginKeychainExists) {
-                rename_stat = ::rename(shortnameKeychain.c_str(), loginDotKeychain.c_str());
-                loginKeychainExists = (rename_stat == 0);
-            } else {
-                // we have all 3 keychains: login.keychain, shortname, and shortname.keychain.
-                // on Leopard we never want a shortname keychain, so we must move it aside.
-                char pathbuf[MAXPATHLEN];
-                std::string shortnameRenamedXXXKeychain = keychainPath;
-                shortnameRenamedXXXKeychain += userName;
-                shortnameRenamedXXXKeychain += "_renamed_XXX.keychain";
-                ::strlcpy(pathbuf, shortnameRenamedXXXKeychain.c_str(), sizeof(pathbuf));
-                ::mkstemps(pathbuf, 9); // 9 == strlen(".keychain")
-                rename_stat = ::rename(shortnameKeychain.c_str(), pathbuf);
-                shortnameKeychainExists = (rename_stat != 0);
-            }
-        }
-        if (rename_stat != 0) {
-            MacOSError::throwMe(errno);
-        }
-    }
-
-    //***************************************************************
-    // handle special case where user previously reset the keychain
-    //***************************************************************
-    // Since 9A581, we have changed the definition of kKeychainRenamedSuffix from "_renamed" to "_renamed_".
-    // Therefore, if "login_renamed1.keychain" exists and there is no plist, the user may have run into a
-    // prior upgrade issue and clicked Reset. If we can successfully unlock login_renamed1.keychain with the
-    // supplied password, then we will attempt to rename it to login.keychain if that file is empty, or with
-    // "shortname.keychain" if it is not.
-
-    if (loginRenamed1KeychainExists && (!loginKeychainExists ||
-        (mSavedList.searchList().size() == 1 && mSavedList.member(loginDLDbIdentifier)) )) {
-        try
-        {
-            Keychain loginRenamed1KC(keychain(loginRenamed1DLDbIdentifier));
-            secdebug("KCLogin", "Attempting to unlock %s with %d-character password",
-                (loginRenamed1KC) ? loginRenamed1KC->name() : "<NULL>", (unsigned int)passwordLength);
-            loginRenamed1KC->unlock(CssmData(const_cast<void *>(password), passwordLength));
-            // if we get here, we unlocked it
-            if (loginKeychainExists) {
-                struct stat st;
-                int tmp_result = ::stat(loginDotKeychain.c_str(), &st);
-                if (tmp_result == 0) {
-                    if (st.st_size <= kEmptyKeychainSizeInBytes) {
-                        tmp_result = ::unlink(loginDotKeychain.c_str());
-                        tmp_result = ::rename(loginRenamed1Keychain.c_str(), loginDotKeychain.c_str());
-                    } else if (!shortnameDotKeychainExists) {
-                        tmp_result = ::rename(loginRenamed1Keychain.c_str(), shortnameDotKeychain.c_str());
-                        shortnameDotKeychainExists = (tmp_result == 0);
-                    } else {
-                        throw 1;   // can't do anything with it except move it out of the way
-                    }
-                }
-            } else {
-                int tmp_result = ::rename(loginRenamed1Keychain.c_str(), loginDotKeychain.c_str());
-                loginKeychainExists = (tmp_result == 0);
-            }
-        }
-        catch(...)
-        {
-            // we failed to unlock the login_renamed1.keychain file with the login password.
-            // move it aside so we don't try to deal with it again.
-            char pathbuf[MAXPATHLEN];
-            std::string loginRenamedXXXKeychain = keychainPath;
-            loginRenamedXXXKeychain += "login_renamed_XXX.keychain";
-            ::strlcpy(pathbuf, loginRenamedXXXKeychain.c_str(), sizeof(pathbuf));
-            ::mkstemps(pathbuf, 9); // 9 == strlen(".keychain")
-            ::rename(loginRenamed1Keychain.c_str(), pathbuf);
-        }
-    }
-
-    // if login.keychain does not exist at this point, create it
-    if (!loginKeychainExists) {
-        Keychain theKeychain(keychain(loginDLDbIdentifier));
-        secdebug("KCLogin", "Creating login keychain %s", (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-        theKeychain->create(passwordLength, password);
-        secdebug("KCLogin", "Login keychain created successfully");
-        loginKeychainExists = true;
-        // Set the prefs for this new login keychain.
-        loginKeychain(theKeychain);
-        // Login Keychain does not lock on sleep nor lock after timeout by default.
-        theKeychain->setSettings(INT_MAX, false);
-        loginUnlocked = true;
-        mSavedList.revert(true);
-    }
-
-    //***************************************************************
-    // make plist changes after files have been renamed or created
-    //***************************************************************
-
-    // if the shortname keychain exists in the search list, either rename or remove the entry
-    if (mSavedList.member(shortnameDLDbIdentifier)) {
-        if (shortnameDotKeychainExists && !mSavedList.member(shortnameDotDLDbIdentifier)) {
-            // change shortname to shortname.keychain (login.keychain will be added later if not present)
-            secdebug("KCLogin", "Renaming %s to %s in keychain search list",
-                    (shortnameDLDbIdentifier) ? shortnameDLDbIdentifier.dbName() : "<NULL>",
-                    (shortnameDotDLDbIdentifier) ? shortnameDotDLDbIdentifier.dbName() : "<NULL>");
-            mSavedList.rename(shortnameDLDbIdentifier, shortnameDotDLDbIdentifier);
-        } else if (!mSavedList.member(loginDLDbIdentifier)) {
-            // change shortname to login.keychain
-            secdebug("KCLogin", "Renaming %s to %s in keychain search list",
-                    (shortnameDLDbIdentifier) ? shortnameDLDbIdentifier.dbName() : "<NULL>",
-                    (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-            mSavedList.rename(shortnameDLDbIdentifier, loginDLDbIdentifier);
-        } else {
-            // already have login.keychain in list, and renaming to shortname.keychain isn't an option,
-            // so just remove the entry
-            secdebug("KCLogin", "Removing %s from keychain search list", (shortnameDLDbIdentifier) ? shortnameDLDbIdentifier.dbName() : "<NULL>");
-            mSavedList.remove(shortnameDLDbIdentifier);
-        }
-
-        // note: save() will cause the plist to be unlinked if the only remaining entry is for login.keychain
-        mSavedList.save();
-        mSavedList.revert(true);
-    }
-
-    // make sure that login.keychain is in the search list
-    if (!mSavedList.member(loginDLDbIdentifier)) {
-       secdebug("KCLogin", "Adding %s to keychain search list", (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-        mSavedList.add(loginDLDbIdentifier);
-        mSavedList.save();
-        mSavedList.revert(true);
-    }
-
-    // if we have a shortname.keychain, always include it in the plist (after login.keychain)
-    if (shortnameDotKeychainExists && !mSavedList.member(shortnameDotDLDbIdentifier)) {
-        mSavedList.add(shortnameDotDLDbIdentifier);
-        mSavedList.save();
-        mSavedList.revert(true);
-    }
-
-    // make sure that the default keychain is in the search list; if not, reset the default to login.keychain
-       if (!mSavedList.member(mSavedList.defaultDLDbIdentifier())) {
-       secdebug("KCLogin", "Changing default keychain to %s", (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-        mSavedList.defaultDLDbIdentifier(loginDLDbIdentifier);
-        mSavedList.save();
-        mSavedList.revert(true);
-       }
-
-    //***************************************************************
-    // auto-unlock the login keychain(s)
-    //***************************************************************
-    // all our preflight fixups are finally done, so we can now attempt to unlock the login keychain
-
-    OSStatus loginResult = errSecSuccess;
-       if (!loginUnlocked) {
-        try
-        {
-            Keychain theKeychain(keychain(loginDLDbIdentifier));
-            secdebug("KCLogin", "Attempting to unlock login keychain \"%s\" with %d-character password",
-                (theKeychain) ? theKeychain->name() : "<NULL>", (unsigned int)passwordLength);
-            theKeychain->unlock(CssmData(const_cast<void *>(password), passwordLength));
-            loginUnlocked = true;
-        }
-        catch(const CssmError &e)
-        {
-            loginResult = e.osStatus(); // save this result
-        }
-    }
-
-    if (!loginUnlocked) {
-        try {
-            loginResult = errSecSuccess;
-            Keychain theKeychain(keychain(loginDLDbIdentifier));
-
-            // build a fake key
-            CssmKey key;
-            key.header().BlobType = CSSM_KEYBLOB_RAW;
-            key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
-            key.header().AlgorithmId = CSSM_ALGID_3DES_3KEY;
-            key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
-            key.header().KeyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYATTR_EXTRACTABLE;
-            key.header().KeyAttr = 0;
-            key.KeyData = CssmData(const_cast<void *>(password), passwordLength);
-            
-            // unwrap it into the CSP (but keep it raw)
-            UnwrapKey unwrap(theKeychain->csp(), CSSM_ALGID_NONE);
-            CssmKey masterKey;
-            CssmData descriptiveData;
-            unwrap(key,
-                   KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_EXTRACTABLE),
-                   masterKey, &descriptiveData, NULL);
-            
-            CssmClient::Db db = theKeychain->database();
-            
-            // create the keychain, using appropriate credentials
-            Allocator &alloc = db->allocator();
-            AutoCredentials cred(alloc);       // will leak, but we're quitting soon :-)
-            
-            // use this passphrase
-            cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
-                              new(alloc) ListElement(CSSM_SAMPLE_TYPE_SYMMETRIC_KEY),
-                              new(alloc) ListElement(CssmData::wrap(theKeychain->csp()->handle())),
-                              new(alloc) ListElement(CssmData::wrap(masterKey)),
-                              new(alloc) ListElement(CssmData()));
-            db->authenticate(CSSM_DB_ACCESS_READ, &cred);
-            db->unlock();
-            loginUnlocked = true;
-        } catch (const CssmError &e) {
-            loginResult = e.osStatus();
-        }
-    }
-
-    // if "shortname.keychain" exists and is in the search list, attempt to auto-unlock it with the same password
-    if (shortnameDotKeychainExists && mSavedList.member(shortnameDotDLDbIdentifier)) {
-        try
-        {
-            Keychain shortnameDotKC(keychain(shortnameDotDLDbIdentifier));
-            secdebug("KCLogin", "Attempting to unlock %s",
-                (shortnameDotKC) ? shortnameDotKC->name() : "<NULL>");
-            shortnameDotKC->unlock(CssmData(const_cast<void *>(password), passwordLength));
-        }
-        catch(const CssmError &e)
-        {
-            // ignore; failure to unlock this keychain is not considered an error
-        }
-    }
-
-    if (loginResult != errSecSuccess) {
-        MacOSError::throwMe(loginResult);
-    }
-}
-
-void StorageManager::stashLogin()
-{
-    OSStatus loginResult = errSecSuccess;
-    
-    DLDbIdentifier loginDLDbIdentifier;
-    {
-        mSavedList.revert(true);
-        loginDLDbIdentifier = mSavedList.loginDLDbIdentifier();
-    }
-    
-       secdebug("KCLogin", "StorageManager::stash: loginDLDbIdentifier is %s", (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-       if (!loginDLDbIdentifier)
-               MacOSError::throwMe(errSecNoSuchKeychain);
-    
-    try
-    {
-        CssmData empty;
-        Keychain theKeychain(keychain(loginDLDbIdentifier));
-        secdebug("KCLogin", "Attempting to use stash for login keychain \"%s\"",
-                 (theKeychain) ? theKeychain->name() : "<NULL>");
-        theKeychain->stashCheck();
-    }
-    catch(const CssmError &e)
-    {
-        loginResult = e.osStatus(); // save this result
-    }
-    
-    
-    if (loginResult != errSecSuccess) {
-        MacOSError::throwMe(loginResult);
-    }
-}
-
-void StorageManager::stashKeychain()
-{
-    OSStatus loginResult = errSecSuccess;
-    
-    DLDbIdentifier loginDLDbIdentifier;
-    {
-        mSavedList.revert(true);
-        loginDLDbIdentifier = mSavedList.loginDLDbIdentifier();
-    }
-    
-       secdebug("KCLogin", "StorageManager::stash: loginDLDbIdentifier is %s", (loginDLDbIdentifier) ? loginDLDbIdentifier.dbName() : "<NULL>");
-       if (!loginDLDbIdentifier)
-               MacOSError::throwMe(errSecNoSuchKeychain);
-    
-    try
-    {
-        Keychain theKeychain(keychain(loginDLDbIdentifier));
-        secdebug("KCLogin", "Attempting to stash login keychain \"%s\"",
-                 (theKeychain) ? theKeychain->name() : "<NULL>");
-        theKeychain->stash();
-    }
-    catch(const CssmError &e)
-    {
-        loginResult = e.osStatus(); // save this result
-    }
-
-
-    if (loginResult != errSecSuccess) {
-        MacOSError::throwMe(loginResult);
-    }
-}
-
-void StorageManager::logout()
-{
-    // nothing left to do here
-}
-
-void StorageManager::changeLoginPassword(ConstStringPtr oldPassword, ConstStringPtr newPassword)
-{
-       StLock<Mutex>_(mMutex);
-
-       loginKeychain()->changePassphrase(oldPassword, newPassword);
-       secdebug("KClogin", "Changed login keychain password successfully");
-}
-
-
-void StorageManager::changeLoginPassword(UInt32 oldPasswordLength, const void *oldPassword,  UInt32 newPasswordLength, const void *newPassword)
-{
-       StLock<Mutex>_(mMutex);
-
-       loginKeychain()->changePassphrase(oldPasswordLength, oldPassword,  newPasswordLength, newPassword);
-       secdebug("KClogin", "Changed login keychain password successfully");
-}
-
-// Clear out the keychain search list and rename the existing login.keychain.
-//
-void StorageManager::resetKeychain(Boolean resetSearchList)
-{
-       StLock<Mutex>_(mMutex);
-
-    // Clear the keychain search list.
-    try
-    {
-        if ( resetSearchList )
-        {
-            StorageManager::KeychainList keychainList;
-            setSearchList(keychainList);
-        }
-        // Get a reference to the existing login keychain...
-        // If we don't have one, we throw (not requiring a rename).
-        //
-        Keychain keychain = loginKeychain();
-        //
-        // Rename the existing login.keychain (i.e. put it aside).
-        //
-        CFMutableStringRef newName = NULL;
-        newName = CFStringCreateMutable(NULL, 0);
-        CFStringRef currName = NULL;
-        currName = CFStringCreateWithCString(NULL, keychain->name(), kCFStringEncodingUTF8);
-        if ( newName && currName )
-        {
-            CFStringAppend(newName, currName);
-            CFStringRef kcSuffix = CFSTR(kKeychainSuffix);
-            if ( CFStringHasSuffix(newName, kcSuffix) )        // remove the .keychain extension
-            {
-                CFRange suffixRange = CFStringFind(newName, kcSuffix, 0);
-                CFStringFindAndReplace(newName, kcSuffix, CFSTR(""), suffixRange, 0);
-            }
-            CFStringAppend(newName, CFSTR(kKeychainRenamedSuffix));    // add "_renamed_"
-            try
-            {
-                renameUnique(keychain, newName);
-            }
-            catch(...)
-            {
-                // we need to release 'newName' & 'currName'
-            }
-        }       // else, let the login call report a duplicate
-        if ( newName )
-            CFRelease(newName);
-        if ( currName )
-            CFRelease(currName);
-    }
-    catch(...)
-    {
-        // We either don't have a login keychain, or there was a
-        // failure to rename the existing one.
-    }
-}
-
-#pragma mark ____ File Related ____
-
-Keychain StorageManager::make(const char *pathName)
-{
-       return make(pathName, true);
-}
-
-Keychain StorageManager::make(const char *pathName, bool add)
-{
-       StLock<Mutex>_(mMutex);
-
-       string fullPathName;
-    if ( pathName[0] == '/' )
-               fullPathName = pathName;
-       else
-    {
-               // Get Home directory from environment.
-               switch (mDomain)
-               {
-               case kSecPreferencesDomainUser:
-                       {
-                               const char *homeDir = getenv("HOME");
-                               if (homeDir == NULL)
-                               {
-                                       // If $HOME is unset get the current user's home directory
-                                       // from the passwd file.
-                                       uid_t uid = geteuid();
-                                       if (!uid) uid = getuid();
-                                       struct passwd *pw = getpwuid(uid);
-                                       if (!pw)
-                                               MacOSError::throwMe(errSecParam);
-                                       homeDir = pw->pw_dir;
-                               }
-                               fullPathName = homeDir;
-                       }
-                       break;
-               case kSecPreferencesDomainSystem:
-                       fullPathName = "";
-                       break;
-               default:
-                       assert(false);  // invalid domain for this
-               }
-
-               fullPathName += "/Library/Keychains/";
-               fullPathName += pathName;
-       }
-
-    const CSSM_NET_ADDRESS *DbLocation = NULL; // NULL for keychains
-    const CSSM_VERSION *version = NULL;
-    uint32 subserviceId = 0;
-    CSSM_SERVICE_TYPE subserviceType = CSSM_SERVICE_DL | CSSM_SERVICE_CSP;
-    const CssmSubserviceUid ssuid(gGuidAppleCSPDL, version,
-                                   subserviceId, subserviceType);
-       DLDbIdentifier dLDbIdentifier(ssuid, fullPathName.c_str(), DbLocation);
-       return makeKeychain(dLDbIdentifier, add);
-}
-
-Keychain StorageManager::makeLoginAuthUI(const Item *item)
-{
-       StLock<Mutex>_(mMutex);
-
-    // Create a login/default keychain for the user using UI.
-    // The user can cancel out of the operation, or create a new login keychain.
-    // If auto-login is turned off, the user will be asked for their login password.
-    //
-    OSStatus result = errSecSuccess;
-    Keychain keychain; // We return this keychain.
-    //
-    // Set up the Auth ref to bring up UI.
-    //
-       AuthorizationItem *currItem, *authEnvirItemArrayPtr = NULL;
-    AuthorizationRef authRef = NULL;
-       try
-       {
-               result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authRef);
-               if ( result )
-                       MacOSError::throwMe(result);
-
-               AuthorizationEnvironment envir;
-               envir.count = 6;        // up to 6 hints can be used.
-               authEnvirItemArrayPtr = (AuthorizationItem*)malloc(sizeof(AuthorizationItem) * envir.count);
-               if ( !authEnvirItemArrayPtr )
-                       MacOSError::throwMe(errAuthorizationInternal);
-
-               currItem = envir.items = authEnvirItemArrayPtr;
-
-               //
-               // 1st Hint (optional): The keychain item's account attribute string.
-               //                                              When item is specified, we assume an 'add' operation is being attempted.
-               char buff[256];
-               UInt32 actLen = 0;
-               SecKeychainAttribute attr = { kSecAccountItemAttr, 255, &buff };
-               if ( item )
-               {
-                       try
-                       {
-                               (*item)->getAttribute(attr, &actLen);
-                       }
-                       catch(...)
-                       {
-                               actLen = 0;     // This item didn't have the account attribute, so don't display one in the UI.
-                       }
-               }
-               currItem->name = AGENT_HINT_ATTR_NAME;  // name str that identifies this hint as attr name
-               if ( actLen )   // Fill in the hint if we have an account attr
-               {
-                       if ( actLen >= sizeof(buff) )
-                               buff[sizeof(buff)-1] = 0;
-                       else
-                               buff[actLen] = 0;
-                       currItem->valueLength = strlen(buff)+1;
-                       currItem->value = buff;
-               }
-               else
-               {
-                       currItem->valueLength = 0;
-                       currItem->value = NULL;
-               }
-               currItem->flags = 0;
-
-               //
-               // 2nd Hint (optional): The item's keychain full path.
-               //
-               currItem++;
-               char* currDefaultName = NULL;
-               try
-               {
-                       currDefaultName = (char*)defaultKeychain()->name();     // Use the name if we have it.
-                       currItem->name = AGENT_HINT_LOGIN_KC_NAME;      // Name str that identifies this hint as kc path
-                       currItem->valueLength = (currDefaultName) ? strlen(currDefaultName) : 0;
-                       currItem->value = (currDefaultName) ? (void*)currDefaultName : (void*)"";
-                       currItem->flags = 0;
-                       currItem++;
-               }
-               catch(...)
-               {
-                       envir.count--;
-               }
-
-               //
-               // 3rd Hint (required): check if curr default keychain is unavailable.
-               // This is determined by the parent not existing.
-               //
-               currItem->name = AGENT_HINT_LOGIN_KC_EXISTS_IN_KC_FOLDER;
-               Boolean loginUnavail = false;
-               try
-               {
-                       Keychain defaultKC = defaultKeychain();
-                       if ( !defaultKC->exists() )
-                               loginUnavail = true;
-               }
-               catch(...)      // login.keychain not present
-               {
-               }
-               currItem->valueLength = sizeof(Boolean);
-               currItem->value = (void*)&loginUnavail;
-               currItem->flags = 0;
-
-               //
-               // 4th Hint (required): userName
-               //
-               currItem++;
-               currItem->name = AGENT_HINT_LOGIN_KC_USER_NAME;
-               char* uName = getenv("USER");
-               string userName = uName ? uName : "";
-               if ( userName.length() == 0 )
-               {
-                       uid_t uid = geteuid();
-                       if (!uid) uid = getuid();
-                       struct passwd *pw = getpwuid(uid);      // fallback case...
-                       if (pw)
-                               userName = pw->pw_name;
-                       endpwent();
-               }
-               if ( userName.length() == 0 )   // did we ultimately get one?
-                       MacOSError::throwMe(errAuthorizationInternal);
-
-               currItem->value = (void*)userName.c_str();
-               currItem->valueLength = userName.length();
-               currItem->flags = 0;
-
-               //
-               // 5th Hint (required): flags if user has more than 1 keychain (used for a later warning when reset to default).
-               //
-               currItem++;
-               currItem->name = AGENT_HINT_LOGIN_KC_USER_HAS_OTHER_KCS_STR;
-               Boolean moreThanOneKCExists = false;
-               {
-                       // if item is NULL, then this is a user-initiated full reset
-                       if (item && mSavedList.searchList().size() > 1)
-                               moreThanOneKCExists = true;
-               }
-               currItem->value = &moreThanOneKCExists;
-               currItem->valueLength = sizeof(Boolean);
-               currItem->flags = 0;
-
-               //
-               // 6th Hint (required): If no item is involved, this is a user-initiated full reset.
-               // We want to suppress the "do you want to reset to defaults?" panel in this case.
-               //
-               currItem++;
-               currItem->name = AGENT_HINT_LOGIN_KC_SUPPRESS_RESET_PANEL;
-               Boolean suppressResetPanel = (item == NULL) ? TRUE : FALSE;
-               currItem->valueLength = sizeof(Boolean);
-               currItem->value = (void*)&suppressResetPanel;
-               currItem->flags = 0;
-
-               //
-               // Set up the auth rights and make the auth call.
-               //
-               AuthorizationItem authItem = { LOGIN_KC_CREATION_RIGHT, 0 , NULL, 0 };
-               AuthorizationRights rights = { 1, &authItem };
-               AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
-               result = AuthorizationCopyRights(authRef, &rights, &envir, flags, NULL);
-               if ( result )
-                       MacOSError::throwMe(result);
-               try
-               {
-                       resetKeychain(true); // Clears the plist, moves aside existing login.keychain
-               }
-               catch (...) // can throw if no existing login.keychain is found
-               {
-               }
-               login(authRef, (UInt32)userName.length(), userName.c_str()); // Create login.keychain
-               keychain = loginKeychain(); // Get newly-created login keychain
-               defaultKeychain(keychain);      // Set it to be the default
-
-               free(authEnvirItemArrayPtr);
-               AuthorizationFree(authRef, kAuthorizationFlagDefaults);
-       }
-
-       catch (...)
-       {
-               // clean up allocations, then rethrow error
-               if ( authEnvirItemArrayPtr )
-                       free(authEnvirItemArrayPtr);
-               if ( authRef )
-                       AuthorizationFree(authRef, kAuthorizationFlagDefaults);
-               throw;
-       }
-
-    return keychain;
-}
-
-Keychain StorageManager::defaultKeychainUI(Item &item)
-{
-       StLock<Mutex>_(mMutex);
-
-    Keychain returnedKeychain;
-    try
-    {
-        returnedKeychain = defaultKeychain(); // If we have one, return it.
-        if ( returnedKeychain->exists() )
-            return returnedKeychain;
-    }
-    catch(...) // We could have one, but it isn't available (i.e. on a un-mounted volume).
-    {
-    }
-    if ( globals().getUserInteractionAllowed() )
-    {
-        returnedKeychain = makeLoginAuthUI(&item); // If no Keychains is present, one will be created.
-        if ( !returnedKeychain )
-            MacOSError::throwMe(errSecInvalidKeychain);        // Something went wrong...
-    }
-    else
-        MacOSError::throwMe(errSecInteractionNotAllowed); // If UI isn't allowed, return an error.
-
-    return returnedKeychain;
-}
-
-void
-StorageManager::addToDomainList(SecPreferencesDomain domain,
-       const char* dbName, const CSSM_GUID &guid, uint32 subServiceType)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       // make the identifier
-       CSSM_VERSION version = {0, 0};
-       DLDbIdentifier id = DLDbListCFPref::makeDLDbIdentifier (guid, version, 0,
-               subServiceType, dbName, NULL);
-
-       if (domain == mDomain)
-       {
-               // manipulate the user's list
-               {
-                       mSavedList.revert(true);
-                       mSavedList.add(id);
-                       mSavedList.save();
-               }
-
-               KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-       }
-       else
-       {
-               // manipulate the other list
-               DLDbListCFPref(domain).add(id);
-       }
-}
-
-void
-StorageManager::isInDomainList(SecPreferencesDomain domain,
-       const char* dbName, const CSSM_GUID &guid, uint32 subServiceType)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       CSSM_VERSION version = {0, 0};
-       DLDbIdentifier id = DLDbListCFPref::makeDLDbIdentifier (guid, version, 0,
-               subServiceType, dbName, NULL);
-
-       // determine the list to search
-       bool result;
-       if (domain == mDomain)
-       {
-               result = mSavedList.member(id);
-       }
-       else
-       {
-               result = DLDbListCFPref(domain).member(id);
-       }
-
-       // do the search
-       if (!result)
-       {
-               MacOSError::throwMe(errSecNoSuchKeychain);
-       }
-}
-
-void
-StorageManager::removeFromDomainList(SecPreferencesDomain domain,
-       const char* dbName, const CSSM_GUID &guid, uint32 subServiceType)
-{
-       StLock<Mutex>_(mMutex);
-
-       if (domain == kSecPreferencesDomainDynamic)
-               MacOSError::throwMe(errSecInvalidPrefsDomain);
-
-       // make the identifier
-       CSSM_VERSION version = {0, 0};
-       DLDbIdentifier id = DLDbListCFPref::makeDLDbIdentifier (guid, version, 0,
-               subServiceType, dbName, NULL);
-
-       if (domain == mDomain)
-       {
-               // manipulate the user's list
-               {
-                       mSavedList.revert(true);
-                       mSavedList.remove(id);
-                       mSavedList.save();
-               }
-
-               KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
-       }
-       else
-       {
-               // manipulate the other list
-               DLDbListCFPref(domain).remove(id);
-       }
-}
-
-bool
-StorageManager::keychainOwnerPermissionsValidForDomain(const char* path, SecPreferencesDomain domain)
-{
-       struct stat sb;
-       mode_t perms;
-       const char* sysPrefDir = "/Library/Preferences";
-       const char* errMsg = "Will not set default";
-       char* mustOwnDir = NULL;
-       struct passwd* pw = NULL;
-
-       // get my uid
-       uid_t uid = geteuid();
-       if (!uid) uid = getuid();
-
-       // our (e)uid must own the appropriate preferences or home directory
-       // for the specified preference domain whose default we will be modifying
-       switch (domain) {
-               case kSecPreferencesDomainUser:
-                       mustOwnDir = getenv("HOME");
-                       if (mustOwnDir == NULL) {
-                               pw = getpwuid(uid);
-                               if (!pw) return false;
-                               mustOwnDir = pw->pw_dir;
-                       }
-                       break;
-               case kSecPreferencesDomainSystem:
-                       mustOwnDir = (char*)sysPrefDir;
-                       break;
-               case kSecPreferencesDomainCommon:
-                       mustOwnDir = (char*)sysPrefDir;
-                       break;
-               default:
-                       return false;
-       }
-
-       if (mustOwnDir != NULL) {
-               struct stat dsb;
-               if ( (stat(mustOwnDir, &dsb) != 0) || (dsb.st_uid != uid) ) {
-                       fprintf(stderr, "%s: UID=%d does not own directory %s\n", errMsg, (int)uid, mustOwnDir);
-                       mustOwnDir = NULL; // will return below after calling endpwent()
-               }
-       }
-
-       if (pw != NULL)
-               endpwent();
-
-       if (mustOwnDir == NULL)
-               return false;
-
-       // check that file actually exists
-       if (stat(path, &sb) != 0) {
-               fprintf(stderr, "%s: file %s does not exist\n", errMsg, path);
-               return false;
-       }
-
-       // check flags
-       if (sb.st_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
-               fprintf(stderr, "%s: file %s is immutable\n", errMsg, path);
-               return false;
-       }
-
-       // check ownership
-       if (sb.st_uid != uid) {
-               fprintf(stderr, "%s: file %s is owned by UID=%d, but we have UID=%d\n",
-                       errMsg, path, (int)sb.st_uid, (int)uid);
-               return false;
-       }
-
-       // check mode
-       perms = sb.st_mode;
-       perms |= 0600; // must have owner read/write permission set
-       if (sb.st_mode != perms) {
-               fprintf(stderr, "%s: file %s does not have the expected permissions\n", errMsg, path);
-               return false;
-       }
-
-       // user owns file and can read/write it
-       return true;
-}