main.cpp
1 /* 2 * Copyright (c) 2000-2009,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25 // 26 // securityd - Apple security services daemon. 27 // 28 #include <securityd_client/ucsp.h> 29 30 #include "server.h" 31 #include "session.h" 32 #include "notifications.h" 33 #include "auditevents.h" 34 #include "self.h" 35 #include "util.h" 36 37 #include <security_utilities/daemon.h> 38 #include <security_utilities/machserver.h> 39 #include <security_utilities/logging.h> 40 41 #include <Security/SecKeychainPriv.h> 42 43 #include <unistd.h> 44 #include <sys/types.h> 45 #include <signal.h> 46 #include <syslog.h> 47 48 // ACL subject types (their makers are instantiated here) 49 #include <security_cdsa_utilities/acl_any.h> 50 #include <security_cdsa_utilities/acl_password.h> 51 #include <security_cdsa_utilities/acl_prompted.h> 52 #include <security_cdsa_utilities/acl_protectedpw.h> 53 #include <security_cdsa_utilities/acl_threshold.h> 54 #include <security_cdsa_utilities/acl_codesigning.h> 55 #include <security_cdsa_utilities/acl_process.h> 56 #include <security_cdsa_utilities/acl_comment.h> 57 #include <security_cdsa_utilities/acl_preauth.h> 58 #include "acl_keychain.h" 59 #include "acl_partition.h" 60 61 #include <sandbox.h> 62 63 // 64 // Local functions of the main program driver 65 // 66 static void usage(const char *me) __attribute__((noreturn)); 67 static void handleSignals(int sig); 68 69 static Port gMainServerPort; 70 71 72 // 73 // Main driver 74 // 75 int main(int argc, char *argv[]) 76 { 77 DisableLocalization(); 78 79 // clear the umask - we know what we're doing 80 secnotice("SecServer", "starting umask was 0%o", ::umask(0)); 81 ::umask(0); 82 83 // tell the keychain (client) layer to turn off the server interface 84 SecKeychainSetServerMode(); 85 86 const char *params[] = {"LEGACY_TOKENS_ENABLED", "NO", NULL}; 87 char* errorbuf = NULL; 88 if (sandbox_init_with_parameters("com.apple.securityd", SANDBOX_NAMED, params, &errorbuf)) { 89 seccritical("SecServer: unable to enter sandbox: %{public}s", errorbuf); 90 if (errorbuf) { 91 sandbox_free_error(errorbuf); 92 } 93 exit(1); 94 } else { 95 secnotice("SecServer", "entered sandbox"); 96 } 97 98 // program arguments (preset to defaults) 99 bool debugMode = false; 100 int workerTimeout = 0; 101 int maxThreads = 0; 102 bool waitForClients = true; 103 bool mdsIsInstalled = false; 104 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED; 105 unsigned int verbose = 0; 106 107 // check for the Installation-DVD environment and modify some default arguments if found 108 if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists 109 secnotice("SecServer", "starting in installmode"); 110 } 111 112 // parse command line arguments 113 extern char *optarg; 114 extern int optind; 115 int arg; 116 while ((arg = getopt(argc, argv, ":dE:im:t:T:uvW")) != -1) { 117 switch (arg) { 118 case 'd': 119 debugMode = true; 120 break; 121 case 'E': 122 /* was entropyFile, kept to preserve ABI */ 123 break; 124 case 'i': 125 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID; 126 break; 127 case 'm': 128 mdsIsInstalled = true; 129 break; 130 case 't': 131 if ((maxThreads = atoi(optarg)) < 0) 132 maxThreads = 0; 133 break; 134 case 'T': 135 if ((workerTimeout = atoi(optarg)) < 0) 136 workerTimeout = 0; 137 break; 138 case 'W': 139 waitForClients = false; 140 break; 141 case 'u': 142 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED; 143 break; 144 case 'v': 145 verbose++; 146 break; 147 default: 148 usage(argv[0]); 149 } 150 } 151 152 // take no non-option arguments 153 if (optind < argc) { 154 usage(argv[0]); 155 } 156 157 const char *bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME; 158 const char* messagingName = SharedMemoryCommon::kDefaultSecurityMessagesName; 159 160 // configure logging first 161 if (debugMode) { 162 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR); 163 Syslog::notice("%s started in debug mode", argv[0]); 164 } else { 165 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS); 166 } 167 168 // if we're not running as root in production mode, fail 169 // in debug mode, issue a warning 170 if (uid_t uid = getuid()) { 171 #if defined(NDEBUG) 172 Syslog::alert("Tried to run securityd as user %d: aborted", uid); 173 fprintf(stderr, "You are not allowed to run securityd\n"); 174 exit(1); 175 #else 176 fprintf(stderr, "securityd is unprivileged (uid=%d); some features may not work.\n", uid); 177 #endif //NDEBUG 178 } 179 180 // turn into a properly diabolical daemon unless debugMode is on 181 if (!debugMode && getppid() != 1 && !Daemon::incarnate(false)) { 182 exit(1); // can't daemonize 183 } 184 185 // arm signal handlers; code below may generate signals we want to see 186 if (signal(SIGCHLD, handleSignals) == SIG_ERR 187 || signal(SIGINT, handleSignals) == SIG_ERR 188 || signal(SIGTERM, handleSignals) == SIG_ERR 189 || signal(SIGPIPE, handleSignals) == SIG_ERR 190 #if !defined(NDEBUG) 191 || signal(SIGUSR1, handleSignals) == SIG_ERR 192 #endif //NDEBUG 193 || signal(SIGUSR2, handleSignals) == SIG_ERR) { 194 perror("signal"); 195 exit(1); 196 } 197 198 // The clang static analyzer isn't a big fan of our "object creation hooks object into global pointer graph" model. 199 // Tell it not to worry. 200 #ifndef __clang_analyzer__ 201 // introduce all supported ACL subject types 202 new AnyAclSubject::Maker(); 203 new PasswordAclSubject::Maker(); 204 new ProtectedPasswordAclSubject::Maker(); 205 new PromptedAclSubject::Maker(); 206 new ThresholdAclSubject::Maker(); 207 new CommentAclSubject::Maker(); 208 new ProcessAclSubject::Maker(); 209 new CodeSignatureAclSubject::Maker(); 210 new KeychainPromptAclSubject::Maker(keychainAclDefault); 211 new PartitionAclSubject::Maker(); 212 new PreAuthorizationAcls::OriginMaker(); 213 new PreAuthorizationAcls::SourceMaker(); 214 #endif 215 // establish the code equivalents database 216 CodeSignatures codeSignatures; 217 218 219 // create the main server object and register it 220 Server server(codeSignatures, bootstrapName); 221 222 // Remember the primary service port to send signal events to 223 gMainServerPort = server.primaryServicePort(); 224 225 // set server configuration from arguments, if specified 226 if (workerTimeout) 227 server.timeout(workerTimeout); 228 if (maxThreads) 229 server.maxThreads(maxThreads); 230 server.floatingThread(true); 231 server.waitForClients(waitForClients); 232 server.verbosity(verbose); 233 234 // create the RootSession object (if -d, give it graphics and tty attributes) 235 RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server); 236 237 // create a monitor thread to watch for audit session events 238 AuditMonitor audits(gMainServerPort); 239 audits.threadRun(); 240 241 // install MDS (if needed) and initialize the local CSSM 242 server.loadCssm(mdsIsInstalled); 243 244 #ifndef __clang_analyzer__ 245 // create the shared memory notification hub 246 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize); 247 #endif 248 249 250 // okay, we're ready to roll 251 secnotice("SecServer", "Entering service as %s", (char*)bootstrapName); 252 Syslog::notice("Entering service"); 253 254 // go 255 server.run(); 256 257 // fell out of runloop (should not happen) 258 Syslog::alert("Aborting"); 259 return 1; 260 } 261 262 263 // 264 // Issue usage message and die 265 // 266 static void usage(const char *me) 267 { 268 fprintf(stderr, "Usage: %s [-dwX]" 269 "\n\t[-e equivDatabase] path to code equivalence database" 270 "\n\t[-t maxthreads] [-T threadTimeout] server thread control" 271 "\n", me); 272 exit(2); 273 } 274 275 const CFStringRef kTKSmartCardPreferencesDomain = CFSTR("com.apple.security.smartcard"); 276 const CFStringRef kTKLegacyTokendPreferencesKey = CFSTR("Legacy"); 277 278 // 279 // Handle signals. 280 // We send ourselves a message (through the "self" service), so actual 281 // actions happen on the normal event loop path. Note that another thread 282 // may be picking up the message immediately. 283 // 284 static void handleSignals(int sig) 285 { 286 (void)self_client_handleSignal(gMainServerPort, sig); 287 }