X-Git-Url: https://git.saurik.com/apple/securityd.git/blobdiff_plain/eeadf2e6470f45ea0275a6019635573f2a7b5a2c..4cd1cad0dea00daa03e1b54fdf2797a02373ad5b:/src/main.cpp diff --git a/src/main.cpp b/src/main.cpp index d765ec8..8647e72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,8 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved. * * @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 @@ -29,97 +27,101 @@ // #include -#include "securityserver.h" #include "server.h" #include "entropy.h" - -#include -#include #include "authority.h" #include "session.h" +#include "notifications.h" #include "pcscmonitor.h" +#include "auditevents.h" +#include "self.h" -#include +#include #include +#include +#include + +#include #include #include - -#include - -// #define PERFORMANCE_MEASUREMENT 1 - -#ifdef PERFORMANCE_MEASUREMENT -#include -#endif +#include // ACL subject types (their makers are instantiated here) #include #include +#include #include #include #include #include #include -#include +#include #include "acl_keychain.h" -namespace Security -{ - -// -// Program options (set by argument scan and environment) -// -uint32 debugMode = 0; -const char *bootstrapName = NULL; - -} // end namespace Security - - // // Local functions of the main program driver // -static void usage(const char *me); -static void handleSIGCHLD(int); -static void handleSIGOther(int); -IFDEBUG(static void handleSIGdebug(int)); +static void usage(const char *me) __attribute__((noreturn)); +static void handleSignals(int sig); +static PCSCMonitor::ServiceLevel scOptions(const char *optionString); + static Port gMainServerPort; +PCSCMonitor *gPCSC; + // // Main driver // int main(int argc, char *argv[]) { - #ifdef PERFORMANCE_MEASUREMENT - // needed for automated timing of securityd startup - uint64_t startTime = mach_absolute_time (); - #endif + // clear the umask - we know what we're doing + secdebug("SS", "starting umask was 0%o", ::umask(0)); + ::umask(0); + + // tell the keychain (client) layer to turn off the server interface + SecKeychainSetServerMode(); - Debug::trace (kSecTraceSecurityServerStart); - // program arguments (preset to defaults) + bool debugMode = false; + const char *bootstrapName = NULL; + const char* messagingName = SECURITY_MESSAGES_NAME; bool doFork = false; - bool forceCssmInit = false; bool reExecute = false; int workerTimeout = 0; int maxThreads = 0; + bool waitForClients = true; + bool mdsIsInstalled = false; const char *authorizationConfig = "/etc/authorization"; + const char *tokenCacheDir = "/var/db/TokenCache"; const char *entropyFile = "/var/db/SystemEntropyCache"; const char *equivDbFile = EQUIVALENCEDBPATH; + const char *smartCardOptions = getenv("SMARTCARDS"); + uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED; + unsigned int verbose = 0; + + // check for the Installation-DVD environment and modify some default arguments if found + if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists + SECURITYD_INSTALLMODE(); + smartCardOptions = "off"; // needs writable directories that aren't + } // parse command line arguments extern char *optarg; extern int optind; int arg; - while ((arg = getopt(argc, argv, "a:de:E:fN:t:T:X")) != -1) { + while ((arg = getopt(argc, argv, "a:c:de:E:imN:s:t:T:uvWX")) != -1) { switch (arg) { case 'a': authorizationConfig = optarg; break; + case 'c': + tokenCacheDir = optarg; + break; case 'd': - debugMode++; + debugMode = true; break; case 'e': equivDbFile = optarg; @@ -127,12 +129,18 @@ int main(int argc, char *argv[]) case 'E': entropyFile = optarg; break; - case 'f': - forceCssmInit = true; + case 'i': + keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID; + break; + case 'm': + mdsIsInstalled = true; break; case 'N': bootstrapName = optarg; break; + case 's': + smartCardOptions = optarg; + break; case 't': if ((maxThreads = atoi(optarg)) < 0) maxThreads = 0; @@ -141,6 +149,15 @@ int main(int argc, char *argv[]) if ((workerTimeout = atoi(optarg)) < 0) workerTimeout = 0; break; + case 'W': + waitForClients = false; + break; + case 'u': + keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED; + break; + case 'v': + verbose++; + break; case 'X': doFork = true; reExecute = true; @@ -155,16 +172,26 @@ int main(int argc, char *argv[]) usage(argv[0]); // figure out the bootstrap name - IFDEBUG(if (!bootstrapName) bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV)); - - if (!bootstrapName) { - bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME; + if (!bootstrapName) { + bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV); + if (!bootstrapName) + { + bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME; + } + else + { + messagingName = bootstrapName; + } } - + else + { + messagingName = bootstrapName; + } + // configure logging first if (debugMode) { Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR); - Syslog::notice("SecurityServer started in debug mode"); + Syslog::notice("%s started in debug mode", argv[0]); } else { Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS); } @@ -177,39 +204,47 @@ int main(int argc, char *argv[]) fprintf(stderr, "You are not allowed to run securityd\n"); exit(1); #else - fprintf(stderr, "securityd is unprivileged; some features may not work.\n"); - secdebug("SS", "Running as user %d (you have been warned)", uid); + fprintf(stderr, "securityd is unprivileged (uid=%d); some features may not work.\n", uid); #endif //NDEBUG } // turn into a properly diabolical daemon unless debugMode is on - if (!debugMode) { + if (!debugMode && getppid() != 1) { if (!Daemon::incarnate(doFork)) exit(1); // can't daemonize if (reExecute && !Daemon::executeSelf(argv)) exit(1); // can't self-execute } - - // create a code signing engine - CodeSigning::OSXSigner signer; - + + // arm signal handlers; code below may generate signals we want to see + if (signal(SIGCHLD, handleSignals) == SIG_ERR + || signal(SIGINT, handleSignals) == SIG_ERR + || signal(SIGTERM, handleSignals) == SIG_ERR + || signal(SIGPIPE, handleSignals) == SIG_ERR +#if !defined(NDEBUG) + || signal(SIGUSR1, handleSignals) == SIG_ERR +#endif //NDEBUG + || signal(SIGUSR2, handleSignals) == SIG_ERR) { + perror("signal"); + exit(1); + } + // create an Authorization engine Authority authority(authorizationConfig); - // establish the ACL machinery + // introduce all supported ACL subject types new AnyAclSubject::Maker(); new PasswordAclSubject::Maker(); new ProtectedPasswordAclSubject::Maker(); + new PromptedAclSubject::Maker(); new ThresholdAclSubject::Maker(); new CommentAclSubject::Maker(); new ProcessAclSubject::Maker(); - new CodeSignatureAclSubject::Maker(signer); - new KeychainPromptAclSubject::Maker(); - - // add a temporary registration for a subject type that went out in 10.2 seed 1 - // this should probably be removed for the next major release >10.2 - new KeychainPromptAclSubject::Maker(CSSM_WORDID__RESERVED_1); + new CodeSignatureAclSubject::Maker(); + new KeychainPromptAclSubject::Maker(keychainAclDefault); + new PreAuthorizationAcls::OriginMaker(); + new PreAuthorizationAcls::SourceMaker(); // establish the code equivalents database CodeSignatures codeSignatures(equivDbFile); @@ -217,7 +252,7 @@ int main(int argc, char *argv[]) // create the main server object and register it Server server(authority, codeSignatures, bootstrapName); - // Remember the primary service port to send signal events to. + // Remember the primary service port to send signal events to gMainServerPort = server.primaryServicePort(); // set server configuration from arguments, if specified @@ -225,64 +260,38 @@ int main(int argc, char *argv[]) server.timeout(workerTimeout); if (maxThreads) server.maxThreads(maxThreads); + server.floatingThread(true); + server.waitForClients(waitForClients); + server.verbosity(verbose); - // add the RNG seed timer to it + // add the RNG seed timer # if defined(NDEBUG) EntropyManager entropy(server, entropyFile); # else - if (!getuid()) new EntropyManager(server, entropyFile); + if (getuid() == 0) new EntropyManager(server, entropyFile); # endif - // create smartcard monitors to manage external token devices - PCSCMonitor secureCards(server); + // create a smartcard monitor to manage external token devices + gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions)); // create the RootSession object (if -d, give it graphics and tty attributes) - RootSession rootSession(server.primaryServicePort(), - debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0); - - // set up signal handlers - if (signal(SIGCHLD, handleSIGCHLD) == SIG_ERR) - secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno); - if (signal(SIGINT, handleSIGOther) == SIG_ERR) - secdebug("SS", "Cannot handle SIGINT: errno=%d", errno); - if (signal(SIGTERM, handleSIGOther) == SIG_ERR) - secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno); -#if !defined(NDEBUG) - if (signal(SIGUSR1, handleSIGdebug) == SIG_ERR) - secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno); -#endif //NDEBUG + RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server); + + // create a monitor thread to watch for audit session events + AuditMonitor audits(gMainServerPort); + audits.run(); - // initialize CSSM now if requested - if (forceCssmInit) - server.loadCssm(); + // install MDS (if needed) and initialize the local CSSM + server.loadCssm(mdsIsInstalled); + // create the shared memory notification hub + new SharedMemoryListener(messagingName, kSharedMemoryPoolSize); + + // okay, we're ready to roll + SECURITYD_INITIALIZED((char*)bootstrapName); Syslog::notice("Entering service"); - secdebug("SS", "%s initialized", bootstrapName); - - Debug::trace (kSecTraceSecurityServerInitialized); - #ifdef PERFORMANCE_MEASUREMENT - // needed for automated timing of securityd startup - uint64_t endTime = mach_absolute_time (); - - // compute how long it took to initialize - uint64_t elapsedTime = endTime - startTime; - mach_timebase_info_data_t multiplier; - mach_timebase_info (&multiplier); - - elapsedTime = elapsedTime * multiplier.numer / multiplier.denom; - - FILE* f = fopen ("/var/log/startuptime.txt", "a"); - if (f == NULL) - { - // probably not running as root. - f = fopen ("/tmp/startuptime.txt", "a"); - } - - fprintf (f, "%lld\n", elapsedTime); - fclose (f); - #endif - + // go server.run(); // fell out of runloop (should not happen) @@ -296,46 +305,50 @@ int main(int argc, char *argv[]) // static void usage(const char *me) { - fprintf(stderr, "Usage: %s [-df] [-t maxthreads] [-T threadTimeout]" - "\t[-N bootstrapName] [-a authConfigFile]\n", me); + fprintf(stderr, "Usage: %s [-dwX]" + "\n\t[-a authConfigFile] Authorization configuration file" + "\n\t[-c tokencache] smartcard token cache directory" + "\n\t[-e equivDatabase] path to code equivalence database" + "\n\t[-N serviceName] MACH service name" + "\n\t[-s off|on|conservative|aggressive] smartcard operation level" + "\n\t[-t maxthreads] [-T threadTimeout] server thread control" + "\n", me); exit(2); } // -// Handle SIGCHLD signals to reap our children (zombie cleanup) +// Translate strings (e.g. "conservative") into PCSCMonitor service levels // -static void handleSIGCHLD(int signal_number) +static PCSCMonitor::ServiceLevel scOptions(const char *optionString) { - kern_return_t kt = ucsp_client_handleSignal(gMainServerPort, mach_task_self(), signal_number); - if (kt) - syslog(LOG_ERR, "ucsp_client_handleSignal returned: %d", kt); + if (optionString) + if (!strcmp(optionString, "off")) + return PCSCMonitor::forcedOff; + else if (!strcmp(optionString, "on")) + return PCSCMonitor::forcedOn; + else if (!strcmp(optionString, "conservative")) + return PCSCMonitor::conservative; + else if (!strcmp(optionString, "aggressive")) + return PCSCMonitor::aggressive; + else if (!strcmp(optionString, "external")) + return PCSCMonitor::externalDaemon; + else + usage("securityd"); + else + return PCSCMonitor::aggressive; } // -// Handle some other signals to shut down cleanly (and with logging) +// Handle signals. +// We send ourselves a message (through the "self" service), so actual +// actions happen on the normal event loop path. Note that another thread +// may be picking up the message immediately. // -static void handleSIGOther(int sig) +static void handleSignals(int sig) { - switch (sig) { - case SIGINT: - //secdebug("SS", "Interrupt signal; terminating"); - Syslog::notice("received interrupt signal; terminating"); - exit(0); - case SIGTERM: - //secdebug("SS", "Termination signal; terminating"); - Syslog::notice("received termination signal; terminating"); - exit(0); - } + SECURITYD_SIGNAL_RECEIVED(sig); + if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig)) + Syslog::error("self-send failed (mach error %d)", rc); } - - -#if !defined(NDEBUG) - -static void handleSIGdebug(int) -{ - NodeCore::dumpAll(); -} - -#endif //NDEBUG