#include "acls.h"
#include "connection.h"
#include "server.h"
#include "agentquery.h"
#include "tokendatabase.h"
#include "acl_keychain.h"
#include <security_cdsa_utilities/acl_any.h>
#include <security_cdsa_utilities/acl_password.h>
#include <security_cdsa_utilities/acl_threshold.h>
#include <sys/sysctl.h>
#include <security_utilities/logging.h>
SecurityServerAcl::~SecurityServerAcl()
{ }
void SecurityServerAcl::getOwner(AclOwnerPrototype &owner)
{
StLock<Mutex> _(aclSequence);
ObjectAcl::cssmGetOwner(owner);
}
void SecurityServerAcl::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls)
{
StLock<Mutex> _(aclSequence);
ObjectAcl::cssmGetAcl(tag, count, acls);
}
void SecurityServerAcl::changeAcl(const AclEdit &edit, const AccessCredentials *cred,
Database *db)
{
StLock<Mutex> _(aclSequence);
SecurityServerEnvironment env(*this, db);
ObjectAcl::cssmChangeAcl(edit, cred, &env);
}
void SecurityServerAcl::changeOwner(const AclOwnerPrototype &newOwner,
const AccessCredentials *cred, Database *db)
{
StLock<Mutex> _(aclSequence);
SecurityServerEnvironment env(*this, db);
ObjectAcl::cssmChangeOwner(newOwner, cred, &env);
}
void SecurityServerAcl::validate(AclAuthorization auth, const AccessCredentials *cred, Database *db)
{
SecurityServerEnvironment env(*this, db);
StLock<Mutex> objectSequence(aclSequence);
StLock<Mutex> processSequence(Server::process().aclSequence);
ObjectAcl::validate(auth, cred, &env);
}
void SecurityServerAcl::validate(AclAuthorization auth, const Context &context, Database *db)
{
validate(auth,
context.get<AccessCredentials>(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS), db);
}
bool SecurityServerAcl::addToStandardACL(const AclValidationContext &context, AclSubject *subject)
{
if (SecurityServerEnvironment *env = context.environment<SecurityServerEnvironment>())
if (ThresholdAclSubject *threshold = env->standardSubject(context)) {
unsigned size = threshold->count();
if (dynamic_cast<KeychainPromptAclSubject *>(threshold->subject(size-1))) {
secdebug("acl", "adding new subject %p to from of threshold ACL", subject);
threshold->add(subject, 0);
context.acl()->changedAcl();
Server::connection().overrideReturn(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT);
return true;
}
}
secdebug("acl", "ACL is not standard form; cannot edit");
return false;
}
bool SecurityServerAcl::looksLikeLegacyDotMac(const AclValidationContext &context)
{
static const char * const prototypicalDotMacPath[] = {
"/Applications/Mail.app",
"/Applications/Safari.app",
"/Applications/iSync.app",
"/Applications/System Preferences.app",
"/Applications/iCal.app",
"/Applications/iChat.app",
"/Applications/iTunes.app",
"/Applications/Address Book.app",
"/Applications/iSync.app",
NULL };
static const unsigned threshold = 6;
if (SecurityServerEnvironment *env = context.environment<SecurityServerEnvironment>()) {
if (ThresholdAclSubject *list = env->standardSubject(context)) {
unsigned count = list->count();
unsigned matches = 0;
for (unsigned n = 0; n < count; ++n) {
if (CodeSignatureAclSubject *app = dynamic_cast<CodeSignatureAclSubject *>(list->subject(n))) {
for (const char * const *p = prototypicalDotMacPath; *p; p++)
if (app->path() == *p)
matches++;
}
}
secdebug("codesign", "matched %d of %zd candididates (threshold=%d)",
matches, sizeof(prototypicalDotMacPath) / sizeof(char *) - 1, threshold);
return matches >= threshold;
}
}
return false;
}
Adornable &SecurityServerEnvironment::store(const AclSubject *subject)
{
switch (subject->type()) {
case CSSM_ACL_SUBJECT_TYPE_PREAUTH:
{
if (TokenDatabase *tokenDb = dynamic_cast<TokenDatabase *>(database))
return tokenDb->common().store();
}
break;
default:
break;
}
CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED);
}
uid_t SecurityServerEnvironment::getuid() const
{
return Server::process().uid();
}
gid_t SecurityServerEnvironment::getgid() const
{
return Server::process().gid();
}
pid_t SecurityServerEnvironment::getpid() const
{
return Server::process().pid();
}
bool SecurityServerEnvironment::verifyCodeSignature(const OSXVerifier &verifier,
const AclValidationContext &context)
{
return Server::codeSignatures().verify(Server::process(), verifier, context);
}
bool SecurityServerEnvironment::getSecret(CssmOwnedData &secret, const CssmData &prompt) const
{
if (database) {
QueryPIN query(*database);
query.inferHints(Server::process());
if (!query()) { secret = query.pin();
return true;
}
}
return false;
}
bool SecurityServerEnvironment::validateSecret(const SecretAclSubject *me,
const AccessCredentials *cred)
{
return database && database->validateSecret(me, cred);
}
ObjectAcl *SecurityServerEnvironment::preAuthSource()
{
return database ? &database->acl() : NULL;
}
ThresholdAclSubject *SecurityServerEnvironment::standardSubject(const AclValidationContext &context)
{
return dynamic_cast<ThresholdAclSubject *>(context.subject());
}
AclSource::~AclSource()
{ }
SecurityServerAcl &AclSource::acl()
{
CssmError::throwMe(CSSM_ERRCODE_OBJECT_ACL_NOT_SUPPORTED);
}
Database *AclSource::relatedDatabase()
{
return NULL;
}