#include "agentquery.h"
#include "authority.h"
#include "server.h"
#include "session.h"
using namespace SecurityAgent;
const char SecurityAgentQuery::defaultName[] = "com.apple.SecurityAgent";
SecurityAgentQuery::SecurityAgentQuery() :
SecurityAgent::Client(Server::active().connection().process.uid(),
Server::active().connection().process.session.bootstrapPort(),
defaultName),
mClientSession(Server::active().connection().process.session)
{
}
SecurityAgentQuery::SecurityAgentQuery(uid_t clientUID,
Session &clientSession,
const char *agentName) :
SecurityAgent::Client(clientUID, clientSession.bootstrapPort(), agentName),
mClientSession(clientSession)
{
}
SecurityAgentQuery::~SecurityAgentQuery()
{
terminate();
}
void
SecurityAgentQuery::activate()
{
if (isActive())
return;
if (!(mClientSession.attributes() & sessionHasGraphicAccess))
CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
Server::active().longTermActivity();
Server::connection().useAgent(this);
try {
SecurityAgent::Client::activate();
} catch (...) {
Server::connection().useAgent(NULL); throw;
}
}
void
SecurityAgentQuery::terminate()
{
if (!isActive())
return;
Server::connection(true).useAgent(NULL);
SecurityAgent::Client::terminate();
}
void QueryKeychainUse::queryUser (const Database *db, const char *database, const char *description,
AclAuthorization action)
{
Reason reason;
int retryCount = 0;
queryKeychainAccess(Server::connection().process.clientCode(),
Server::connection().process.pid(),
database, description, action, needPassphrase, *this);
CssmData data (passphrase, strlen (passphrase));
if (needPassphrase) {
while (reason = (const_cast<Database*>(db)->decode(data) ? noReason : invalidPassphrase)) {
if (++retryCount > kMaximumAuthorizationTries) {
cancelStagedQuery(tooManyTries);
return;
}
else {
retryQueryKeychainAccess (reason, *this);
data = CssmData (passphrase, strlen (passphrase));
}
}
finishStagedQuery (); }
}
QueryKeychainUse::~QueryKeychainUse()
{
memset(passphrase, 0, sizeof(passphrase));
}
void QueryCodeCheck::operator () (const char *aclPath)
{
queryCodeIdentity(Server::connection().process.clientCode(),
Server::connection().process.pid(), aclPath, *this);
}
Reason QueryUnlock::query()
{
CssmAutoData passphrase(CssmAllocator::standard(CssmAllocator::sensitive));
int retryCount = 0;
queryInteractive(passphrase);
while (Reason reason = accept(passphrase)) {
if (++retryCount > maxTries) {
cancelStagedQuery(tooManyTries);
return reason;
} else {
retryInteractive(passphrase, reason);
}
}
finishStagedQuery();
return noReason;
}
Reason QueryUnlock::operator () ()
{
return query();
}
Reason QueryUnlock::accept(CssmManagedData &passphrase)
{
return database.decode(passphrase) ? noReason : invalidPassphrase;
}
void QueryUnlock::queryInteractive(CssmOwnedData &passphrase)
{
char passString[maxPassphraseLength];
queryUnlockDatabase(Server::connection().process.clientCode(),
Server::connection().process.pid(),
database.dbName(), passString);
passphrase.copy(passString, strlen(passString));
}
void QueryUnlock::retryInteractive(CssmOwnedData &passphrase, Reason reason)
{
char passString[maxPassphraseLength];
retryUnlockDatabase(reason, passString);
passphrase.copy(passString, strlen(passString));
}
Reason QueryNewPassphrase::query()
{
CssmAutoData passphrase(CssmAllocator::standard(CssmAllocator::sensitive));
CssmAutoData oldPassphrase(CssmAllocator::standard(CssmAllocator::sensitive));
int retryCount = 0;
queryInteractive(passphrase, oldPassphrase);
while (Reason reason = accept(passphrase,
(initialReason == changePassphrase) ? &oldPassphrase.get() : NULL)) {
if (++retryCount > maxTries) {
cancelStagedQuery(tooManyTries);
return reason;
} else {
retryInteractive(passphrase, oldPassphrase, reason);
}
}
finishStagedQuery();
return noReason;
}
Reason QueryNewPassphrase::operator () (CssmOwnedData &passphrase)
{
if (Reason result = query())
return result; passphrase = mPassphrase;
return noReason; }
Reason QueryNewPassphrase::accept(CssmManagedData &passphrase, CssmData *oldPassphrase)
{
if (oldPassphrase && !database.validatePassphrase(*oldPassphrase))
return oldPassphraseWrong;
if (!(mPassphraseValid && passphrase.get() == mPassphrase)) {
mPassphrase = passphrase;
mPassphraseValid = true;
if (mPassphrase.length() == 0)
return passphraseIsNull;
if (mPassphrase.length() < 6)
return passphraseTooSimple;
}
return noReason;
}
void QueryNewPassphrase::queryInteractive(CssmOwnedData &passphrase, CssmOwnedData &oldPassphrase)
{
char passString[maxPassphraseLength], oldPassString[maxPassphraseLength];
queryNewPassphrase(Server::connection().process.clientCode(),
Server::connection().process.pid(),
database.dbName(), initialReason, passString, oldPassString);
passphrase.copy(passString, strlen(passString));
oldPassphrase.copy(oldPassString, strlen(oldPassString));
}
void QueryNewPassphrase::retryInteractive(CssmOwnedData &passphrase, CssmOwnedData &oldPassphrase, Reason reason)
{
char passString[maxPassphraseLength], oldPassString[maxPassphraseLength];
retryNewPassphrase(reason, passString, oldPassString);
passphrase.copy(passString, strlen(passString));
oldPassphrase.copy(oldPassString, strlen(oldPassString));
}
QueryAuthorizeByGroup::QueryAuthorizeByGroup(uid_t clientUID, const AuthorizationToken &auth) :
SecurityAgentQuery(Server::active().connection().process.uid(), auth.session),
authorization(auth), mActive(false) { }
void QueryAuthorizeByGroup::cancel(Reason reason)
{
if (mActive) {
cancelStagedQuery(reason);
mActive = false;
}
}
void QueryAuthorizeByGroup::done()
{
if (mActive) {
finishStagedQuery();
mActive = false;
}
}
uid_t QueryAuthorizeByGroup::uid()
{
return Server::connection().process.uid();
}
bool QueryAuthorizeByGroup::operator () (const char *group, const char *candidateUser,
char username[maxUsernameLength], char passphrase[maxPassphraseLength], Reason reason)
{
if (mActive) {
return retryAuthorizationAuthenticate(reason, username, passphrase);
} else {
bool result = authorizationAuthenticate(authorization.creatorCode(),
Server::connection().process.pid(), group, candidateUser, username, passphrase);
mActive = true;
return result;
}
}
QueryInvokeMechanism::QueryInvokeMechanism(uid_t clientUID, const AuthorizationToken &auth, const char *agentName) :
SecurityAgentQuery(clientUID, auth.session, agentName) {}
bool QueryInvokeMechanism::operator () (const string &inPluginId, const string &inMechanismId, const AuthValueVector &inArguments, AuthItemSet &inHints, AuthItemSet &inContext, AuthorizationResult *outResult)
{
bool result = invokeMechanism(inPluginId, inMechanismId, inArguments, inHints, inContext, outResult);
return result;
}
void QueryInvokeMechanism::terminateAgent()
{
SecurityAgentQuery::terminateAgent();
}