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