]> git.saurik.com Git - apple/securityd.git/blobdiff - src/server.cpp
securityd-27896.tar.gz
[apple/securityd.git] / src / server.cpp
index af82dd77e08a011a995c0c733ddcfb349cbc89df..f440a7d8fff07b252ceb20bbbb092377c7aaaab5 100644 (file)
@@ -3,8 +3,6 @@
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
  * 
  * @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
  * 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
 
 
 //
 
 
 //
-// server - the actual SecurityServer server object
+// server - securityd main server object
 //
 //
-#include <securityd_client/ucsp.h> // knowledge of mig message sizes
+#include <securityd_client/ucsp.h>     // MIG ucsp service
+#include "self.h"                                      // MIG self service
+#include <security_utilities/logging.h>
+#include <security_cdsa_client/mdsclient.h>
 #include "server.h"
 #include "session.h"
 #include "acls.h"
 #include "notifications.h"
 #include "server.h"
 #include "session.h"
 #include "acls.h"
 #include "notifications.h"
+#include "child.h"
 #include <mach/mach_error.h>
 #include <mach/mach_error.h>
+#include <security_utilities/ccaudit.h>
 
 using namespace MachPlusPlus;
 
 
 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),
     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
     // engage the subsidiary port handler for sleep notifications
-    add(sleepWatcher);
+       add(sleepWatcher);
 }
 
 
 }
 
 
@@ -129,39 +138,30 @@ RefPointer<Key> Server::key(KeyHandle key)
 
 RefPointer<Database> Server::database(DbHandle db)
 {
 
 RefPointer<Database> Server::database(DbHandle db)
 {
-       RefPointer<Database> database = 
-               HandleObject::findRef<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
-       if (database->process() != process())
-               CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
-       return database;
+       return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
 }
 
 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
 {
 }
 
 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
 {
-       RefPointer<KeychainDatabase> keychain =
-               HandleObject::findRef<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
-       if (keychain->process() != process())
-               CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
-       return keychain;
+       return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
 }
 
 }
 
-RefPointer<Database> Server::optionalDatabase(DbHandle db)
+RefPointer<Database> Server::optionalDatabase(DbHandle db, bool persistent)
 {
 {
-       if (db == noDb)
-               return &process().localStore();
-       else
+       if (persistent && db != noDb)
                return database(db);
                return database(db);
+       else
+               return &process().localStore();
 }
 
 
 //
 // Locate an ACL bearer (database or key) by handle
 //
 }
 
 
 //
 // 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<SecurityServerAcl>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
-       if (kind != bearer.kind())
+       AclSource &bearer = HandleObject::find<AclSource>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
+       if (kind != bearer.acl().aclKind())
                CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE);
        return bearer;
 }
                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) |
 {
        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.
 }
 
 
 //
 // 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 *);
 // 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)
 {
 
 #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
 
 }
 
 #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)
 {
 
 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);
     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;
 }
     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,
 // 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<Mutex> _(*this);
 {
        // first, make or find the process based on task port
        StLock<Mutex> _(*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);
        }
                // 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);
        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);
        }
 
                notifyIfDead(taskPort);
        }
 
@@ -292,6 +314,7 @@ void Server::notifyDeadName(Port port)
     if (Listener::remove(port))
         return;
     
     if (Listener::remove(port))
         return;
     
+       // well, what IS IT?!
        secdebug("server", "spurious dead port notification for port %d", port.port());
 }
 
        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
 //
 //
 // Notifier for system sleep events
 //
@@ -314,63 +377,48 @@ void Server::SleepWatcher::systemWillSleep()
 {
     secdebug("SS", "sleep notification received");
     Session::processSystemSleep();
 {
     secdebug("SS", "sleep notification received");
     Session::processSystemSleep();
+       secdebug("server", "distributing sleep event to %ld clients", mPowerClients.size());
+       for (set<PowerWatcher *>::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<PowerWatcher *>::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.
 }
 
 
 //
 // 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<Mutex> _(*this);
                if (!mCssm->isActive()) {
 void Server::loadCssm()
 {
        if (!mCssm->isActive()) {
                StLock<Mutex> _(*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();
                        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 <Security/mds.h>
-
-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));
-}