]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/SecKeychain.cpp
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecKeychain.cpp
index 8a48d3f2a5ae87728ee7878e43b468810ad01afd..b13c0357d7fe3045fa3cad59149a0b33a5b5fadb 100644 (file)
 #include <security_cdsa_utilities/Schema.h>
 #include <security_cdsa_client/mdsclient.h>
 #include <pwd.h>
+#include <os/activity.h>
+#include <Security/AuthorizationTagsPriv.h>
+#include <Security/Authorization.h>
+#include "TokenLogin.h"
 
 OSStatus
 SecKeychainMDSInstall()
 {
-       BEGIN_SECAPI
+    BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        Security::MDSClient::Directory d;
        d.install();
@@ -73,6 +80,9 @@ OSStatus
 SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle();
 
@@ -85,6 +95,9 @@ SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subse
                                                const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainOpenWithGuid", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        // range check parameters
        RequiredParam (guid);
@@ -96,7 +109,7 @@ SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subse
        DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation);
        
        // make a keychain from the supplied info
-       RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false)->handle ();
+       RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false, false)->handle ();
 
        END_SECAPI
 }
@@ -107,9 +120,12 @@ SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *passw
        Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
     
     KCThrowParamErrIf_(!pathName);
-       Keychain keychain = globals().storageManager.make(pathName);
+       Keychain keychain = globals().storageManager.make(pathName, true, true);
 
        // @@@ the call to StorageManager::make above leaves keychain the the cache.
        // If the create below fails we should probably remove it.
@@ -131,6 +147,9 @@ OSStatus
 SecKeychainDelete(SecKeychainRef keychainOrArray)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        KCThrowIf_(!keychainOrArray, errSecInvalidKeychain);
        StorageManager::KeychainList keychains;
@@ -146,6 +165,9 @@ OSStatus
 SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        Keychain keychain = Keychain::optional(keychainRef);
        if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1)
@@ -163,6 +185,9 @@ OSStatus
 SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        Keychain keychain = Keychain::optional(keychainRef);
        if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1)
@@ -183,6 +208,9 @@ OSStatus
 SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        Keychain keychain = Keychain::optional(keychainRef);
 
@@ -199,6 +227,9 @@ OSStatus
 SecKeychainLock(SecKeychainRef keychainRef)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        Keychain keychain = Keychain::optional(keychainRef);
        keychain->lock();
@@ -211,6 +242,9 @@ OSStatus
 SecKeychainLockAll(void)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        globals().storageManager.lockAll();
 
@@ -221,6 +255,9 @@ SecKeychainLockAll(void)
 OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
         //
         // Get the current user (using fallback method if necessary)
         //
@@ -236,17 +273,19 @@ OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Bool
             endpwent();
         }
         if ( userName.length() == 0 )  // did we ultimately get one?
+        {
             MacOSError::throwMe(errAuthorizationInternal);
+        }
 
         SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData());
-
+        secwarning("SecKeychainResetLogin: reset AKS passphrase");
                if (password)
                {
                        // Clear the plist and move aside (rename) the existing login.keychain
                        globals().storageManager.resetKeychain(resetSearchList);
 
                        // Create the login keychain without UI
-                       globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password);
+                       globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password, true);
                        
                        // Set it as the default
                        Keychain keychain = globals().storageManager.loginKeychain();
@@ -256,13 +295,15 @@ OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Bool
                {
                        // Create the login keychain, prompting for password
                        // (implicitly calls resetKeychain, login, and defaultKeychain)
-                       globals().storageManager.makeLoginAuthUI(NULL);
+                       globals().storageManager.makeLoginAuthUI(NULL, true);
                }
+        secwarning("SecKeychainResetLogin: reset osx keychain");
 
                // Post a "list changed" event after a reset, so apps can refresh their list.
                // Make sure we are not holding mLock when we post this event.
                KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
 
+
        END_SECAPI
 }
 
@@ -281,6 +322,9 @@ OSStatus
 SecKeychainSetDefault(SecKeychainRef keychainRef)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        globals().storageManager.defaultKeychain(Keychain::optional(keychainRef));
 
@@ -290,6 +334,9 @@ SecKeychainSetDefault(SecKeychainRef keychainRef)
 OSStatus SecKeychainCopySearchList(CFArrayRef *searchList)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(searchList);
        StorageManager &smr = globals().storageManager;
