StorageManager.cpp [plain text]
#include "StorageManager.h"
#include "KCEventNotifier.h"
#include <Security/cssmapple.h>
#include <sys/types.h>
#include <pwd.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <algorithm>
#include <string>
#include <Security/Authorization.h>
#include <Security/AuthorizationTags.h>
#include <Security/AuthSession.h>
#include <Security/debugging.h>
#include "KCCursor.h"
#include "Globals.h"
#include "DefaultKeychain.h"
using namespace CssmClient;
using namespace KeychainCore;
StorageManager::StorageManager() :
mSavedList(),
mKeychains(),
mMultiDLDb(mSavedList.list(), true) {
}
Keychain
StorageManager::keychain(const DLDbIdentifier &dLDbIdentifier)
{
KeychainMap::iterator it = mKeychains.find(dLDbIdentifier);
if (it != mKeychains.end())
return it->second;
Keychain keychain(mMultiDLDb->database(dLDbIdentifier));
mKeychains.insert(KeychainMap::value_type(dLDbIdentifier, keychain));
return keychain;
}
Keychain
StorageManager::makeKeychain(const DLDbIdentifier &dLDbIdentifier)
{
Keychain keychain(keychain(dLDbIdentifier));
const vector<DLDbIdentifier> &list = mMultiDLDb->list();
if (find(list.begin(), list.end(), dLDbIdentifier) != list.end())
{
return keychain;
}
if (!keychain->exists())
return keychain;
mSavedList.revert(true);
mSavedList.add(dLDbIdentifier);
mSavedList.save();
mMultiDLDb->list(mSavedList.list());
KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
return keychain;
}
void
StorageManager::created(const Keychain &keychain) {
DLDbIdentifier dLDbIdentifier = keychain->dLDbIdentifier();
DefaultKeychain &defaultKeychain = globals().defaultKeychain;
if (!defaultKeychain.isSet())
defaultKeychain.dLDbIdentifier(dLDbIdentifier);
mSavedList.revert(true);
mSavedList.add(dLDbIdentifier);
mSavedList.save();
mMultiDLDb->list(mSavedList.list());
KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
}
KCCursor
StorageManager::createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList)
{
return KCCursor(DbCursor(mMultiDLDb), itemClass, attrList);
}
KCCursor
StorageManager::createCursor(const SecKeychainAttributeList *attrList)
{
return KCCursor(DbCursor(mMultiDLDb), attrList);
}
void
StorageManager::lockAll()
{
for (KeychainMap::iterator ix = mKeychains.begin(); ix != mKeychains.end(); ix++)
{
Keychain keychain(ix->second);
if (keychain->isActive())
keychain->lock();
}
}
void
StorageManager::reload(bool force)
{
if (mSavedList.revert(force))
mMultiDLDb->list(mSavedList.list());
}
size_t
StorageManager::size()
{
reload();
return mMultiDLDb->list().size();
}
Keychain
StorageManager::at(unsigned int ix)
{
reload();
if (ix >= mMultiDLDb->list().size())
MacOSError::throwMe(errSecInvalidKeychain);
return keychain(mMultiDLDb->list().at(ix));
}
Keychain
StorageManager::operator[](unsigned int ix)
{
return at(ix);
}
void StorageManager::remove(const list<SecKeychainRef>& kcsToRemove)
{
mSavedList.revert(true);
DLDbIdentifier defaultId = globals().defaultKeychain.dLDbIdentifier();
bool unsetDefault=false;
for (list<SecKeychainRef>::const_iterator ix = kcsToRemove.begin();ix!=kcsToRemove.end();ix++)
{
Keychain keychainToRemove;
try
{
keychainToRemove = KeychainRef::required(*ix);
}
catch (const MacOSError& err)
{
if (err.osStatus() == errSecInvalidKeychain)
continue;
throw;
}
mSavedList.remove(keychainToRemove->dLDbIdentifier());
if (keychainToRemove->dLDbIdentifier() == defaultId)
unsetDefault=true;
KeychainMap::iterator it = mKeychains.find(keychainToRemove->dLDbIdentifier());
if (it==mKeychains.end())
continue;
mKeychains.erase(it);
}
mSavedList.save();
mMultiDLDb->list(mSavedList.list());
KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
if (unsetDefault)
globals().defaultKeychain.unset();
}
void StorageManager::replace(const list<SecKeychainRef>& newKCList)
{
CssmClient::DLDbList dldbList;
convert(newKCList,dldbList);
}
void StorageManager::convert(const list<SecKeychainRef>& SecKeychainRefList,CssmClient::DLDbList& dldbList)
{
dldbList.clear(); for (list<SecKeychainRef>::const_iterator ix = SecKeychainRefList.begin();ix!=SecKeychainRefList.end();ix++)
{
Keychain keychain;
try
{
keychain = KeychainRef::required(*ix);
}
catch (const MacOSError& err)
{
if (err.osStatus() == errSecInvalidKeychain)
continue;
throw;
}
dldbList.push_back(keychain->dLDbIdentifier());
}
}
#pragma mark ΡΡΡΡ Login Functions ΡΡΡΡ
void StorageManager::login(ConstStringPtr name, ConstStringPtr password)
{
if ( name == NULL || password == NULL )
MacOSError::throwMe(paramErr);
login(name[0], name + 1, password[0], password + 1);
}
void StorageManager::login(UInt32 nameLength, const void *name, UInt32 passwordLength, const void *password)
{
debug("KClogin", "setting up login session");
if (OSStatus ssnErr = SessionCreate(sessionKeepCurrentBootstrap,
sessionHasGraphicAccess | sessionHasTTY))
debug("KClogin", "session setup failed status=%ld", ssnErr);
if (name == NULL || (passwordLength != 0 && password == NULL))
MacOSError::throwMe(paramErr);
string theName(reinterpret_cast<const char *>(name), nameLength);
Keychain keychain = make(theName.c_str());
try
{
keychain->unlock(CssmData(const_cast<void *>(password), passwordLength));
debug("KClogin", "keychain unlock successful");
}
catch(const CssmError &e)
{
if (e.osStatus() != CSSMERR_DL_DATASTORE_DOESNOT_EXIST)
throw;
debug("KClogin", "creating login keychain");
keychain->create(passwordLength, password);
keychain->setSettings(INT_MAX, false);
}
debug("KClogin", "creating login authorization");
const AuthorizationItem envList[] =
{
{ kAuthorizationEnvironmentUsername, nameLength, const_cast<void *>(name), 0 },
{ kAuthorizationEnvironmentPassword, passwordLength, const_cast<void *>(password), 0 },
{ kAuthorizationEnvironmentShared, 0, NULL, 0 }
};
const AuthorizationEnvironment environment =
{
sizeof(envList) / sizeof(*envList),
const_cast<AuthorizationItem *>(envList)
};
if (OSStatus authErr = AuthorizationCreate(NULL, &environment,
kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize, NULL))
debug("KClogin", "failed to create login auth, status=%ld", authErr);
}
void StorageManager::logout()
{
}
void StorageManager::changeLoginPassword(ConstStringPtr oldPassword, ConstStringPtr newPassword)
{
globals().defaultKeychain.keychain()->changePassphrase(oldPassword, newPassword);
}
void StorageManager::changeLoginPassword(UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword)
{
globals().defaultKeychain.keychain()->changePassphrase(oldPasswordLength, oldPassword, newPasswordLength, newPassword);
}
#pragma mark ΡΡΡΡ File Related ΡΡΡΡ
Keychain StorageManager::make(const char *pathName)
{
string fullPathName;
if ( pathName[0] == '/' )
fullPathName = pathName;
else
{
const char *homeDir = getenv("HOME");
if (homeDir == NULL)
{
struct passwd *pw = getpwuid(getuid());
if (!pw)
MacOSError::throwMe(paramErr);
homeDir = pw->pw_dir;
}
fullPathName = homeDir;
fullPathName += "/Library/Keychains/";
fullPathName += pathName;
}
const CSSM_NET_ADDRESS *DbLocation = NULL; 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 );
}
KeychainSchema
StorageManager::keychainSchemaFor(const CssmClient::Db &db)
{
KeychainSchema schema(db);
pair<KeychainSchemaSet::iterator, bool> result = mKeychainSchemaSet.insert(db);
if (result.second)
return schema;
return *result.first;
}