#include "acl_keychain.h"
#include "agentquery.h"
#include "acls.h"
#include "connection.h"
#include "xdatabase.h"
#include "server.h"
#include <Security/debugging.h>
#include <algorithm>
#define ACCEPT_LEGACY_FORM 1
#define FECKLESS_KEYCHAIN_ACCESS_EXCEPTION 1
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR KeychainPromptAclSubject::defaultSelector = {
CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION, 0 };
bool KeychainPromptAclSubject::validate(const AclValidationContext &context,
const TypedList &sample) const
{
if (SecurityServerEnvironment *env = context.environment<SecurityServerEnvironment>()) {
if (context.authorization() == CSSM_ACL_AUTHORIZATION_CHANGE_ACL
&& Server::connection().aclWasSetForUpdateTrigger(env->acl)) {
secdebug("kcacl", "honoring acl update trigger for %p(%s)",
&env->acl, description.c_str());
return true;
}
const Database *db = env->database();
bool needPassphrase = db && (selector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE);
#if FECKLESS_KEYCHAIN_ACCESS_EXCEPTION
Process &process = Server::active().connection().process;
secdebug("kcacl", "Keychain query from process %d (UID %d)", process.pid(), process.uid());
if (process.clientCode())
needPassphrase |=
process.clientCode()->canonicalPath() == "/Applications/Utilities/Keychain Access.app";
#endif
QueryKeychainUse query(needPassphrase);
const char* dbName = db ? db->dbName() : NULL;
query.queryUser(db, dbName, description.c_str(), context.authorization());
if (query.continueGrantingToCaller) {
Server::connection().setAclUpdateTrigger(env->acl);
secdebug("kcacl", "setting acl update trigger for %p(%s)",
&env->acl, description.c_str());
CssmError::throwMe(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT);
}
return query.allowAccess;
}
return false; }
CssmList KeychainPromptAclSubject::toList(CssmAllocator &alloc) const
{
return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT,
new(alloc) ListElement(alloc, CssmData::wrap(selector)),
new(alloc) ListElement(alloc, description));
}
KeychainPromptAclSubject *KeychainPromptAclSubject::Maker::make(const TypedList &list) const
{
switch (list.length()) {
#if ACCEPT_LEGACY_FORM
case 2: {
ListElement *params[1];
crack(list, 1, params, CSSM_LIST_ELEMENT_DATUM);
return new KeychainPromptAclSubject(*params[0], defaultSelector);
}
#endif //ACCEPT_LEGACY_FORM
case 3: {
ListElement *params[2];
crack(list, 2, params, CSSM_LIST_ELEMENT_DATUM, CSSM_LIST_ELEMENT_DATUM);
return new KeychainPromptAclSubject(*params[1],
*params[0]->data().interpretedAs<CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR>(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE));
}
default:
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
}
}
KeychainPromptAclSubject *KeychainPromptAclSubject::Maker::make(Version version,
Reader &pub, Reader &) const
{
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR selector;
const char *description;
switch (version) {
case pumaVersion:
selector = defaultSelector;
pub(description);
break;
case jaguarVersion:
pub(selector);
selector.version = n2h (selector.version);
selector.flags = n2h (selector.flags);
pub(description);
break;
}
return new KeychainPromptAclSubject(description, selector);
}
KeychainPromptAclSubject::KeychainPromptAclSubject(string descr,
const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR &sel)
: SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT),
selector(sel), description(descr)
{
if (selector.version != CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION)
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
if (selector.flags == 0) version(pumaVersion);
else
version(jaguarVersion);
}
void KeychainPromptAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv)
{
if (version() != 0) {
selector.version = h2n (selector.version);
selector.flags = h2n (selector.flags);
pub(selector);
}
pub.insert(description.size() + 1);
}
void KeychainPromptAclSubject::exportBlob(Writer &pub, Writer &priv)
{
if (version() != 0) {
selector.version = h2n (selector.version);
selector.flags = h2n (selector.flags);
pub(selector);
}
pub(description.c_str());
}
bool KeychainPromptAclSubject::isLegacyCompatible() const
{
return selector.flags == 0;
}
#ifdef DEBUGDUMP
void KeychainPromptAclSubject::debugDump() const
{
Debug::dump("KeychainPrompt:%s(%s)",
description.c_str(),
(selector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE) ? "passphrase" : "standard");
}
#endif //DEBUGDUMP