X-Git-Url: https://git.saurik.com/apple/securityd.git/blobdiff_plain/eeadf2e6470f45ea0275a6019635573f2a7b5a2c..24a291535d44686bc7959c7e398fab040e3e08a7:/src/server.cpp?ds=sidebyside diff --git a/src/server.cpp b/src/server.cpp index af82dd7..f440a7d 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,14 +23,19 @@ // -// server - the actual SecurityServer server object +// server - securityd main server object // -#include // knowledge of mig message sizes +#include // MIG ucsp service +#include "self.h" // MIG self service +#include +#include #include "server.h" #include "session.h" #include "acls.h" #include "notifications.h" +#include "child.h" #include +#include using namespace MachPlusPlus; @@ -56,10 +59,16 @@ Server::Server(Authority &authority, CodeSignatures &signatures, const char *boo mBootstrapName(bootstrapName), mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule), mAuthority(authority), - mCodeSignatures(signatures) + mCodeSignatures(signatures), + mAudit(geteuid(), getpid()) { + // make me eternal (in the object mesh) + ref(); + + mAudit.registerSession(); + // engage the subsidiary port handler for sleep notifications - add(sleepWatcher); + add(sleepWatcher); } @@ -129,39 +138,30 @@ RefPointer Server::key(KeyHandle key) RefPointer Server::database(DbHandle db) { - RefPointer database = - HandleObject::findRef(db, CSSMERR_DL_INVALID_DB_HANDLE); - if (database->process() != process()) - CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE); - return database; + return find(db, CSSMERR_DL_INVALID_DB_HANDLE); } RefPointer Server::keychain(DbHandle db) { - RefPointer keychain = - HandleObject::findRef(db, CSSMERR_DL_INVALID_DB_HANDLE); - if (keychain->process() != process()) - CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE); - return keychain; + return find(db, CSSMERR_DL_INVALID_DB_HANDLE); } -RefPointer Server::optionalDatabase(DbHandle db) +RefPointer Server::optionalDatabase(DbHandle db, bool persistent) { - if (db == noDb) - return &process().localStore(); - else + if (persistent && db != noDb) return database(db); + else + return &process().localStore(); } // // Locate an ACL bearer (database or key) by handle // -SecurityServerAcl &Server::aclBearer(AclKind kind, CSSM_HANDLE handle) +AclSource &Server::aclBearer(AclKind kind, CSSM_HANDLE handle) { - SecurityServerAcl &bearer = - HandleObject::find(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE); - if (kind != bearer.kind()) + AclSource &bearer = HandleObject::find(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE); + if (kind != bearer.acl().aclKind()) CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); return bearer; } @@ -174,37 +174,55 @@ void Server::run() { MachServer::run(0x10000, MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | - MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)); + MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)); +} + + +// +// Handle thread overflow. MachServer will call this if it has hit its thread +// limit and yet still needs another thread. +// +void Server::threadLimitReached(UInt32 limit) +{ + Syslog::notice("securityd has reached its thread limit (%ld) - service deadlock is possible", + limit); } // // The primary server run-loop function. -// Invokes the MIG-generated main dispatch function (ucsp_server). +// Invokes the MIG-generated main dispatch function (ucsp_server), as well +// as the self-send dispatch (self_server). // For debug builds, look up request names in a MIG-generated table // for better debug-log messages. // boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *); +boolean_t self_server(mach_msg_header_t *, mach_msg_header_t *); #if defined(NDEBUG) boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) { - return ucsp_server(in, out); + return ucsp_server(in, out) || self_server(in, out); } #else //NDEBUG -static const struct IPCName { const char *name; int ipc; } ipcNames[] = - { subsystem_to_name_map_ucsp }; // macro generated by MIG, from ucsp.h +struct IPCName { const char *name; int ipc; }; +static IPCName ucspNames[] = { subsystem_to_name_map_ucsp }; // generated by MIG +static IPCName selfNames[] = { subsystem_to_name_map_self }; // generated by MIG boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) { - const int first = ipcNames[0].ipc; - const char *name = (in->msgh_id >= first && in->msgh_id < first + ucsp_MSG_COUNT) ? - ipcNames[in->msgh_id - first].name : "OUT OF BOUNDS"; + const int id = in->msgh_id; + const int ucspBase = ucspNames[0].ipc; + const int selfBase = selfNames[0].ipc; + const char *name = + (id >= ucspBase && id < ucspBase + ucsp_MSG_COUNT) ? ucspNames[id - ucspBase].name : + (id >= selfBase && id < selfBase + self_MSG_COUNT) ? selfNames[id - selfBase].name : + "OUT OF BOUNDS"; secdebug("SSreq", "begin %s (%d)", name, in->msgh_id); - boolean_t result = ucsp_server(in, out); + boolean_t result = ucsp_server(in, out) || self_server(in, out); secdebug("SSreq", "end %s (%d)", name, in->msgh_id); return result; } @@ -220,7 +238,7 @@ boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) // in the case of session re-initialization (see below). // void Server::setupConnection(ConnectLevel type, Port servicePort, Port replyPort, Port taskPort, - const security_token_t &securityToken, const ClientSetupInfo *info, const char *identity) + const audit_token_t &auditToken, const ClientSetupInfo *info, const char *identity) { // first, make or find the process based on task port StLock _(*this); @@ -229,12 +247,16 @@ void Server::setupConnection(ConnectLevel type, Port servicePort, Port replyPort // The client has talked to us before and now wants to create a new session. proc->changeSession(servicePort); } + if (proc && type == connectNewProcess) { + // the client has amnesia - reset it + assert(info && identity); + proc->reset(servicePort, taskPort, info, identity, AuditToken(auditToken)); + } if (!proc) { if (type == connectNewThread) // client error (or attack) CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); assert(info && identity); - proc = new Process(servicePort, taskPort, info, identity, - securityToken.val[0], securityToken.val[1]); + proc = new Process(servicePort, taskPort, info, identity, AuditToken(auditToken)); notifyIfDead(taskPort); } @@ -292,6 +314,7 @@ void Server::notifyDeadName(Port port) if (Listener::remove(port)) return; + // well, what IS IT?! secdebug("server", "spurious dead port notification for port %d", port.port()); } @@ -307,6 +330,46 @@ void Server::notifyNoSenders(Port port, mach_port_mscount_t) } +// +// Handling signals. +// These are sent as Mach messages from ourselves to escape the limitations of +// the signal handler environment. +// +kern_return_t self_server_handleSignal(mach_port_t sport, + mach_port_t taskPort, int sig) +{ + try { + if (taskPort != mach_task_self()) { + Syslog::error("handleSignal: received from someone other than myself"); + secdebug("SS", "unauthorized handleSignal"); + return 0; + } + secdebug("SS", "dispatching indirect signal %d", sig); + switch (sig) { + case SIGCHLD: + ServerChild::checkChildren(); + break; + case SIGINT: + case SIGTERM: + secdebug("SS", "signal %d received: terminating", sig); + Syslog::notice("securityd terminating due to signal %d", sig); + exit(0); +#if defined(DEBUGDUMP) + case SIGUSR1: + NodeCore::dumpAll(); + break; +#endif //DEBUGDUMP + default: + assert(false); + } + } catch(...) { + secdebug("SS", "exception handling a signal (ignored)"); + } + mach_port_deallocate(mach_task_self(), taskPort); + return 0; +} + + // // Notifier for system sleep events // @@ -314,63 +377,48 @@ void Server::SleepWatcher::systemWillSleep() { secdebug("SS", "sleep notification received"); Session::processSystemSleep(); + secdebug("server", "distributing sleep event to %ld clients", mPowerClients.size()); + for (set::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) + (*it)->systemWillSleep(); } +void Server::SleepWatcher::systemIsWaking() +{ + secdebug("server", "distributing wakeup event to %ld clients", mPowerClients.size()); + for (set::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) + (*it)->systemIsWaking(); +} -// -// Return the primary Cryptographic Service Provider. -// This will be lazily loaded when it is first requested. -// -CssmClient::CSP &Server::getCsp() +void Server::SleepWatcher::add(PowerWatcher *client) { - if (!mCssm->isActive()) - loadCssm(); - return mCSP; + assert(mPowerClients.find(client) == mPowerClients.end()); + mPowerClients.insert(client); +} + +void Server::SleepWatcher::remove(PowerWatcher *client) +{ + assert(mPowerClients.find(client) != mPowerClients.end()); + mPowerClients.erase(client); } // // Initialize the CSSM/MDS subsystem. -// This is thread-safe and can be done lazily. +// This was once done lazily on demand. These days, we are setting up the +// system MDS here, and CSSM is pretty much always needed, so this is called +// early during program startup. Do note that the server may not (yet) be running. // -static void initMds(); - void Server::loadCssm() { if (!mCssm->isActive()) { StLock _(*this); if (!mCssm->isActive()) { - try { - initMds(); - } catch (const CssmError &error) { - switch (error.osStatus()) { - case CSSMERR_DL_MDS_ERROR: - case CSSMERR_DL_OS_ACCESS_DENIED: - secdebug("SS", "MDS initialization failed; continuing"); - Syslog::warning("MDS initialization failed; continuing"); - break; - default: - throw; - } - } + secdebug("SS", "Installing MDS"); + MDSClient::mds().install(); secdebug("SS", "CSSM initializing"); mCssm->init(); mCSP->attach(); - IFDEBUG(char guids[Guid::stringRepLength+1]); - secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString(guids)); + secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString().c_str()); } } } - -#include - -static void initMds() -{ - secdebug("SS", "MDS initializing"); - CssmAllocatorMemoryFunctions memory(Allocator::standard()); - MDS_FUNCS functions; - MDS_HANDLE handle; - CssmError::check(MDS_Initialize(NULL, &memory, &functions, &handle)); - CssmError::check(MDS_Install(handle)); - CssmError::check(MDS_Terminate(handle)); -}