@@ -303,6 +350,9 @@ OSStatus SecKeychainCopySearchList(CFArrayRef *searchList)
 OSStatus SecKeychainSetSearchList(CFArrayRef searchList)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(searchList);
        StorageManager &smr = globals().storageManager;
@@ -316,6 +366,9 @@ OSStatus SecKeychainSetSearchList(CFArrayRef searchList)
 OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle();
 
@@ -325,6 +378,9 @@ OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRe
 OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef));
 
@@ -347,6 +403,9 @@ OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef
 OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(searchList);
        StorageManager &smr = globals().storageManager;
@@ -360,6 +419,9 @@ OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef
 OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        globals().storageManager.domain(domain);
 
@@ -369,6 +431,9 @@ OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain)
 OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
        
        *domain = globals().storageManager.domain();
        
@@ -408,6 +473,50 @@ SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathN
        END_SECAPI
 }
 
+OSStatus
+SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version)
+{
+    BEGIN_SECAPI
+
+    RequiredParam(version);
+
+    *version = Keychain::optional(keychainRef)->database()->dbBlobVersion();
+
+    END_SECAPI
+}
+
+OSStatus
+SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename)
+{
+    BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
+
+    RequiredParam(masterKeyFilename);
+    Keychain kc = Keychain::optional(keychain);
+
+    SecurityServer::SystemKeychainKey keychainKey(masterKeyFilename);
+    if(keychainKey.valid()) {
+        // We've managed to read the key; now, create credentials using it
+        string path = kc->name();
+
+        CssmClient::Key keychainMasterKey(kc->csp(), keychainKey.key(), true);
+        CssmClient::AclFactory::MasterKeyUnlockCredentials creds(keychainMasterKey, Allocator::standard(Allocator::sensitive));
+
+        // Attempt the migrate, using our master key as the ACL override
+        bool result = kc->keychainMigration(path, kc->database()->dbBlobVersion(), path, version, creds.getAccessCredentials());
+        if(!result) {
+            return errSecBadReq;
+        }
+        return (kc->database()->dbBlobVersion() == version ? errSecSuccess : errSecBadReq);
+    } else {
+        return errSecBadReq;
+    }
+
+    END_SECAPI
+}
+
 
 // @@@ Deprecated
 UInt16
@@ -478,6 +587,9 @@ pascal OSStatus
 SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(callbackFunction);
        CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext);
@@ -490,6 +602,9 @@ OSStatus
 SecKeychainRemoveCallback(SecKeychainCallback callbackFunction)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(callbackFunction);
        CCallbackMgr::RemoveCallback(callbackFunction);
@@ -501,6 +616,9 @@ OSStatus
 SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
        // @@@ Get real itemClass
@@ -560,6 +678,9 @@ SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLeng
                                                                                                
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        StorageManager::KeychainList keychains;
        globals().storageManager.optionalSearchList(keychainOrArray, keychains);
@@ -615,9 +736,13 @@ SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLeng
        {
                CssmDataContainer outData;
                item->getData(outData);
-               *passwordLength=(UInt32)outData.length();
+               if (passwordLength) {
+                       *passwordLength=(UInt32)outData.length();
+               }
                outData.Length=0;
-               *passwordData=outData.data();
+               if (passwordData) {
+                       *passwordData=outData.data();
+               }
                outData.Data=NULL;
        }
 
@@ -632,6 +757,9 @@ OSStatus
 SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
        // @@@ Get real itemClass
@@ -642,17 +770,7 @@ SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLeng
        {
                CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength);
                item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
-               // use service name as default label (UNLESS the service is iTools and we have an account name [3787371])
-               const char *iTools = "iTools";
-               if (accountNameLength && serviceNameLength==strlen(iTools) && !memcmp(serviceName, iTools, serviceNameLength))
-               {
-                       CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
-                       item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), account);
-               }
-               else
-               {
-                       item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
-               }
+        item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
        }
 
        if (accountName && accountNameLength)
@@ -688,6 +806,9 @@ SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLeng
                                                                                                                                                           
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        StorageManager::KeychainList keychains;
        globals().storageManager.optionalSearchList(keychainOrArray, keychains);
@@ -714,9 +835,13 @@ SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLeng
        {
                CssmDataContainer outData;
                item->getData(outData);
-               *passwordLength=(UInt32)outData.length();
+               if (passwordLength) {
+                       *passwordLength=(UInt32)outData.length();
+               }
                outData.Length=0;
-               *passwordData=outData.data();
+               if (passwordData) {
+                       *passwordData=outData.data();
+               }
                outData.Data=NULL;
        }
 
