server.cpp
1 /* 2 * Copyright (c) 2000-2010,2013 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 // server - securityd main server object 27 // 28 #include <securityd_client/ucsp.h> // MIG ucsp service 29 #include "self.h" // MIG self service 30 #include <security_utilities/logging.h> 31 #include <security_cdsa_client/mdsclient.h> 32 #include "server.h" 33 #include "session.h" 34 #include "acls.h" 35 #include "notifications.h" 36 #include "child.h" 37 #include <mach/mach_error.h> 38 #include <security_utilities/ccaudit.h> 39 #include <security_utilities/casts.h> 40 41 #include "agentquery.h" 42 43 44 using namespace MachPlusPlus; 45 46 // 47 // Construct the server object 48 // 49 Server::Server(CodeSignatures &signatures, const char *bootstrapName) 50 : MachServer(bootstrapName), 51 mBootstrapName(bootstrapName), 52 mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule), 53 mCodeSignatures(signatures), 54 mVerbosity(0), 55 mWaitForClients(true), mShuttingDown(false) 56 { 57 // make me eternal (in the object mesh) 58 ref(); 59 60 #ifndef DARLING 61 // engage the subsidiary port handler for sleep notifications 62 add(sleepWatcher); 63 #endif 64 } 65 66 67 // 68 // Clean up the server object 69 // 70 Server::~Server() 71 { 72 //@@@ more later 73 } 74 75 76 // 77 // Locate a connection by reply port and make it the current connection 78 // of this thread. The connection will be marked busy, and can be accessed 79 // by calling Server::connection() [no argument] until it is released by 80 // calling Connection::endWork(). 81 // 82 Connection &Server::connection(mach_port_t port, audit_token_t &auditToken) 83 { 84 Server &server = active(); 85 StLock<Mutex> _(server); 86 Connection *conn = server.mConnections.get(port, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE); 87 conn->process().checkSession(auditToken); 88 active().mCurrentConnection() = conn; 89 conn->beginWork(auditToken); 90 return *conn; 91 } 92 93 Connection &Server::connection(bool tolerant) 94 { 95 Connection *conn = active().mCurrentConnection(); 96 assert(conn); // have to have one 97 if (!tolerant) 98 conn->checkWork(); 99 return *conn; 100 } 101 102 void Server::requestComplete(CSSM_RETURN &rcode) 103 { 104 Server &server = active(); 105 StLock<Mutex> lock(server); 106 // note: there may not be an active connection if connection setup failed 107 if (RefPointer<Connection> &conn = server.mCurrentConnection()) { 108 conn->endWork(rcode); 109 conn = NULL; 110 } 111 IFDUMPING("state", NodeCore::dumpAll()); 112 } 113 114 115 // 116 // Shorthand for "current" process and session. 117 // This is the process and session for the current connection. 118 // 119 Process &Server::process() 120 { 121 return connection().process(); 122 } 123 124 Session &Server::session() 125 { 126 return connection().process().session(); 127 } 128 129 RefPointer<Key> Server::key(KeyHandle key) 130 { 131 return U32HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE); 132 } 133 134 RefPointer<Database> Server::database(DbHandle db) 135 { 136 return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE); 137 } 138 139 RefPointer<KeychainDatabase> Server::keychain(DbHandle db) 140 { 141 return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE); 142 } 143 144 RefPointer<Database> Server::optionalDatabase(DbHandle db, bool persistent) 145 { 146 if (persistent && db != noDb) 147 return database(db); 148 else 149 return &process().localStore(); 150 } 151 152 153 // 154 // Locate an ACL bearer (database or key) by handle 155 // The handle might be used across IPC, so we clamp it accordingly 156 // 157 AclSource &Server::aclBearer(AclKind kind, U32HandleObject::Handle handle) 158 { 159 AclSource &bearer = U32HandleObject::find<AclSource>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE); 160 if (kind != bearer.acl().aclKind()) 161 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); 162 return bearer; 163 } 164 165 166 // 167 // Run the server. This will not return until the server is forced to exit. 168 // 169 void Server::run() 170 { 171 MachServer::run(0x10000, 172 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | 173 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)); 174 } 175 176 177 // 178 // Handle thread overflow. MachServer will call this if it has hit its thread 179 // limit and yet still needs another thread. 180 // 181 void Server::threadLimitReached(UInt32 limit) 182 { 183 Syslog::notice("securityd has reached its thread limit (%d) - service deadlock is possible", 184 (uint32_t) limit); 185 } 186 187 188 // 189 // The primary server run-loop function. 190 // Invokes the MIG-generated main dispatch function (ucsp_server), as well 191 // as the self-send dispatch (self_server). 192 // For debug builds, look up request names in a MIG-generated table 193 // for better debug-log messages. 194 // 195 boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *); 196 boolean_t self_server(mach_msg_header_t *, mach_msg_header_t *); 197 198 199 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) 200 { 201 return ucsp_server(in, out) || self_server(in, out); 202 } 203 204 205 // 206 // Set up a new Connection. This establishes the environment (process et al) as needed 207 // and registers a properly initialized Connection object to run with. 208 // Type indicates how "deep" we need to initialize (new session, process, or connection). 209 // Everything at and below that level is constructed. This is straight-forward except 210 // in the case of session re-initialization (see below). 211 // 212 void Server::setupConnection(ConnectLevel type, Port replyPort, Port taskPort, 213 const audit_token_t &auditToken, const ClientSetupInfo *info) 214 { 215 Security::CommonCriteria::AuditToken audit(auditToken); 216 217 // first, make or find the process based on task port 218 StLock<Mutex> _(*this); 219 RefPointer<Process> &proc = mProcesses[taskPort]; 220 if (proc && proc->session().sessionId() != audit.sessionId()) 221 proc->changeSession(audit.sessionId()); 222 if (proc && type == connectNewProcess) { 223 // the client has amnesia - reset it 224 assert(info); 225 proc->reset(taskPort, info, audit); 226 proc->changeSession(audit.sessionId()); 227 } 228 if (!proc) { 229 if (type == connectNewThread) // client error (or attack) 230 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 231 assert(info); 232 proc = new Process(taskPort, info, audit); 233 notifyIfDead(taskPort); 234 mPids[proc->pid()] = proc; 235 } 236 237 // now, establish a connection and register it in the server 238 Connection *connection = new Connection(*proc, replyPort); 239 if (mConnections.contains(replyPort)) // malicious re-entry attempt? 240 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); //@@@ error code? (client error) 241 mConnections[replyPort] = connection; 242 notifyIfDead(replyPort); 243 } 244 245 // 246 // Handling dead-port notifications. 247 // This receives DPNs for all kinds of ports we're interested in. 248 // 249 void Server::notifyDeadName(Port port) 250 { 251 // We need the lock to get a proper iterator on mConnections or mProcesses, 252 // but must release it before we call abort or kill, as these might take 253 // unbounded time, including calls out to token daemons etc. 254 255 StLock<Mutex> serverLock(*this); 256 257 // is it a connection? 258 PortMap<Connection>::iterator conIt = mConnections.find(port); 259 if (conIt != mConnections.end()) { 260 secinfo("SecServer", "%p dead connection %d", this, port.port()); 261 RefPointer<Connection> con = conIt->second; 262 mConnections.erase(conIt); 263 serverLock.unlock(); 264 return; 265 } 266 267 // is it a process? 268 PortMap<Process>::iterator procIt = mProcesses.find(port); 269 if (procIt != mProcesses.end()) { 270 secinfo("SecServer", "%p dead process %d", this, port.port()); 271 RefPointer<Process> proc = procIt->second; 272 mPids.erase(proc->pid()); 273 mProcesses.erase(procIt); 274 serverLock.unlock(); 275 // The kill may take some time; make sure there is a spare thread around 276 // to prevent deadlocks 277 StLock<MachServer, &Server::busy, &Server::idle> _(*this); 278 proc->kill(); 279 return; 280 } 281 282 // well, what IS IT?! 283 secnotice("server", "spurious dead port notification for port %d", port.port()); 284 } 285 286 287 // 288 // Handling no-senders notifications. 289 // This is currently only used for (subsidiary) service ports 290 // 291 void Server::notifyNoSenders(Port port, mach_port_mscount_t) 292 { 293 secinfo("SecServer", "%p dead session %d", this, port.port()); 294 } 295 296 297 // 298 // Handling signals. 299 // These are sent as Mach messages from ourselves to escape the limitations of 300 // the signal handler environment. 301 // 302 kern_return_t self_server_handleSignal(mach_port_t sport, 303 audit_token_t auditToken, int sig) 304 { 305 try { 306 secnotice("SecServer", "signal handled %d", sig); 307 if (audit_token_to_pid(auditToken) != getpid()) { 308 Syslog::error("handleSignal: received from someone other than myself"); 309 return KERN_SUCCESS; 310 } 311 switch (sig) { 312 case SIGCHLD: 313 ServerChild::checkChildren(); 314 break; 315 case SIGINT: 316 secnotice("SecServer", "shutdown due to SIGINT"); 317 Syslog::notice("securityd terminated due to SIGINT"); 318 _exit(0); 319 case SIGTERM: 320 Server::active().beginShutdown(); 321 break; 322 case SIGPIPE: 323 fprintf(stderr, "securityd ignoring SIGPIPE received"); 324 break; 325 326 #if defined(DEBUGDUMP) 327 case SIGUSR1: 328 NodeCore::dumpAll(); 329 break; 330 #endif //DEBUGDUMP 331 332 case SIGUSR2: 333 fprintf(stderr, "securityd ignoring SIGUSR2 received"); 334 break; 335 336 default: 337 assert(false); 338 } 339 } catch(...) { 340 secnotice("SecServer", "exception handling a signal (ignored)"); 341 } 342 return KERN_SUCCESS; 343 } 344 345 346 kern_return_t self_server_handleSession(mach_port_t sport, 347 audit_token_t auditToken, uint32_t event, uint64_t ident) 348 { 349 try { 350 if (audit_token_to_pid(auditToken) != getpid()) { 351 Syslog::error("handleSession: received from someone other than myself"); 352 return KERN_SUCCESS; 353 } 354 if (event == AUE_SESSION_END) 355 Session::destroy(int_cast<uint64_t, Session::SessionId>(ident)); 356 } catch(...) { 357 secnotice("SecServer", "exception handling a signal (ignored)"); 358 } 359 return KERN_SUCCESS; 360 } 361 362 363 // 364 // Notifier for system sleep events 365 // 366 void Server::SleepWatcher::systemWillSleep() 367 { 368 secnotice("SecServer", "%p will sleep", this); 369 Session::processSystemSleep(); 370 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) 371 (*it)->systemWillSleep(); 372 } 373 374 void Server::SleepWatcher::systemIsWaking() 375 { 376 secnotice("SecServer", "%p is waking", this); 377 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) 378 (*it)->systemIsWaking(); 379 } 380 381 void Server::SleepWatcher::systemWillPowerOn() 382 { 383 secnotice("SecServer", "%p will power on", this); 384 Server::active().longTermActivity(); 385 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) 386 (*it)->systemWillPowerOn(); 387 } 388 389 void Server::SleepWatcher::add(PowerWatcher *client) 390 { 391 assert(mPowerClients.find(client) == mPowerClients.end()); 392 mPowerClients.insert(client); 393 } 394 395 void Server::SleepWatcher::remove(PowerWatcher *client) 396 { 397 assert(mPowerClients.find(client) != mPowerClients.end()); 398 mPowerClients.erase(client); 399 } 400 401 402 // 403 // Expose the process/pid map to the outside 404 // 405 Process *Server::findPid(pid_t pid) const 406 { 407 PidMap::const_iterator it = mPids.find(pid); 408 return (it == mPids.end()) ? NULL : it->second; 409 } 410 411 412 // 413 // Set delayed shutdown mode 414 // 415 void Server::waitForClients(bool waiting) 416 { 417 mWaitForClients = waiting; 418 } 419 420 421 // 422 // Begin shutdown processing. 423 // We relinquish our primary state authority. From now on, we'll be 424 // kept alive (only) by our current clients. 425 // 426 static FILE *reportFile; 427 428 void Server::beginShutdown() 429 { 430 StLock<Mutex> _(*this); 431 if (!mWaitForClients) { 432 secnotice("SecServer", "%p shutting down now", this); 433 _exit(0); 434 } else { 435 if (!mShuttingDown) { 436 mShuttingDown = true; 437 Session::invalidateAuthHosts(); 438 secnotice("SecServer", "%p beginning shutdown", this); 439 shutdownReport(); // always tell me about residual clients... 440 if (verbosity() >= 2) { // ...and if we really care write to the log, too 441 reportFile = fopen("/var/log/securityd-shutdown.log", "w"); 442 shutdownReport_file(); 443 } 444 } 445 } 446 } 447 448 449 // 450 // During shutdown, we report residual clients to dtrace, and allow a state dump 451 // for debugging. 452 // We don't bother locking for the shuttingDown() check; it's a latching boolean 453 // and we'll be good enough without a lock. 454 // 455 void Server::eventDone() 456 { 457 StLock<Mutex> lock(*this); 458 if (this->shuttingDown()) { 459 shutdownReport(); 460 if (verbosity() >= 2) { 461 secnotice("SecServer", "shutting down with %ld processes", mProcesses.size()); 462 shutdownReport_file(); 463 } 464 } 465 } 466 467 void Server::shutdownReport() 468 { 469 PidMap mPidsCopy = PidMap(mPids); 470 secnotice("shutdown", "Residual clients count: %d", int(mPidsCopy.size())); 471 for (PidMap::const_iterator it = mPidsCopy.begin(); it != mPidsCopy.end(); ++it) { 472 secnotice("shutdown", "Residual client: %d", it->first); 473 } 474 } 475 476 void Server::shutdownReport_file() 477 { 478 time_t now; 479 time(&now); 480 fprintf(reportFile, "%.24s %d residual clients:\n", ctime(&now), int(mPids.size())); 481 for (PidMap::const_iterator it = mPids.begin(); it != mPids.end(); ++it) { 482 string path = it->second->getPath(); 483 fprintf(reportFile, " %s (%d)\n", path.c_str(), it->first); 484 } 485 fprintf(reportFile, "\n"); 486 fflush(reportFile); 487 } 488 489 bool Server::inDarkWake() 490 { 491 bool inDarkWake = IOPMIsADarkWake(IOPMConnectionGetSystemCapabilities()); 492 if (inDarkWake) { 493 secnotice("SecServer", "Server::inDarkWake returned inDarkWake"); 494 } 495 return inDarkWake; 496 } 497 498 // 499 // Initialize the CSSM/MDS subsystem. 500 // This was once done lazily on demand. These days, we are setting up the 501 // system MDS here, and CSSM is pretty much always needed, so this is called 502 // early during program startup. Do note that the server may not (yet) be running. 503 // 504 void Server::loadCssm(bool mdsIsInstalled) 505 { 506 try { 507 508 if (!mCssm->isActive()) { 509 StLock<Mutex> _(*this); 510 xpc_transaction_begin(); 511 if (!mCssm->isActive()) { 512 if (!mdsIsInstalled) { // non-system securityd instance should not reinitialize MDS 513 secnotice("SecServer", "Installing MDS"); 514 IFDEBUG(if (geteuid() == 0)) 515 MDSClient::mds().install(); 516 } 517 secnotice("SecServer", "CSSM initializing"); 518 mCssm->init(); 519 mCSP->attach(); 520 secnotice("SecServer", "CSSM ready with CSP %s", mCSP->guid().toString().c_str()); 521 } 522 xpc_transaction_end(); 523 } 524 } catch (const UnixError& err) { 525 secerror("load cssm failed: %s", err.what()); 526 if (err.unixError() == ENOSPC) { 527 _exit(1); 528 } else { 529 abort(); 530 } 531 } catch (const MacOSError& err) { 532 secerror("load cssm failed: %s", err.what()); 533 abort(); 534 } catch (const CommonError& err) { 535 secerror("load cssm failed: %d/%d", (int)err.osStatus(), err.unixError()); 536 abort(); 537 } catch (const std::exception& err) { 538 secerror("load cssm failed: %s", err.what()); 539 abort(); 540 } 541 } 542 543 544 // 545 // LongtermActivity/lock combo 546 // 547 LongtermStLock::LongtermStLock(Mutex &lck) 548 : StLock<Mutex>(lck, false) // don't take the lock yet 549 { 550 if (lck.tryLock()) { // uncontested 551 this->mActive = true; 552 } else { // contested - need backup thread 553 Server::active().longTermActivity(); 554 this->lock(); 555 } 556 }