#include <Security/Access.h>
#include <Security/SecBase.h>
#include "SecBridge.h"
#include <Security/devrandom.h>
#include <Security/uniformrandom.h>
#include <vector>
using namespace KeychainCore;
Access::Access(const string &descriptor, const ACL::ApplicationList &trusted)
{
makeStandard(descriptor, trusted);
}
Access::Access(const string &descriptor)
{
ACL::ApplicationList trusted;
trusted.push_back(new TrustedApplication);
makeStandard(descriptor, trusted);
}
void Access::makeStandard(const string &descriptor, const ACL::ApplicationList &trusted)
{
RefPointer<ACL> owner = new ACL(*this, descriptor, ACL::defaultSelector);
owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
addOwner(owner);
RefPointer<ACL> encrypt = new ACL(*this, descriptor, ACL::defaultSelector);
encrypt->setAuthorization(CSSM_ACL_AUTHORIZATION_ENCRYPT);
encrypt->form(ACL::allowAllForm);
add(encrypt);
RefPointer<ACL> decrypt = new ACL(*this, descriptor, ACL::defaultSelector);
decrypt->setAuthorization(CSSM_ACL_AUTHORIZATION_DECRYPT);
decrypt->applications() = trusted;
add(decrypt);
}
Access::Access(AclBearer &source)
{
AutoAclOwnerPrototype owner;
source.getOwner(owner);
AutoAclEntryInfoList acls;
source.getAcl(acls);
compile(*owner, acls.count(), acls.entries());
}
Access::Access(const CSSM_ACL_OWNER_PROTOTYPE &owner,
uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls)
{
compile(owner, aclCount, acls);
}
Access::~Access()
{
}
CFArrayRef Access::copySecACLs() const
{
return makeCFArray(gTypes().acl, mAcls);
}
CFArrayRef Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action) const
{
list<ACL *> choices;
for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++)
if (it->second->authorizations().find(action) != it->second->authorizations().end())
choices.push_back(it->second);
return choices.empty() ? NULL : makeCFArray(gTypes().acl, choices);
}
void Access::setAccess(AclBearer &target, bool update = false)
{
AclFactory factory;
editAccess(target, update, factory.promptCred());
}
void Access::setAccess(AclBearer &target, Maker &maker)
{
target.deleteAcl(Maker::creationEntryTag, maker.cred());
editAccess(target, false, maker.cred());
}
void Access::editAccess(AclBearer &target, bool update, const AccessCredentials *cred)
{
assert(mAcls[ownerHandle]);
for (Map::iterator it = mAcls.begin(); it != mAcls.end(); it++)
if (!it->second->isOwner())
it->second->setAccess(target, update, cred);
mAcls[ownerHandle]->setAccess(target, update, cred);
}
void Access::addApplicationToRight(AclAuthorization right, TrustedApplication *app)
{
vector<ACL *> acls;
findAclsForRight(right, acls);
if (acls.size() != 1)
MacOSError::throwMe(errSecACLNotSimple); (*acls.begin())->addApplication(app);
}
void Access::add(ACL *newAcl)
{
if (&newAcl->access != this)
MacOSError::throwMe(paramErr);
assert(!mAcls[newAcl->entryHandle()]);
mAcls[newAcl->entryHandle()] = newAcl;
}
void Access::addOwner(ACL *newAcl)
{
newAcl->makeOwner();
assert(mAcls.find(ownerHandle) == mAcls.end()); add(newAcl);
}
void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE &owner,
uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls)
{
mAcls[ownerHandle] = new ACL(*this, AclOwnerPrototype::overlay(owner));
const AclEntryInfo *acl = AclEntryInfo::overlay(acls);
for (uint32 n = 0; n < aclCount; n++) {
debug("SecAccess", "%p compiling entry %ld", this, acl[n].handle());
mAcls[acl[n].handle()] = new ACL(*this, acl[n]);
}
debug("SecAccess", "%p %ld entries compiled", this, mAcls.size());
}
const char Access::Maker::creationEntryTag[] = "___setup___";
Access::Maker::Maker(CssmAllocator &alloc)
: allocator(alloc), mKey(alloc), mCreds(allocator)
{
mKey.malloc(keySize);
UniformRandomBlobs<DevRandomGenerator>().random(mKey.get());
mInput = AclEntryPrototype(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
new(allocator) ListElement(mKey.get())));
mInput.proto().tag(creationEntryTag);
mCreds += TypedList(allocator, CSSM_SAMPLE_TYPE_PASSWORD, new(allocator) ListElement(mKey.get()));
}
void Access::Maker::initialOwner(ResourceControlContext &ctx, const AccessCredentials *creds)
{
ctx.input() = mInput;
ctx.credentials(creds);
}
const AccessCredentials *Access::Maker::cred()
{
return &mCreds;
}