@@ -753,6 +878,9 @@ OSStatus
 SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(dldbHandle);
        
@@ -762,6 +890,8 @@ SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHand
     END_SECAPI
 }
 
+static ModuleNexus<Mutex> gSecReturnedKeychainCSPsMutex;
+static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeychainCSPs;
 
 OSStatus
 SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle)
@@ -771,7 +901,15 @@ SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle)
        RequiredParam(cspHandle);
 
        Keychain keychain = Keychain::optional(keychainRef);
-       *cspHandle = keychain->csp()->handle();
+
+    // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
+    // Keep a global pointer to it to force the CSP to stay live forever.
+    CssmClient::CSP returnedKeychainCSP = keychain->csp();
+    {
+        StLock<Mutex> _(gSecReturnedKeychainCSPsMutex());
+        gSecReturnedKeychainCSPs().insert(returnedKeychainCSP);
+    }
+       *cspHandle = returnedKeychainCSP->handle();
 
        END_SECAPI
 }
@@ -806,6 +944,9 @@ OSStatus
 SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword,  UInt32 newPasswordLength, const void *newPassword)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        Keychain keychain = Keychain::optional(keychainRef);
         keychain->changePassphrase (oldPasswordLength, oldPassword,  newPasswordLength, newPassword);
@@ -818,6 +959,9 @@ OSStatus
 SecKeychainCopyLogin(SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle();
 
@@ -829,17 +973,21 @@ OSStatus
 SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        try
        {
                if (password) {
-            globals().storageManager.login(nameLength, name,  passwordLength, password);
+            globals().storageManager.login(nameLength, name,  passwordLength, password, false);
         } else {
             globals().storageManager.stashLogin();
         }
        }
        catch (CommonError &e)
        {
+        secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not");
                if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
                {
                        return errSecAuthFailed;
@@ -849,13 +997,21 @@ SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, con
                        return e.osStatus();
                }
        }
-       
+
+    catch (...) {
+        __secapiresult=errSecInternalComponent;
+    }
+    secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not");
+
     END_SECAPI
 }
 
 OSStatus SecKeychainStash()
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
     
        try
        {
@@ -880,6 +1036,9 @@ OSStatus
 SecKeychainLogout()
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        globals().storageManager.logout();
 
@@ -922,6 +1081,9 @@ OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
 OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
         StorageManager::KeychainList singleton;
         singleton.push_back(KeychainImpl::required(keychainRef));
         globals().storageManager.remove(singleton);
@@ -933,6 +1095,9 @@ OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
 OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
         RequiredParam(inPassword);
         KeychainImpl::required(keychainRef)->create(passwordLength, inPassword);
        END_SECAPI
@@ -943,6 +1108,9 @@ OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength,
 OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        // do error checking for required parameters
        RequiredParam(dbBlobArray);
@@ -1018,6 +1186,9 @@ OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlob
 OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) 
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        // do error checking for required parameters
        RequiredParam(keychainSignature);
@@ -1042,6 +1213,9 @@ OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychai
 OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        // do error checking for required parameters
        RequiredParam(dbBlob);
@@ -1061,6 +1235,9 @@ OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
 OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
        
        KCThrowParamErrIf_(!fullPathName);
        KCThrowParamErrIf_(!dbBlob);
@@ -1085,6 +1262,9 @@ OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char
                                                                                 const CSSM_GUID *guid, uint32 subServiceType)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
        RequiredParam(dbName);
        StorageManager &smr = globals().storageManager;
@@ -1109,6 +1289,9 @@ OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const
                                                                                          const CSSM_GUID *guid, uint32 subServiceType)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
        RequiredParam(dbName);
        StorageManager &smr = globals().storageManager;
        smr.removeFromDomainList(domain, dbName, *guid, subServiceType);
@@ -1127,6 +1310,9 @@ void SecKeychainSetServerMode()
 OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
 {
        BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
        RequiredParam(kcRef);
        Keychain keychain = Keychain::optional(kcRef);
        keychain->setBatchMode(mode, rollback);
@@ -1144,6 +1330,9 @@ OSStatus SecKeychainCleanupHandles()
 OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
     SecurityServer::ClientSession().verifyKeyStorePassphrase(retries);
     END_SECAPI
 }
