#include <security_keychain/Access.h>
#include <Security/SecBase.h>
#include "SecBridge.h"
#include <security_utilities/devrandom.h>
#include <security_cdsa_utilities/uniformrandom.h>
#include <security_cdsa_client/aclclient.h>
#include <vector>
#include <SecBase.h>
using namespace KeychainCore;
using namespace CssmClient;
const CSSM_ACL_HANDLE Access::ownerHandle;
Access::Access() : mMutex(Mutex::recursive)
{
SecPointer<ACL> owner = new ACL(*this);
owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
addOwner(owner);
SecPointer<ACL> any = new ACL(*this);
add(any);
}
Access::Access(const string &descriptor, const ACL::ApplicationList &trusted) : mMutex(Mutex::recursive)
{
makeStandard(descriptor, trusted);
}
Access::Access(const string &descriptor) : mMutex(Mutex::recursive)
{
ACL::ApplicationList trusted;
trusted.push_back(new TrustedApplication);
makeStandard(descriptor, trusted);
}
Access::Access(const string &descriptor, const ACL::ApplicationList &trusted,
const AclAuthorizationSet &limitedRights, const AclAuthorizationSet &freeRights) : mMutex(Mutex::recursive)
{
makeStandard(descriptor, trusted, limitedRights, freeRights);
}
void Access::makeStandard(const string &descriptor, const ACL::ApplicationList &trusted,
const AclAuthorizationSet &limitedRights, const AclAuthorizationSet &freeRights)
{
StLock<Mutex>_(mMutex);
SecPointer<ACL> owner = new ACL(*this, descriptor, ACL::defaultSelector);
owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
addOwner(owner);
SecPointer<ACL> unlimited = new ACL(*this, descriptor, ACL::defaultSelector);
if (freeRights.empty()) {
unlimited->authorizations().clear();
unlimited->authorizations().insert(CSSM_ACL_AUTHORIZATION_ENCRYPT);
} else
unlimited->authorizations() = freeRights;
unlimited->form(ACL::allowAllForm);
add(unlimited);
SecPointer<ACL> limited = new ACL(*this, descriptor, ACL::defaultSelector);
if (limitedRights.empty()) {
limited->authorizations().clear();
limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_DECRYPT);
limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_SIGN);
limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_MAC);
limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_DERIVE);
limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR);
limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED);
} else
limited->authorizations() = limitedRights;
limited->applications() = trusted;
add(limited);
}
Access::Access(AclBearer &source) : mMutex(Mutex::recursive)
{
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) : mMutex(Mutex::recursive)
{
compile(owner, aclCount, acls);
}
Access::~Access()
{
}
static SecACLRef
convert(const SecPointer<ACL> &acl)
{
return *acl;
}
CFArrayRef Access::copySecACLs() const
{
return makeCFArray(convert, 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->authorizes(action))
choices.push_back(it->second);
return choices.empty() ? NULL : makeCFArray(convert, choices);
}
void Access::setAccess(AclBearer &target, bool update )
{
StLock<Mutex>_(mMutex);
AclFactory factory;
editAccess(target, update, factory.promptCred());
}
void Access::setAccess(AclBearer &target, Maker &maker)
{
StLock<Mutex>_(mMutex);
if (maker.makerType() == Maker::kStandardMakerType)
{
target.deleteAcl(Maker::creationEntryTag, maker.cred());
editAccess(target, false, maker.cred());
}
}
void Access::editAccess(AclBearer &target, bool update, const AccessCredentials *cred)
{
StLock<Mutex>_(mMutex);
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)
{
StLock<Mutex>_(mMutex);
vector<ACL *> acls;
findAclsForRight(right, acls);
if (acls.size() != 1)
MacOSError::throwMe(errSecACLNotSimple); (*acls.begin())->addApplication(app);
}
void Access::copyOwnerAndAcl(CSSM_ACL_OWNER_PROTOTYPE * &ownerResult,
uint32 &aclCount, CSSM_ACL_ENTRY_INFO * &aclsResult)
{
StLock<Mutex>_(mMutex);
Allocator& alloc = Allocator::standard();
unsigned long count = mAcls.size() - 1; AclOwnerPrototype owner;
CssmAutoPtr<AclEntryInfo> acls = new(alloc) AclEntryInfo[count];
AclEntryInfo *aclp = acls; for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) {
SecPointer<ACL> acl = it->second;
if (acl->isOwner()) {
acl->copyAclOwner(owner, alloc);
} else {
aclp->handle() = acl->entryHandle();
acl->copyAclEntry(*aclp, alloc);
++aclp;
}
}
assert((aclp - acls) == count);
ownerResult = new(alloc) AclOwnerPrototype(owner);
aclCount = (uint32)count;
aclsResult = acls.release();
}
string Access::promptDescription() const
{
for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) {
ACL *acl = it->second;
switch (acl->form()) {
case ACL::allowAllForm:
case ACL::appListForm:
{
string descr = acl->promptDescription();
if (!descr.empty())
return descr;
}
default:
break;
}
}
CssmError::throwMe(errSecACLNotSimple);
}
void Access::add(ACL *newAcl)
{
StLock<Mutex>_(mMutex);
if (&newAcl->access != this)
MacOSError::throwMe(errSecParam);
assert(!mAcls[newAcl->entryHandle()]);
mAcls[newAcl->entryHandle()] = newAcl;
}
void Access::addOwner(ACL *newAcl)
{
StLock<Mutex>_(mMutex);
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)
{
StLock<Mutex>_(mMutex);
mAcls[ownerHandle] = new ACL(*this, AclOwnerPrototype::overlay(owner));
const AclEntryInfo *acl = AclEntryInfo::overlay(acls);
for (uint32 n = 0; n < aclCount; n++) {
secdebug("SecAccess", "%p compiling entry %ld", this, acl[n].handle());
mAcls[acl[n].handle()] = new ACL(*this, acl[n]);
}
secdebug("SecAccess", "%p %ld entries compiled", this, mAcls.size());
}
const char Access::Maker::creationEntryTag[] = "___setup___";
Access::Maker::Maker(Allocator &alloc, MakerType makerType)
: allocator(alloc), mKey(alloc), mCreds(allocator), mMakerType(makerType)
{
if (makerType == kStandardMakerType)
{
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()));
}
else
{
mInput = AclEntryPrototype(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_ANY));
}
}
void Access::Maker::initialOwner(ResourceControlContext &ctx, const AccessCredentials *creds)
{
ctx.input() = mInput;
ctx.credentials(creds);
}
const AccessCredentials *Access::Maker::cred()
{
return &mCreds;
}