//
// passphrases - canonical code to obtain passphrases
//
+#define __STDC_WANT_LIB_EXT1__ 1
+#include <string.h>
+
#include "agentquery.h"
-#include "authority.h"
#include "ccaudit_extensions.h"
#include <Security/AuthorizationTags.h>
#include <xpc/private.h>
#include "securityd_service/securityd_service/securityd_service_client.h"
+// Includes for <rdar://problem/34677969> Always require the user's password on keychain approval dialogs
+#include "server.h"
+
#define SECURITYAGENT_BOOTSTRAP_NAME_BASE "com.apple.security.agent"
#define SECURITYAGENT_LOGINWINDOW_BOOTSTRAP_NAME_BASE "com.apple.security.agent.login"
-#define AUTHORIZATIONHOST_BOOTSTRAP_NAME_BASE "com.apple.security.authhost"
#define AUTH_XPC_ITEM_NAME "_item_name"
#define AUTH_XPC_ITEM_FLAGS "_item_flags"
#define AUTH_XPC_ITEM_VALUE "_item_value"
#define AUTH_XPC_ITEM_TYPE "_item_type"
+#define AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH "_item_sensitive_value_length"
#define AUTH_XPC_REQUEST_METHOD_KEY "_agent_request_key"
#define AUTH_XPC_REQUEST_METHOD_CREATE "_agent_request_create"
{ 0,0,0,0, 0,0,0,0, 0,0,0,0, (unsigned char)((0xff000000 & (sessionid))>>24), (unsigned char)((0x00ff0000 & (sessionid))>>16), (unsigned char)((0x0000ff00 & (sessionid))>>8), (unsigned char)((0x000000ff & (sessionid))) }
-// NOSA support functions. This is a test mode where the SecurityAgent
-// is simulated via stdio in the client. Good for running automated tests
-// of client programs. Only available if -DNOSA when compiling.
-
-#if defined(NOSA)
-#include <cstdarg>
-
-static void getNoSA(char *buffer, size_t bufferSize, const char *fmt, ...)
-{
- // write prompt
- va_list args;
- va_start(args, fmt);
- vfprintf(stdout, fmt, args);
- va_end(args);
-
- // read reply
- 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'; // remove trailing newline
- if (!isatty(fileno(stdin)))
- printf("%s\n", buffer); // echo to output if input not terminal
- } else {
- strncpy(buffer, nosa, bufferSize-1);
- printf("%s\n", buffer);
- }
- if (buffer[0] == '\0') // empty input -> cancellation
- CssmError::throwMe(CSSM_ERRCODE_USER_CANCELED);
-}
-#endif // NOSA
-
-
// SecurityAgentXPCConnection
-SecurityAgentXPCConnection::SecurityAgentXPCConnection(const AuthHostType type, Session &session)
-: mAuthHostType(type),
-mHostInstance(session.authhost(mAuthHostType)),
+SecurityAgentXPCConnection::SecurityAgentXPCConnection(Session &session)
+: mHostInstance(session.authhost()),
mSession(session),
mConnection(&Server::connection()),
mAuditToken(Server::connection().auditToken())
{
// this may take a while
Server::active().longTermActivity();
- secdebug("SecurityAgentConnection", "new SecurityAgentConnection(%p)", this);
+ secnotice("SecurityAgentConnection", "new SecurityAgentConnection(%p)", this);
mXPCConnection = NULL;
mNobodyUID = -2;
struct passwd *pw = getpwnam("nobody");
SecurityAgentXPCConnection::~SecurityAgentXPCConnection()
{
- secdebug("SecurityAgentConnection", "SecurityAgentConnection(%p) dying", this);
+ secnotice("SecurityAgentConnection", "SecurityAgentConnection(%p) dying", this);
mConnection->useAgent(NULL);
// If a connection has been established, we need to tear it down.
if (NULL != mXPCConnection) {
// Tearing this down is a multi-step process. First, request a cancellation.
- // This is safe even if the connection is already in the cancelled state.
+ // This is safe even if the connection is already in the canceled state.
xpc_connection_cancel(mXPCConnection);
// Then release the XPC connection
void
SecurityAgentXPCConnection::activate(bool ignoreUid)
{
- secdebug("SecurityAgentConnection", "activate(%p)", this);
+ secnotice("SecurityAgentConnection", "activate(%p)", this);
mConnection->useAgent(this);
if (mXPCConnection != NULL) {
try {
uuid_t sessionUUID = UUID_INITIALIZER_FROM_SESSIONID(mSession.sessionId());
- if (mAuthHostType == securityAgent) {
- // Yes, these need to be throws, as we're still in securityd, and thus still have to do flow control with exceptions.
- if (!(mSession.attributes() & sessionHasGraphicAccess))
- CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
- if (inDarkWake())
- CssmError::throwMe(CSSM_ERRCODE_IN_DARK_WAKE);
- uid_t targetUid = mHostInstance->session().originatorUid();
-
- secdebug("SecurityAgentXPCConnection","Retrieved UID %d for this session", targetUid);
- if (!ignoreUid && targetUid != 0 && targetUid != mNobodyUID) {
- mXPCConnection = xpc_connection_create_mach_service(SECURITYAGENT_BOOTSTRAP_NAME_BASE, NULL, 0);
- xpc_connection_set_target_uid(mXPCConnection, targetUid);
- secdebug("SecurityAgentXPCConnection", "Creating a standard security agent");
- } else {
- mXPCConnection = xpc_connection_create_mach_service(SECURITYAGENT_LOGINWINDOW_BOOTSTRAP_NAME_BASE, NULL, 0);
- xpc_connection_set_instance(mXPCConnection, sessionUUID);
- secdebug("SecurityAgentXPCConnection", "Creating a loginwindow security agent");
- }
- } else {
- mXPCConnection = xpc_connection_create_mach_service(AUTHORIZATIONHOST_BOOTSTRAP_NAME_BASE, NULL, 0);
+ // Yes, these need to be throws, as we're still in securityd, and thus still have to do flow control with exceptions.
+ if (!(mSession.attributes() & sessionHasGraphicAccess))
+ CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
+ if (inDarkWake())
+ CssmError::throwMe(CSSM_ERRCODE_IN_DARK_WAKE);
+ uid_t targetUid = mHostInstance->session().originatorUid();
+
+ secnotice("SecurityAgentXPCConnection","Retrieved UID %d for this session", targetUid);
+ if (!ignoreUid && targetUid != 0 && targetUid != mNobodyUID) {
+ mXPCConnection = xpc_connection_create_mach_service(SECURITYAGENT_BOOTSTRAP_NAME_BASE, NULL, 0);
+ xpc_connection_set_target_uid(mXPCConnection, targetUid);
+ secnotice("SecurityAgentXPCConnection", "Creating a standard security agent");
+ } else {
+ mXPCConnection = xpc_connection_create_mach_service(SECURITYAGENT_LOGINWINDOW_BOOTSTRAP_NAME_BASE, NULL,
+ XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
xpc_connection_set_instance(mXPCConnection, sessionUUID);
- secdebug("SecurityAgentXPCConnection", "Creating a standard authhost");
- }
+ secnotice("SecurityAgentXPCConnection", "Creating a loginwindow security agent");
+ }
xpc_connection_set_event_handler(mXPCConnection, ^(xpc_object_t object) {
if (xpc_get_type(object) == XPC_TYPE_ERROR) {
- secdebug("SecurityAgentXPCConnection", "error during xpc: %s", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION));
+ secnotice("SecurityAgentXPCConnection", "error during xpc: %s", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION));
}
});
xpc_connection_resume(mXPCConnection);
- secdebug("SecurityAgentXPCConnection", "%p activated", this);
+ secnotice("SecurityAgentXPCConnection", "%p activated", this);
}
catch (MacOSError &err) {
mConnection->useAgent(NULL); // guess not
- Syslog::error("SecurityAgentConnection: error activating %s instance %p",
- mAuthHostType == privilegedAuthHost
- ? "authorizationhost"
- : "SecurityAgent", this);
+ Syslog::error("SecurityAgentConnection: error activating SecurityAgent instance %p", this);
throw;
}
- secdebug("SecurityAgentXPCConnection", "contact didn't throw (%p)", this);
-}
-
-void
-SecurityAgentXPCConnection::reconnect()
-{
+ secnotice("SecurityAgentXPCConnection", "contact didn't throw (%p)", this);
}
void
}
-SecurityAgentXPCQuery::SecurityAgentXPCQuery(const AuthHostType type, Session &session)
-: SecurityAgentXPCConnection(type, session), mAgentConnected(false), mTerminateOnSleep(false)
+SecurityAgentXPCQuery::SecurityAgentXPCQuery(Session &session)
+: SecurityAgentXPCConnection(session), mAgentConnected(false), mTerminateOnSleep(false)
{
- secdebug("SecurityAgentXPCQuery", "new SecurityAgentXPCQuery(%p)", this);
+ secnotice("SecurityAgentXPCQuery", "new SecurityAgentXPCQuery(%p)", this);
}
SecurityAgentXPCQuery::~SecurityAgentXPCQuery()
{
- secdebug("SecurityAgentXPCQuery", "SecurityAgentXPCQuery(%p) dying", this);
+ secnotice("SecurityAgentXPCQuery", "SecurityAgentXPCQuery(%p) dying", this);
if (mAgentConnected) {
this->disconnect();
}
void
SecurityAgentXPCQuery::inferHints(Process &thisProcess)
{
- string guestPath;
- if (SecCodeRef clientCode = thisProcess.currentGuest())
- guestPath = codePath(clientCode);
-
AuthItemSet clientHints;
SecurityAgent::RequestorType type = SecurityAgent::bundle;
pid_t clientPid = thisProcess.pid();
uid_t clientUid = thisProcess.uid();
+ string guestPath = thisProcess.getPath();
+ Boolean ignoreSession = TRUE;
clientHints.insert(AuthItemRef(AGENT_HINT_CLIENT_TYPE, AuthValueOverlay(sizeof(type), &type)));
clientHints.insert(AuthItemRef(AGENT_HINT_CLIENT_PATH, AuthValueOverlay(guestPath)));
clientHints.insert(AuthItemRef(AGENT_HINT_CLIENT_PID, AuthValueOverlay(sizeof(clientPid), &clientPid)));
clientHints.insert(AuthItemRef(AGENT_HINT_CLIENT_UID, AuthValueOverlay(sizeof(clientUid), &clientUid)));
+ /*
+ * If its loginwindow that's asking, override the loginwindow shield detection
+ * up front so that it can trigger SecurityAgent dialogs (like password change)
+ * for when the OD password and keychain password is out of sync.
+ */
+
+ if (guestPath == "/System/Library/CoreServices/loginwindow.app") {
+ clientHints.insert(AuthItemRef(AGENT_HINT_IGNORE_SESSION, AuthValueOverlay(sizeof(ignoreSession), &ignoreSession)));
+ }
mClientHints.insert(clientHints.begin(), clientHints.end());
bool validSignature = thisProcess.checkAppleSigned();
AuthItemSet clientImmutableHints;
- clientImmutableHints.insert(AuthItemRef(AGENT_HINT_PROCESS_SIGNED, AuthValueOverlay(sizeof(validSignature), &validSignature)));
+ clientImmutableHints.insert(AuthItemRef(AGENT_HINT_CLIENT_SIGNED, AuthValueOverlay(sizeof(validSignature), &validSignature)));
mImmutableHints.insert(clientImmutableHints.begin(), clientImmutableHints.end());
}
size_t length;
const void *data = xpc_dictionary_get_data(item, AUTH_XPC_ITEM_VALUE, &length);
- void *dataCopy = malloc(length);
- memcpy(dataCopy, data, length);
+ void *dataCopy = 0;
+
+ // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
+ bool sensitive = xpc_dictionary_get_value(item, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH);
+ if (sensitive) {
+ size_t sensitiveLength = (size_t)xpc_dictionary_get_uint64(item, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH);
+ if (sensitiveLength > length) {
+ secnotice("SecurityAgentXPCQuery", "Sensitive data len %zu is not valid", sensitiveLength);
+ return true;
+ }
+ dataCopy = malloc(sensitiveLength);
+ memcpy(dataCopy, data, sensitiveLength);
+ memset_s((void *)data, length, 0, sensitiveLength); // clear the sensitive data, memset_s is never optimized away
+ length = sensitiveLength;
+ } else {
+ dataCopy = malloc(length);
+ memcpy(dataCopy, data, length);
+ }
uint64_t flags = xpc_dictionary_get_uint64(item, AUTH_XPC_ITEM_FLAGS);
AuthItemRef nextItem(name, AuthValueOverlay((uint32_t)length, dataCopy), (uint32_t)flags);
if (doSwitchAudit) {
mach_port_name_t jobPort;
if (0 == audit_session_port(mSession.sessionId(), &jobPort)) {
- secdebug("SecurityAgentXPCQuery", "attaching an audit session port because the uid was %d", targetUid);
+ secnotice("SecurityAgentXPCQuery", "attaching an audit session port because the uid was %d", targetUid);
xpc_dictionary_set_mach_send(requestObject, AUTH_XPC_AUDIT_SESSION_PORT, jobPort);
if (mach_port_mod_refs(mach_task_self(), jobPort, MACH_PORT_RIGHT_SEND, -1) != KERN_SUCCESS) {
- secdebug("SecurityAgentXPCQuery", "unable to release send right for audit session, leaking");
+ secnotice("SecurityAgentXPCQuery", "unable to release send right for audit session, leaking");
}
}
}
if (doSwitchBootstrap) {
- secdebug("SecurityAgentXPCQuery", "attaching a bootstrap port because the uid was %d", targetUid);
+ secnotice("SecurityAgentXPCQuery", "attaching a bootstrap port because the uid was %d", targetUid);
MachPlusPlus::Bootstrap processBootstrap = Server::process().taskPort().bootstrap();
xpc_dictionary_set_mach_send(requestObject, AUTH_XPC_BOOTSTRAP_PORT, processBootstrap);
}
if (status == kAuthorizationResultAllow) {
mAgentConnected = true;
} else {
- secdebug("SecurityAgentXPCQuery", "plugin create failed in SecurityAgent");
+ secnotice("SecurityAgentXPCQuery", "plugin create failed in SecurityAgent");
MacOSError::throwMe(errAuthorizationInternal);
}
}
if (XPC_ERROR_CONNECTION_INVALID == object) {
// If we get an error before getting the create response, try again without the UID
if (ignoreUid) {
- secdebug("SecurityAgentXPCQuery", "failed to establish connection, no retries left");
+ secnotice("SecurityAgentXPCQuery", "failed to establish connection, no retries left");
xpc_release(object);
MacOSError::throwMe(errAuthorizationInternal);
} else {
- secdebug("SecurityAgentXPCQuery", "failed to establish connection, retrying with no UID");
+ secnotice("SecurityAgentXPCQuery", "failed to establish connection, retrying with no UID");
ignoreUid = true;
xpc_release(mXPCConnection);
mXPCConnection = NULL;
return outputArray;
}
-OSStatus
+void
SecurityAgentXPCQuery::invoke() {
- __block OSStatus status = kAuthorizationResultUndefined;
-
xpc_object_t hintsArray = authItemSetToXPCArray(mInHints);
xpc_object_t contextArray = authItemSetToXPCArray(mInContext);
xpc_object_t immutableHintsArray = authItemSetToXPCArray(mImmutableHints);
xpc_release(contextArray);
xpc_release(immutableHintsArray);
xpc_release(requestObject);
-
- return status;
}
void SecurityAgentXPCQuery::checkResult()
{
// if passphrase checking requested, save KeychainDatabase reference
// (will quietly disable check if db isn't a keychain)
- if (needPass)
- mPassphraseCheck = dynamic_cast<const KeychainDatabase *>(db);
+
+ // Always require password due to <rdar://problem/34677969>
+ mPassphraseCheck = dynamic_cast<const KeychainDatabase *>(db);
setTerminateOnSleep(true);
}
+// Callers to this function must hold the common lock
Reason QueryKeychainUse::queryUser (const char *database, const char *description, AclAuthorization action)
{
Reason reason = SecurityAgent::noReason;
- int retryCount = 0;
- OSStatus status;
- AuthValueVector arguments;
+ uint32_t retryCount = 0;
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" : "");
- // turn passphrase (no ':') into y: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
-
// prepopulate with client hints
hints.insert(mClientHints.begin(), mClientHints.end());
// item name into hints
- hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_ITEM_NAME, AuthValueOverlay(description ? (uint32_t)strlen(description) : 0, const_cast<char*>(description))));
+ hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_ITEM_NAME, AuthValueOverlay(description ? (uint32_t)strlen(description) : 0, const_cast<char*>(description))));
// keychain name into hints
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(database ? (uint32_t)strlen(database) : 0, const_cast<char*>(database))));
hints.erase(retryHint); hints.insert(retryHint); // replace
setInput(hints, context);
- status = invoke();
+
+ {
+ // Must drop the common lock while showing UI.
+ StSyncLock<Mutex, Mutex> syncLock(const_cast<KeychainDatabase*>(mPassphraseCheck)->common().uiLock(), const_cast<KeychainDatabase*>(mPassphraseCheck)->common());
+ invoke();
+ }
if (retryCount > kMaximumAuthorizationTries)
{
continue;
passwordItem->getCssmData(data);
+
+ // decode() replaces the master key, so do this only if we know the passphrase is correct.
+ // I suspect decode() is redundant but something might rely on its side effects so let's keep it.
+ if (const_cast<KeychainDatabase*>(mPassphraseCheck)->validatePassphrase(data) && const_cast<KeychainDatabase*>(mPassphraseCheck)->decode(data)) {
+ reason = SecurityAgent::noReason;
+ } else {
+ reason = SecurityAgent::invalidPassphrase;
+ }
}
- while ((reason = (const_cast<KeychainDatabase*>(mPassphraseCheck)->decode(data) ? SecurityAgent::noReason : SecurityAgent::invalidPassphrase)));
+ while (reason != SecurityAgent::noReason);
+
+ readChoice();
}
else
{
- create("builtin", "confirm-access");
- setInput(hints, context);
- invoke();
+// create("builtin", "confirm-access");
+// setInput(hints, context);
+// invoke();
+
+ // This is a hack to support <rdar://problem/34677969>, we can never simply prompt for confirmation
+ secerror("ACL validation fallback case! Must ask user for account password because we have no database");
+ Session &session = Server::session();
+ try{
+ session.verifyKeyStorePassphrase(1, true, description);
+ } catch (...) {
+ return SecurityAgent::invalidPassphrase;
+ }
+ SecurityAgentXPCQuery::allow = true;
}
- readChoice();
-
return reason;
}
-//
-// Perform code signature ACL access adjustment dialogs
-//
-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
-
- // prepopulate with client hints
- hints.insert(mClientHints.begin(), mClientHints.end());
-
- hints.insert(AuthItemRef(AGENT_HINT_APPLICATION_PATH, AuthValueOverlay((uint32_t)strlen(aclPath), const_cast<char*>(aclPath))));
-
- create("builtin", "code-identity");
-
- setInput(hints, context);
- status = invoke();
-
- checkResult();
-
-// MacOSError::check(status);
-
- return kAuthorizationResultAllow == mLastResult;
-}
-
-
//
// Obtain passphrases and submit them to the accept() method until it is accepted
// or we can't get another passphrase. Accept() should consume the passphrase
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)
- // return the passphrase
- 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
-
// prepopulate with client hints
const char *keychainPath = database.dbName();
hints.erase(retryHint); hints.insert(retryHint); // replace
setInput(hints, context);
- status = invoke();
+ invoke();
if (retryCount > maxTries)
{
//
Reason QueryUnlock::accept(CssmManagedData &passphrase)
{
+ // Must hold the 'common' lock to call decode; otherwise there's a data corruption issue
+ StLock<Mutex> _(safer_cast<KeychainDatabase &>(database).common());
+
+ // Calling validatePassphrase here throws when trying to constitute a key.
+ // Unsure why but since this is for the KC unlock path and not a validation path the wrong password won't make things worse.
if (safer_cast<KeychainDatabase &>(database).decode(passphrase))
return SecurityAgent::noReason;
else
Reason QueryKeybagPassphrase::query()
{
Reason reason = SecurityAgent::noReason;
- OSStatus status;
- AuthValueVector arguments;
AuthItemSet hints, context;
CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
int retryCount = 0;
hints.erase(retryHint); hints.insert(retryHint); // replace
setInput(hints, context);
- status = invoke();
+ invoke();
checkResult();
CssmAutoData pass(Allocator::standard(Allocator::sensitive));
CssmAutoData oldPass(Allocator::standard(Allocator::sensitive));
Reason reason = SecurityAgent::noReason;
- OSStatus status;
- AuthValueVector arguments;
AuthItemSet hints, context;
int retryCount = 0;
hints.erase(retryHint); hints.insert(retryHint); // replace
setInput(hints, context);
- status = invoke();
+ invoke();
checkResult();
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
-
// prepopulate with client hints
hints.insert(mClientHints.begin(), mClientHints.end());
hints.erase(retryHint); hints.insert(retryHint); // replace
setInput(hints, context);
- status = invoke();
+ invoke();
if (retryCount > maxTries)
{
string &passphrase)
{
Reason reason = SecurityAgent::noReason;
- OSStatus status; // not really used; remove?
- AuthValueVector arguments;
AuthItemSet hints, context;
-#if defined(NOSA)
- if (getenv("NOSA")) {
- // FIXME 3690984
- return SecurityAgent::noReason;
- }
-#endif
-
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_CUSTOM_PROMPT, AuthValueOverlay(prompt ? (UInt32)prompt->length() : 0, prompt ? prompt->data() : NULL)));
// XXX/gh defined by dmitch but no analogous hint in
if (false == verify) { // import
create("builtin", "generic-unlock");
} else { // verify passphrase (export)
- // new-passphrase-generic works with the pre-4 June 2004 agent;
- // generic-new-passphrase is required for the new agent
create("builtin", "generic-new-passphrase");
}
do {
setInput(hints, context);
- status = invoke();
+ invoke();
checkResult();
passwordItem = mOutContext.find(AGENT_PASSWORD);
{
Reason reason = SecurityAgent::noReason;
CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
- OSStatus status; // not really used; remove?
- AuthValueVector arguments;
AuthItemSet hints/*NUKEME*/, context;
-#if defined(NOSA)
- if (getenv("NOSA")) {
- // FIXME akin to 3690984
- return SecurityAgent::noReason;
- }
-#endif
-
hints.insert(mClientHints.begin(), mClientHints.end());
create("builtin", "generic-unlock-kcblob");
hints.erase(retryHint); hints.insert(retryHint); // replace
setInput(hints, context);
- status = invoke();
+ invoke();
checkResult();
secretItem = mOutContext.find(AGENT_PASSWORD);
if (!secretItem)
try
{
RefPointer<KeychainDatabase> dbToUnlock = Server::keychain(*currHdl);
- dbToUnlock->unlockDb(passphrase);
+ dbToUnlock->unlockDb(passphrase, false);
authenticated = true;
*dbHandleAuthenticated = *currHdl; // return the DbHandle that 'passphrase' authenticated with.
}
// @@@ no pluggable authentication possible!
Reason
-QueryKeychainAuth::operator () (const char *database, const char *description, AclAuthorization action, const char *prompt)
+QueryKeychainAuth::performQuery(const KeychainDatabase& db, 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)
- /* XXX/gh probably not complete; stolen verbatim from rogue-app query */
- 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" : "");
- // turn passphrase (no ':') into y: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
+ KeychainAuthLogger logger(mAuditToken, (short)AUE_ssauthint, db.dbName(), description);
hints.insert(mClientHints.begin(), mClientHints.end());
hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_ITEM_NAME, AuthValueOverlay(description ? (uint32_t)strlen(description) : 0, const_cast<char*>(description))));
// keychain name into hints
- hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(database ? (uint32_t)strlen(database) : 0, const_cast<char*>(database))));
+ hints.insert(AuthItemRef(AGENT_HINT_KEYCHAIN_PATH, AuthValueOverlay(db.dbName() ? (uint32_t)strlen(db.dbName()) : 0, const_cast<char*>(db.dbName()))));
create("builtin", "confirm-access-user-password");
AuthItem *usernameItem;
AuthItem *passwordItem;
+ // This entire do..while requires the UI lock because we do accept() in the condition, which in some cases is reentrant
+ StSyncLock<Mutex, Mutex> syncLock(db.common().uiLock(), db.common());
do {
-
AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount));
hints.erase(triesHint); hints.insert(triesHint); // replace
usernameItem->getString(username);
passwordItem->getString(password);
} while ((reason = accept(username, password)));
+ syncLock.unlock();
if (SecurityAgent::noReason == reason)
logger.logSuccess();