@@ -1151,6 +1340,9 @@ OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
 OSStatus SecKeychainChangeKeyStorePassphrase()
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
     SecurityServer::ClientSession().changeKeyStorePassphrase();
     END_SECAPI
 }
@@ -1158,6 +1350,9 @@ OSStatus SecKeychainChangeKeyStorePassphrase()
 static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password)
 {
     BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
 
     // make a keychain object "wrapper" for this keychain ref
        Keychain keychain = Keychain::optional(userKeychainRef);
@@ -1175,9 +1370,9 @@ static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRe
     cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
                       new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
                       new(alloc) ListElement(StringData(passphrase)));
-       db->accessCredentials(&cred);
-    
-    CSSM_DL_DB_HANDLE dlDb = db->handle();
+       db->authenticate(CSSM_DB_ACCESS_READ, &cred);
+
+       CSSM_DL_DB_HANDLE dlDb = db->handle();
        CssmData dlDbData = CssmData::wrap(dlDb);
        CssmKey refKey;
        KeySpec spec(CSSM_KEYUSE_ANY,
@@ -1196,6 +1391,81 @@ static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRe
     END_SECAPI
 }
 
+static const char     *kAutologinPWFilePath = "/etc/kcpassword";
+static const uint32_t kObfuscatedPasswordSizeMultiple = 12;
+static const uint32_t buffer_size = 512;
+static const uint8_t  kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f};
+
+static void obfuscate(void *buffer, size_t bufferLength)
+{
+       uint8_t       *pBuf = (uint8_t *) buffer;
+       const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey );
+
+       while (bufferLength--) {
+               *pBuf = *pBuf ^ *pKey;
+               ++pKey;
+               ++pBuf;
+               if (pKey == eKey)
+                       pKey = kObfuscationKey;
+       }
+}
+
+static bool _SASetAutologinPW(CFStringRef inAutologinPW)
+{
+       bool    result = false;
+       struct stat sb;
+
+       // Delete the kcpassword file if it exists already
+       if (stat(kAutologinPWFilePath, &sb) == 0)
+               unlink( kAutologinPWFilePath );
+
+    // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off.
+    if (inAutologinPW != NULL) {
+               char buffer[buffer_size];
+               const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8);
+               if (pwAsUTF8String == NULL) {
+                       if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer;
+               }
+
+               if (pwAsUTF8String != NULL) {
+                       size_t pwLength = strlen(pwAsUTF8String) + 1;
+                       size_t obfuscatedPWLength;
+                       char *obfuscatedPWBuffer;
+
+                       // The size of the obfuscated password should be the smallest multiple of
+                       // kObfuscatedPasswordSizeMultiple greater than or equal to pwLength.
+                       obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple;
+                       obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength);
+
+                       // Copy the password (including null terminator) to beginning of obfuscatedPWBuffer
+                       bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength);
+
+                       // Pad remainder of obfuscatedPWBuffer with random bytes
+                       {
+                               char *p;
+                               char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength;
+
+                               for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p)
+                                       *p = random() & 0x000000FF;
+                       }
+
+                       obfuscate(obfuscatedPWBuffer, obfuscatedPWLength);
+
+                       int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR);
+                       if (pwFile >= 0) {
+                               size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength);
+                               if (wrote == obfuscatedPWLength)
+                                       result = true;
+                               close(pwFile);
+                       }
+
+                       chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR);
+                       free(obfuscatedPWBuffer);
+               }
+       }
+
+    return result;
+}
 
 OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) {
     SecTrustedApplicationRef itemPath;
@@ -1203,6 +1473,14 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe
     
     OSStatus result = errSecParam;
     
+       if (userKeychainRef == NULL) {
+               // We don't have a specific user keychain, fall back
+               if (_SASetAutologinPW(password))
+                       result = errSecSuccess;
+
+               return result;
+       }
+
     CFDataRef masterKey = NULL;
     result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password);
     if (errSecSuccess != result) {
@@ -1211,18 +1489,21 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe
     
     result = SecKeychainStash();
     if (errSecSuccess != result) {
-        if (NULL != masterKey) CFRelease(masterKey);
+        if (masterKey != NULL) CFRelease(masterKey);
         return result;
     }
     
     CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-    if ( noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath  )
+    if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath)
         CFArrayAppendValue(trustedApplications, itemPath);
     
