#include "tokenacl.h"
#include "tokend.h"
#include "token.h"
#include "tokendatabase.h"
#include "agentquery.h"
#include <security_utilities/trackingallocator.h>
#include <security_cdsa_utilities/cssmbridge.h>
TokenAcl::TokenAcl()
: mLastReset(0)
{
}
void TokenAcl::instantiateAcl()
{
if (token().resetGeneration(mLastReset))
return;
secinfo("tokenacl", "%p loading ACLs from tokend", this);
AclOwnerPrototype *owner = NULL;
token().tokend().getOwner(aclKind(), tokenHandle(), owner);
assert(owner);
uint32 count;
AclEntryInfo *infos;
token().tokend().getAcl(aclKind(), tokenHandle(), NULL, count, infos);
ObjectAcl::owner(*owner);
ObjectAcl::entries(count, infos);
mLastReset = token().resetGeneration();
}
void TokenAcl::changedAcl()
{
}
void TokenAcl::getOwner(AclOwnerPrototype &owner)
{
ObjectAcl::cssmGetOwner(owner);
}
void TokenAcl::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls)
{
ObjectAcl::cssmGetAcl(tag, count, acls);
}
void TokenAcl::changeAcl(const AclEdit &edit, const AccessCredentials *cred, Database *db)
{
instantiateAcl(); if (TokenDatabase *tokenDb = dynamic_cast<TokenDatabase *>(db))
if (edit.mode() == CSSM_ACL_EDIT_MODE_REPLACE)
if (const AclEntryInput *input = edit.newEntry()) {
if (unsigned pin = pinFromAclTag(input->proto().tag())) {
pinChange(pin, edit.handle(), *tokenDb);
invalidateAcl();
return;
}
}
token().tokend().changeAcl(aclKind(), tokenHandle(), Required(cred), edit);
invalidateAcl();
}
void TokenAcl::changeOwner(const AclOwnerPrototype &newOwner,
const AccessCredentials *cred, Database *db)
{
token().tokend().changeOwner(aclKind(), tokenHandle(), Required(cred), newOwner);
invalidateAcl();
}
class QueryNewPin : public QueryNewPassphrase {
public:
QueryNewPin(unsigned int pinn, CSSM_ACL_HANDLE h, TokenDatabase &db, Reason reason)
: QueryNewPassphrase(db, reason), pin(pinn), handle(h) { }
const unsigned int pin;
const CSSM_ACL_HANDLE handle;
Reason accept(CssmManagedData &passphrase, CssmData *oldPassphrase);
};
SecurityAgent::Reason QueryNewPin::accept(CssmManagedData &passphrase, CssmData *oldPassphrase)
{
assert(oldPassphrase);
try {
TrackingAllocator alloc(Allocator::standard());
AclEntryPrototype proto(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD,
new(alloc) ListElement(passphrase)
));
proto.authorization() = AuthorizationGroup(CSSM_ACL_AUTHORIZATION_PREAUTH(pin), alloc);
char pintag[20]; sprintf(pintag, "PIN%d", pin);
proto.tag(pintag);
AclEntryInput input(proto);
AclEdit edit(CSSM_ACL_EDIT_MODE_REPLACE, handle, &input);
AutoCredentials cred(alloc);
cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
new(alloc) ListElement(*oldPassphrase));
safer_cast<TokenDatabase &>(database).token().tokend().changeAcl(dbAcl, noDb, cred, edit);
return SecurityAgent::noReason;
} catch (const CssmError &err) {
switch (err.error) {
default:
return SecurityAgent::unknownReason;
}
} catch (...) {
return SecurityAgent::unknownReason;
}
}
void TokenAcl::pinChange(unsigned int pin, CSSM_ACL_HANDLE handle, TokenDatabase &database)
{
QueryNewPin query(pin, handle, database, SecurityAgent::changePassphrase);
query.inferHints(Server::process());
CssmAutoData newPin(Allocator::standard(Allocator::sensitive));
CssmAutoData oldPin(Allocator::standard(Allocator::sensitive));
switch (query(oldPin, newPin)) {
case SecurityAgent::noReason: return;
default:
CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
}
}