#include "agentquery.h"
#include "authority.h"
#include "ccaudit_extensions.h"
#include <Security/AuthorizationTags.h>
#include <Security/AuthorizationTagsPriv.h>
#include <Security/checkpw.h>
#include <System/sys/fileport.h>
#include <bsm/audit.h>
#include <bsm/audit_uevents.h> // AUE_ssauthint
#include <security_utilities/logging.h>
#include <security_utilities/mach++.h>
#include <stdlib.h>
#if defined(NOSA)
#include <cstdarg>
static void getNoSA(char *buffer, size_t bufferSize, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stdout, fmt, args);
va_end(args);
memset(buffer, 0, bufferSize);
const char *nosa = getenv("NOSA");
if (!strcmp(nosa, "-")) {
if (fgets(buffer, bufferSize-1, stdin) == NULL)
CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
buffer[strlen(buffer)-1] = '\0'; if (!isatty(fileno(stdin)))
printf("%s\n", buffer); } else {
strncpy(buffer, nosa, bufferSize-1);
printf("%s\n", buffer);
}
if (buffer[0] == '\0') CssmError::throwMe(CSSM_ERRCODE_USER_CANCELED);
}
#endif //NOSA
SecurityAgentConnection::SecurityAgentConnection(const AuthHostType type, Session &session)
: mAuthHostType(type),
mHostInstance(session.authhost(mAuthHostType)),
mConnection(&Server::connection()),
mAuditToken(Server::connection().auditToken())
{
Server::active().longTermActivity();
secdebug("SecurityAgentConnection", "new SecurityAgentConnection(%p)", this);
}
SecurityAgentConnection::~SecurityAgentConnection()
{
secdebug("SecurityAgentConnection", "SecurityAgentConnection(%p) dying", this);
mConnection->useAgent(NULL);
}
void
SecurityAgentConnection::activate()
{
secdebug("SecurityAgentConnection", "activate(%p)", this);
Session &session = mHostInstance->session();
SessionId targetSessionId = session.sessionId();
MachPlusPlus::Bootstrap processBootstrap = Server::process().taskPort().bootstrap();
fileport_t userPrefsFP = MACH_PORT_NULL;
if (mAuthHostType == securityAgent || mAuthHostType == userAuthHost) {
CFRef<CFDataRef> userPrefs(mHostInstance->session().copyUserPrefs());
if (NULL != userPrefs)
{
FILE *mbox = NULL;
int fd = 0;
mbox = tmpfile();
if (NULL != mbox)
{
fd = dup(fileno(mbox));
fclose(mbox);
if (fd != -1)
{
CFIndex length = CFDataGetLength(userPrefs);
if (write(fd, CFDataGetBytePtr(userPrefs), length) != length)
Syslog::error("could not write userPrefs");
else
{
if (0 == fileport_makeport(fd, &userPrefsFP))
secdebug("SecurityAgentConnection", "stashed the userPrefs file descriptor");
else
Syslog::error("failed to stash the userPrefs file descriptor");
}
close(fd);
}
}
}
if (MACH_PORT_NULL == userPrefsFP)
{
secdebug("SecurityAgentConnection", "could not read userPrefs");
}
}
mConnection->useAgent(this);
try
{
StLock<Mutex> _(*mHostInstance);
mach_port_t lookupPort = mHostInstance->lookup(targetSessionId);
if (MACH_PORT_NULL == lookupPort)
{
Syslog::error("could not find real service, bailing");
MacOSError::throwMe(CSSM_ERRCODE_SERVICE_NOT_AVAILABLE);
}
mPort = lookupPort;
SecurityAgent::Client::activate(mPort);
secdebug("SecurityAgentConnection", "%p activated", this);
}
catch (MacOSError &err)
{
mConnection->useAgent(NULL); Syslog::error("SecurityAgentConnection: error activating %s instance %p",
mAuthHostType == privilegedAuthHost
? "authorizationhost"
: "SecurityAgent", this);
throw;
}
secdebug("SecurityAgentConnection", "contacting service (%p)", this);
mach_port_name_t jobPort;
if (0 > audit_session_port(session.sessionId(), &jobPort))
Syslog::error("audit_session_port failed: %m");
MacOSError::check(SecurityAgent::Client::contact(jobPort, processBootstrap, userPrefsFP));
secdebug("SecurityAgentConnection", "contact didn't throw (%p)", this);
if (userPrefsFP != MACH_PORT_NULL)
mach_port_deallocate(mach_task_self(), userPrefsFP);
}
void
SecurityAgentConnection::reconnect()
{
if (mHostInstance)
{
activate();
}
}
void
SecurityAgentConnection::terminate()
{
activate();
mConnection->useAgent(NULL);
}
SecurityAgentTransaction::SecurityAgentTransaction(const AuthHostType type, Session &session, bool startNow)
: SecurityAgentConnection(type, session),
mStarted(false)
{
secdebug("SecurityAgentTransaction", "New SecurityAgentTransaction(%p)", this);
activate(); if (startNow)
start();
}
SecurityAgentTransaction::~SecurityAgentTransaction()
{
try { end(); } catch(...) {}
secdebug("SecurityAgentTransaction", "Destroying %p", this);
}
void
SecurityAgentTransaction::start()
{
secdebug("SecurityAgentTransaction", "start(%p)", this);
MacOSError::check(SecurityAgentQuery::Client::startTransaction(mPort));
mStarted = true;
secdebug("SecurityAgentTransaction", "started(%p)", this);
}
void
SecurityAgentTransaction::end()
{
if (started())
{
MacOSError::check(SecurityAgentQuery::Client::endTransaction(mPort));
mStarted = false;
}
secdebug("SecurityAgentTransaction", "End SecurityAgentTransaction(%p)", this);
}
using SecurityAgent::Reason;
using namespace Authorization;
SecurityAgentQuery::SecurityAgentQuery(const AuthHostType type, Session &session)
: SecurityAgentConnection(type, session)
{
secdebug("SecurityAgentQuery", "new SecurityAgentQuery(%p)", this);
}
SecurityAgentQuery::~SecurityAgentQuery()
{
secdebug("SecurityAgentQuery", "SecurityAgentQuery(%p) dying", this);
#if defined(NOSA)
if (getenv("NOSA")) {
printf(" [query done]\n");
return;
}
#endif
if (SecurityAgent::Client::state() != SecurityAgent::Client::dead)
destroy();
}
void
SecurityAgentQuery::inferHints(Process &thisProcess)
{
string guestPath;
if (SecCodeRef clientCode = thisProcess.currentGuest())
guestPath = codePath(clientCode);
AuthItemSet processHints = clientHints(SecurityAgent::bundle, guestPath,
thisProcess.pid(), thisProcess.uid());
mClientHints.insert(processHints.begin(), processHints.end());
}
void SecurityAgentQuery::addHint(const char *name, const void *value, UInt32 valueLen, UInt32 flags)
{
AuthorizationItem item = { name, valueLen, const_cast<void *>(value), flags };
mClientHints.insert(AuthItemRef(item));
}
void
SecurityAgentQuery::readChoice()
{
allow = false;
remember = false;
AuthItem *allowAction = outContext().find(AGENT_CONTEXT_ALLOW);
if (allowAction)
{
string allowString;
if (allowAction->getString(allowString)
&& (allowString == "YES"))
allow = true;
}
AuthItem *rememberAction = outContext().find(AGENT_CONTEXT_REMEMBER_ACTION);
if (rememberAction)
{
string rememberString;
if (rememberAction->getString(rememberString)
&& (rememberString == "YES"))
remember = true;
}
}
void
SecurityAgentQuery::disconnect()
{
SecurityAgent::Client::destroy();
}
void
SecurityAgentQuery::terminate()
{
SecurityAgentConnection::terminate();
SecurityAgent::Client::terminate();
}
void
SecurityAgentQuery::create(const char *pluginId, const char *mechanismId, const SessionId inSessionId)
{
activate();
OSStatus status = SecurityAgent::Client::create(pluginId, mechanismId, inSessionId);
if (status)
{
secdebug("SecurityAgentQuery", "agent went walkabout, restarting");
reconnect();
status = SecurityAgent::Client::create(pluginId, mechanismId, inSessionId);
}
if (status) MacOSError::throwMe(status);
}
QueryKeychainUse::QueryKeychainUse(bool needPass, const Database *db)
: mPassphraseCheck(NULL)
{
if (needPass)
mPassphraseCheck = dynamic_cast<const KeychainDatabase *>(db);
}
Reason QueryKeychainUse::queryUser (const char *database, const char *description, AclAuthorization action)
{
Reason reason = SecurityAgent::noReason;
int retryCount = 0;
OSStatus status;
AuthValueVector arguments;
AuthItemSet hints, context;
#if defined(NOSA)
if (getenv("NOSA")) {
char answer[maxPassphraseLength+10];
string applicationPath;
AuthItem *applicationPathItem = mClientHints.find(AGENT_HINT_APPLICATION_PATH);
if (applicationPathItem)
applicationPathItem->getString(applicationPath);
getNoSA(answer, sizeof(answer), "Allow %s to do %d on %s in %s? [yn][g]%s ",
applicationPath.c_str(), int(action), (description ? description : "[NULL item]"),
(database ? database : "[NULL database]"),
mPassphraseCheck ? ":passphrase" : "");
if (mPassphraseCheck && !strchr(answer, ':')) {
memmove(answer+2, answer, strlen(answer)+1);
memcpy(answer, "y:", 2);
}
allow = answer[0] == 'y';
remember = answer[1] == 'g';
return SecurityAgent::noReason;
}
#endif
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_ACL_TAG, AuthValueOverlay(sizeof(action), static_cast<sint32*>(&action))));
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_ITEM_NAME, AuthValueOverlay(description ? strlen(description) : 0, const_cast<char*>(description))));
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(database ? strlen(database) : 0, const_cast<char*>(database))));
if (mPassphraseCheck)
{
create("builtin", "confirm-access-password", noSecuritySession);
CssmAutoData data(Allocator::standard(Allocator::sensitive));
do
{
AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount));
hints.erase(triesHint); hints.insert(triesHint);
if (retryCount++ > kMaximumAuthorizationTries)
{
reason = SecurityAgent::tooManyTries;
}
AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
hints.erase(retryHint); hints.insert(retryHint);
setInput(hints, context);
status = invoke();
if (retryCount > kMaximumAuthorizationTries)
{
return reason;
}
checkResult();
AuthItem *passwordItem = outContext().find(kAuthorizationEnvironmentPassword);
if (!passwordItem)
continue;
passwordItem->getCssmData(data);
}
while (reason = (const_cast<KeychainDatabase*>(mPassphraseCheck)->decode(data) ? SecurityAgent::noReason : SecurityAgent::invalidPassphrase));
}
else
{
create("builtin", "confirm-access", noSecuritySession);
setInput(hints, context);
invoke();
}
readChoice();
return reason;
}
bool QueryCodeCheck::operator () (const char *aclPath)
{
OSStatus status;
AuthValueVector arguments;
AuthItemSet hints, context;
#if defined(NOSA)
if (getenv("NOSA")) {
char answer[10];
string applicationPath;
AuthItem *applicationPathItem = mClientHints.find(AGENT_HINT_APPLICATION_PATH);
if (applicationPathItem)
applicationPathItem->getString(applicationPath);
getNoSA(answer, sizeof(answer),
"Allow %s to match an ACL for %s [yn][g]? ",
applicationPath.c_str(), aclPath ? aclPath : "(unknown)");
allow = answer[0] == 'y';
remember = answer[1] == 'g';
return;
}
#endif
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_APPLICATION_PATH, AuthValueOverlay(strlen(aclPath), const_cast<char*>(aclPath))));
create("builtin", "code-identity", noSecuritySession);
setInput(hints, context);
status = invoke();
checkResult();
return kAuthorizationResultAllow == result();
}
Reason QueryOld::query()
{
Reason reason = SecurityAgent::noReason;
OSStatus status;
AuthValueVector arguments;
AuthItemSet hints, context;
CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
int retryCount = 0;
#if defined(NOSA)
if (getenv("NOSA")) {
char passphrase_[maxPassphraseLength];
getNoSA(passphrase, maxPassphraseLength, "Unlock %s [<CR> to cancel]: ", database.dbName());
passphrase.copy(passphrase_, strlen(passphrase_));
return database.decode(passphrase) ? SecurityAgent::noReason : SecurityAgent::invalidPassphrase;
}
#endif
const char *keychainPath = database.dbName();
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(strlen(keychainPath), const_cast<char*>(keychainPath))));
hints.insert(mClientHints.begin(), mClientHints.end());
create("builtin", "unlock-keychain", noSecuritySession);
do
{
AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount));
hints.erase(triesHint); hints.insert(triesHint);
++retryCount;
if (retryCount > maxTries)
{
reason = SecurityAgent::tooManyTries;
}
AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
hints.erase(retryHint); hints.insert(retryHint);
setInput(hints, context);
status = invoke();
if (retryCount > maxTries)
{
return reason;
}
checkResult();
AuthItem *passwordItem = outContext().find(kAuthorizationEnvironmentPassword);
if (!passwordItem)
continue;
passwordItem->getCssmData(passphrase);
}
while (reason = accept(passphrase));
return SecurityAgent::noReason;
}
Reason QueryOld::operator () ()
{
return query();
}
Reason QueryUnlock::accept(CssmManagedData &passphrase)
{
if (safer_cast<KeychainDatabase &>(database).decode(passphrase))
return SecurityAgent::noReason;
else
return SecurityAgent::invalidPassphrase;
}
QueryPIN::QueryPIN(Database &db)
: QueryOld(db), mPin(Allocator::standard())
{
this->inferHints(Server::process());
}
Reason QueryPIN::accept(CssmManagedData &pin)
{
mPin = pin;
return SecurityAgent::noReason;
}
Reason QueryNewPassphrase::query()
{
Reason reason = initialReason;
CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
OSStatus status;
AuthValueVector arguments;
AuthItemSet hints, context;
int retryCount = 0;
#if defined(NOSA)
if (getenv("NOSA")) {
char passphrase_[maxPassphraseLength];
getNoSA(passphrase_, maxPassphraseLength,
"New passphrase for %s (reason %d) [<CR> to cancel]: ",
database.dbName(), reason);
return SecurityAgent::noReason;
}
#endif
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(database.dbName())));
switch (initialReason)
{
case SecurityAgent::newDatabase:
create("builtin", "new-passphrase", noSecuritySession);
break;
case SecurityAgent::changePassphrase:
create("builtin", "change-passphrase", noSecuritySession);
break;
default:
assert(false);
}
do
{
AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount));
hints.erase(triesHint); hints.insert(triesHint);
if (++retryCount > maxTries)
{
reason = SecurityAgent::tooManyTries;
}
AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
hints.erase(retryHint); hints.insert(retryHint);
setInput(hints, context);
status = invoke();
if (retryCount > maxTries)
{
return reason;
}
checkResult();
if (SecurityAgent::changePassphrase == initialReason)
{
AuthItem *oldPasswordItem = outContext().find(AGENT_PASSWORD);
if (!oldPasswordItem)
continue;
oldPasswordItem->getCssmData(oldPassphrase);
}
AuthItem *passwordItem = outContext().find(AGENT_CONTEXT_NEW_PASSWORD);
if (!passwordItem)
continue;
passwordItem->getCssmData(passphrase);
}
while (reason = accept(passphrase, (initialReason == SecurityAgent::changePassphrase) ? &oldPassphrase.get() : NULL));
return SecurityAgent::noReason;
}
Reason QueryNewPassphrase::operator () (CssmOwnedData &passphrase)
{
if (Reason result = query())
return result; passphrase = mPassphrase;
return SecurityAgent::noReason; }
Reason QueryNewPassphrase::accept(CssmManagedData &passphrase, CssmData *oldPassphrase)
{
if (oldPassphrase && !safer_cast<KeychainDatabase&>(database).validatePassphrase(*oldPassphrase))
return SecurityAgent::oldPassphraseWrong;
if (!(mPassphraseValid && passphrase.get() == mPassphrase)) {
mPassphrase = passphrase;
mPassphraseValid = true;
if (mPassphrase.length() == 0)
return SecurityAgent::passphraseIsNull;
if (mPassphrase.length() < 6)
return SecurityAgent::passphraseTooSimple;
}
return SecurityAgent::noReason;
}
Reason QueryGenericPassphrase::operator () (const char *prompt, bool verify,
string &passphrase)
{
return query(prompt, verify, passphrase);
}
Reason QueryGenericPassphrase::query(const char *prompt, bool verify,
string &passphrase)
{
Reason reason = SecurityAgent::noReason;
OSStatus status; AuthValueVector arguments;
AuthItemSet hints, context;
#if defined(NOSA)
if (getenv("NOSA")) {
return SecurityAgent::noReason;
}
#endif
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_CUSTOM_PROMPT, AuthValueOverlay(prompt ? strlen(prompt) : 0, const_cast<char*>(prompt))));
if (false == verify) { create("builtin", "generic-unlock", noSecuritySession);
} else { create("builtin", "generic-new-passphrase", noSecuritySession);
}
AuthItem *passwordItem;
do {
setInput(hints, context);
status = invoke();
checkResult();
passwordItem = outContext().find(AGENT_PASSWORD);
} while (!passwordItem);
passwordItem->getString(passphrase);
return reason;
}
Reason QueryDBBlobSecret::operator () (DbHandle *dbHandleArray, uint8 dbHandleArrayCount, DbHandle *dbHandleAuthenticated)
{
return query(dbHandleArray, dbHandleArrayCount, dbHandleAuthenticated);
}
Reason QueryDBBlobSecret::query(DbHandle *dbHandleArray, uint8 dbHandleArrayCount, DbHandle *dbHandleAuthenticated)
{
Reason reason = SecurityAgent::noReason;
CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
OSStatus status; AuthValueVector arguments;
AuthItemSet hints, context;
#if defined(NOSA)
if (getenv("NOSA")) {
return SecurityAgent::noReason;
}
#endif
hints.insert(mClientHints.begin(), mClientHints.end());
create("builtin", "generic-unlock-kcblob", noSecuritySession);
AuthItem *secretItem;
int retryCount = 0;
do {
AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount));
hints.erase(triesHint); hints.insert(triesHint);
if (++retryCount > maxTries)
{
reason = SecurityAgent::tooManyTries;
}
AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
hints.erase(retryHint); hints.insert(retryHint);
setInput(hints, context);
status = invoke();
checkResult();
secretItem = outContext().find(AGENT_PASSWORD);
if (!secretItem)
continue;
secretItem->getCssmData(passphrase);
} while (reason = accept(passphrase, dbHandleArray, dbHandleArrayCount, dbHandleAuthenticated));
return reason;
}
Reason QueryDBBlobSecret::accept(CssmManagedData &passphrase,
DbHandle *dbHandlesToAuthenticate, uint8 dbHandleCount, DbHandle *dbHandleAuthenticated)
{
DbHandle *currHdl = dbHandlesToAuthenticate;
short index;
Boolean authenticated = false;
for (index=0; index < dbHandleCount && !authenticated; index++)
{
try
{
RefPointer<KeychainDatabase> dbToUnlock = Server::keychain(*currHdl);
dbToUnlock->unlockDb(passphrase);
authenticated = true;
*dbHandleAuthenticated = *currHdl; }
catch (const CommonError &err)
{
currHdl++; }
}
if ( !authenticated )
return SecurityAgent::invalidPassphrase;
return SecurityAgent::noReason;
}
QueryInvokeMechanism::QueryInvokeMechanism(const AuthHostType type, Session &session) :
SecurityAgentQuery(type, session) { }
void QueryInvokeMechanism::initialize(const string &inPluginId, const string &inMechanismId, const AuthValueVector &inArguments, const SessionId inSessionId)
{
if (SecurityAgent::Client::init == SecurityAgent::Client::state())
{
create(inPluginId.c_str(), inMechanismId.c_str(), inSessionId);
mArguments = inArguments;
}
}
void QueryInvokeMechanism::run(const AuthValueVector &inArguments, AuthItemSet &inHints, AuthItemSet &inContext, AuthorizationResult *outResult)
{
inHints.insert(mClientHints.begin(), mClientHints.end());
setArguments(inArguments);
setInput(inHints, inContext);
MacOSError::check(invoke());
if (outResult) *outResult = result();
inHints = outHints();
inContext = outContext();
}
void QueryInvokeMechanism::terminateAgent()
{
terminate();
}
Reason
QueryKeychainAuth::operator () (const char *database, const char *description, AclAuthorization action, const char *prompt)
{
Reason reason = SecurityAgent::noReason;
AuthItemSet hints, context;
AuthValueVector arguments;
int retryCount = 0;
string username;
string password;
using CommonCriteria::Securityd::KeychainAuthLogger;
KeychainAuthLogger logger(mAuditToken, AUE_ssauthint, database, description);
#if defined(NOSA)
if (getenv("NOSA")) {
char answer[maxPassphraseLength+10];
string applicationPath;
AuthItem *applicationPathItem = mClientHints.find(AGENT_HINT_APPLICATION_PATH);
if (applicationPathItem)
applicationPathItem->getString(applicationPath);
getNoSA(answer, sizeof(answer), "Allow %s to do %d on %s in %s? [yn][g]%s ",
applicationPath.c_str(), int(action), (description ? description : "[NULL item]"),
(database ? database : "[NULL database]"),
mPassphraseCheck ? ":passphrase" : "");
if (mPassphraseCheck && !strchr(answer, ':')) {
memmove(answer+2, answer, strlen(answer)+1);
memcpy(answer, "y:", 2);
}
allow = answer[0] == 'y';
remember = answer[1] == 'g';
return SecurityAgent::noReason;
}
#endif
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_ACL_TAG, AuthValueOverlay(sizeof(action), static_cast<sint32*>(&action))));
hints.insert(AuthItemRef(AGENT_HINT_CUSTOM_PROMPT, AuthValueOverlay(prompt ? strlen(prompt) : 0, const_cast<char*>(prompt))));
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_ITEM_NAME, AuthValueOverlay(description ? strlen(description) : 0, const_cast<char*>(description))));
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(database ? strlen(database) : 0, const_cast<char*>(database))));
create("builtin", "confirm-access-user-password", noSecuritySession);
AuthItem *usernameItem;
AuthItem *passwordItem;
do {
AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount));
hints.erase(triesHint); hints.insert(triesHint);
if (++retryCount > maxTries)
reason = SecurityAgent::tooManyTries;
if (SecurityAgent::noReason != reason)
{
if (SecurityAgent::tooManyTries == reason)
logger.logFailure(NULL, CommonCriteria::errTooManyTries);
else
logger.logFailure();
}
AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
hints.erase(retryHint); hints.insert(retryHint);
setInput(hints, context);
try
{
invoke();
checkResult();
}
catch (...) {
logger.logFailure();
throw;
}
usernameItem = outContext().find(AGENT_USERNAME);
passwordItem = outContext().find(AGENT_PASSWORD);
if (!usernameItem || !passwordItem)
continue;
usernameItem->getString(username);
passwordItem->getString(password);
} while (reason = accept(username, password));
if (SecurityAgent::noReason == reason)
logger.logSuccess();
return reason;
}
Reason
QueryKeychainAuth::accept(string &username, string &passphrase)
{
const char *user = username.c_str();
const char *passwd = passphrase.c_str();
int checkpw_status = checkpw(user, passwd);
if (checkpw_status != CHECKPW_SUCCESS)
return SecurityAgent::invalidPassphrase;
return SecurityAgent::noReason;
}