-    if ( trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) {
+    if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) {
         if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) {
+                       SecKeychainRef internalSystemKeychainRef = NULL;
             if (NULL == systemKeychainRef) {
-                SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &systemKeychainRef);
+                               SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef);
+            } else {
+                internalSystemKeychainRef = systemKeychainRef;
             }
             
             const void *queryKeys[] =   { kSecClass,
@@ -1233,7 +1514,7 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe
             const void *queryValues[] = { kSecClassGenericPassword,
                 CFSTR("com.apple.loginwindow.auto-login"),
                 username,
-                systemKeychainRef,
+                               internalSystemKeychainRef,
             };
             
             const void *updateKeys[] =   { kSecAttrAccess,
@@ -1259,7 +1540,7 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe
                 const void *addValues[] = { kSecClassGenericPassword,
                     CFSTR("com.apple.loginwindow.auto-login"),
                     username,
-                    systemKeychainRef,
+                                       internalSystemKeychainRef,
                     ourAccessRef,
                     masterKey,
                 };
@@ -1271,13 +1552,127 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe
 
             if (NULL != query) CFRelease(query);
             if (NULL != update) CFRelease(update);
+
+                       // If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one
+                       if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef);
         }
     }
 
     if (NULL != masterKey) CFRelease(masterKey);
     if (NULL != trustedApplications) CFRelease(trustedApplications);
     if (NULL != ourAccessRef) CFRelease(ourAccessRef);
-    if (NULL != systemKeychainRef) CFRelease(systemKeychainRef);
 
     return result;
 }
+
+OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts)
+{
+    BEGIN_SECAPI
+    os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+    os_activity_scope(activity);
+    os_release(activity);
+
+    if(attempts) {
+        SecurityServer::ClientSession().getUserPromptAttempts(*attempts);
+    }
+
+    END_SECAPI
+}
+
+OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash,
+                                                 SecKeychainRef userKeychain, CFStringRef password)
+{
+       CFRef<CFStringRef> pwd;
+       OSStatus result;
+
+       if (password == NULL || CFStringGetLength(password) == 0) {
+               AuthorizationRef authorizationRef;
+               result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
+               if (result != errAuthorizationSuccess) {
+                       secnotice("SecKeychain", "failed to create authorization");
+                       return result;
+               }
+
+               AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0};
+               AuthorizationRights myRights = {1, &myItems};
+               AuthorizationRights *authorizedRights = NULL;
+
+               char pathName[PATH_MAX];
+               UInt32 pathLength = PATH_MAX;
+               result = SecKeychainGetPath(userKeychain, &pathLength, pathName);
+               if (result != errSecSuccess) {
+                       secnotice("SecKeychain", "failed to create authorization");
+                       return result;
+               }
+
+               Boolean checkPwd = TRUE;
+               Boolean ignoreSession = TRUE;
+               AuthorizationItem envItems[] = {
+                       {AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0},
+                       {AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd},
+                       {AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession}
+               };
+
+               AuthorizationEnvironment environment  = {3, envItems};
+               AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
+               result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, &authorizedRights);
+               if (authorizedRights)
+                       AuthorizationFreeItemSet(authorizedRights);
+
+               if (result == errAuthorizationSuccess) {
+                       AuthorizationItemSet *items;
+                       result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items);
+                       if (result == errAuthorizationSuccess) {
+                               if (items->count > 0) {
+                                       pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8);
+                               }
+                               AuthorizationFreeItemSet(items);
+                       }
+               }
+               AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
+               if (result != errAuthorizationSuccess) {
+                       secnotice("SecKeychain", "did not get authorization to pair the card");
+                       return result;
+               }
+       } else {
+               pwd.take(password);
+       }
+
+       if (!pwd) {
+               secnotice("SecKeychain", "did not get kcpass");
+               return errSecInternalComponent;
+       }
+
+       CFRef<CFDataRef> masterKey;
+       result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd);
+       if (result != errSecSuccess) {
+               secnotice("SecKeychain", "Failed to get master key: %d", (int) result);
+               return result;
+       }
+
+       CFRef<CFDataRef> scBlob;
+       result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take());
+       if (result != errSecSuccess) {
+               secnotice("SecKeychain", "Failed to get stash: %d", (int) result);
+               return result;
+       }
+
+       result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob);
+       if (result != errSecSuccess) {
+               secnotice("SecKeychain", "Failed to create login data: %d", (int) result);
+               return result;
+       }
+
+       secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result);
+       return result;
+}
+
+OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash)
+{
+    OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash);
+    if (result != errSecSuccess) {
+        secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result);
+    }
+    return result;
+}
+