]> git.saurik.com Git - apple/securityd.git/blobdiff - src/main.cpp
securityd-55199.3.tar.gz
[apple/securityd.git] / src / main.cpp
index d765ec855887ac03e0b1a32ff38e4084d130f60b..8647e721dd8c636e233d898b093e57a07e01fce3 100644 (file)
@@ -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
 //
 #include <securityd_client/ucsp.h>
 
-#include "securityserver.h"
 #include "server.h"
 #include "entropy.h"
-
-#include <security_utilities/daemon.h>
-#include <security_cdsa_client/osxsigner.h>
 #include "authority.h"
 #include "session.h"
+#include "notifications.h"
 #include "pcscmonitor.h"
+#include "auditevents.h"
+#include "self.h"
 
-#include <unistd.h>
+#include <security_utilities/daemon.h>
 #include <security_utilities/machserver.h>
+#include <security_utilities/logging.h>
 
+#include <Security/SecKeychainPriv.h>
+
+#include <unistd.h>
 #include <sys/types.h>
 #include <signal.h>
-
-#include <security_utilities/ktracecodes.h>
-
-// #define PERFORMANCE_MEASUREMENT 1
-
-#ifdef PERFORMANCE_MEASUREMENT
-#include <mach/mach_time.h>
-#endif
+#include <syslog.h>
 
 // ACL subject types (their makers are instantiated here)
 #include <security_cdsa_utilities/acl_any.h>
 #include <security_cdsa_utilities/acl_password.h>
+#include <security_cdsa_utilities/acl_prompted.h>
 #include <security_cdsa_utilities/acl_protectedpw.h>
 #include <security_cdsa_utilities/acl_threshold.h>
 #include <security_cdsa_utilities/acl_codesigning.h>
 #include <security_cdsa_utilities/acl_process.h>
 #include <security_cdsa_utilities/acl_comment.h>
-#include <syslog.h>
+#include <security_cdsa_utilities/acl_preauth.h>
 #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