X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/securityd/src/main.cpp?ds=inline diff --git a/securityd/src/main.cpp b/securityd/src/main.cpp new file mode 100644 index 00000000..56097886 --- /dev/null +++ b/securityd/src/main.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2000-2009,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * 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 + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// securityd - Apple security services daemon. +// +#include + +#include "server.h" +#include "entropy.h" +#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 + +// ACL subject types (their makers are instantiated here) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acl_keychain.h" + + +// +// Local functions of the main program driver +// +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[]) +{ + // 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(); + + // program arguments (preset to defaults) + bool debugMode = false; + const char *bootstrapName = NULL; + const char* messagingName = SECURITY_MESSAGES_NAME; + bool doFork = 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:c:de:E:imN:s:t:T:uvWX")) != -1) { + switch (arg) { + case 'a': + authorizationConfig = optarg; + break; + case 'c': + tokenCacheDir = optarg; + break; + case 'd': + debugMode = true; + break; + case 'e': + equivDbFile = optarg; + break; + case 'E': + entropyFile = optarg; + break; + 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; + break; + case 'T': + 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; + break; + default: + usage(argv[0]); + } + } + + // take no non-option arguments + if (optind < argc) + usage(argv[0]); + + // figure out the 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("%s started in debug mode", argv[0]); + } else { + Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS); + } + + // if we're not running as root in production mode, fail + // in debug mode, issue a warning + if (uid_t uid = getuid()) { +#if defined(NDEBUG) + Syslog::alert("Tried to run securityd as user %d: aborted", uid); + fprintf(stderr, "You are not allowed to run securityd\n"); + exit(1); +#else + 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 && getppid() != 1) { + if (!Daemon::incarnate(doFork)) + exit(1); // can't daemonize + + if (reExecute && !Daemon::executeSelf(argv)) + exit(1); // can't self-execute + } + + // 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); + + // 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(); + new KeychainPromptAclSubject::Maker(keychainAclDefault); + new PreAuthorizationAcls::OriginMaker(); + new PreAuthorizationAcls::SourceMaker(); + + // establish the code equivalents database + CodeSignatures codeSignatures(equivDbFile); + + // create the main server object and register it + Server server(authority, codeSignatures, bootstrapName); + + // Remember the primary service port to send signal events to + gMainServerPort = server.primaryServicePort(); + + // set server configuration from arguments, if specified + if (workerTimeout) + server.timeout(workerTimeout); + if (maxThreads) + server.maxThreads(maxThreads); + server.floatingThread(true); + server.waitForClients(waitForClients); + server.verbosity(verbose); + + // add the RNG seed timer +# if defined(NDEBUG) + EntropyManager entropy(server, entropyFile); +# else + if (getuid() == 0) new EntropyManager(server, entropyFile); +# endif + + // 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(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server); + + // create a monitor thread to watch for audit session events + AuditMonitor audits(gMainServerPort); + audits.run(); + + // 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"); + + // go + server.run(); + + // fell out of runloop (should not happen) + Syslog::alert("Aborting"); + return 1; +} + + +// +// Issue usage message and die +// +static void usage(const char *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); +} + + +// +// Translate strings (e.g. "conservative") into PCSCMonitor service levels +// +static PCSCMonitor::ServiceLevel scOptions(const char *optionString) +{ + if (optionString) + if (!strcmp(optionString, "off")) + return PCSCMonitor::forcedOff; + else if (!strcmp(optionString, "on")) + return PCSCMonitor::externalDaemon; + else if (!strcmp(optionString, "conservative")) + return PCSCMonitor::externalDaemon; + else if (!strcmp(optionString, "aggressive")) + return PCSCMonitor::externalDaemon; + else if (!strcmp(optionString, "external")) + return PCSCMonitor::externalDaemon; + else + usage("securityd"); + else + return PCSCMonitor::externalDaemon; +} + + +// +// 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 handleSignals(int sig) +{ + 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); +}