2 * Copyright (c) 2000-2010,2013 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // server - securityd main server object
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>
35 #include "notifications.h"
37 #include <mach/mach_error.h>
38 #include <security_utilities/ccaudit.h>
39 #include <security_utilities/casts.h>
41 #include "agentquery.h"
44 using namespace MachPlusPlus
;
47 // Construct the server object
49 Server::Server(CodeSignatures
&signatures
, const char *bootstrapName
)
50 : MachServer(bootstrapName
),
51 mBootstrapName(bootstrapName
),
52 mCSPModule(gGuidAppleCSP
, mCssm
), mCSP(mCSPModule
),
53 mCodeSignatures(signatures
),
55 mWaitForClients(true), mShuttingDown(false)
57 // make me eternal (in the object mesh)
60 // engage the subsidiary port handler for sleep notifications
66 // Clean up the server object
75 // Locate a connection by reply port and make it the current connection
76 // of this thread. The connection will be marked busy, and can be accessed
77 // by calling Server::connection() [no argument] until it is released by
78 // calling Connection::endWork().
80 Connection
&Server::connection(mach_port_t port
, audit_token_t
&auditToken
)
82 Server
&server
= active();
83 StLock
<Mutex
> _(server
);
84 Connection
*conn
= server
.mConnections
.get(port
, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE
);
85 conn
->process().checkSession(auditToken
);
86 active().mCurrentConnection() = conn
;
87 conn
->beginWork(auditToken
);
91 Connection
&Server::connection(bool tolerant
)
93 Connection
*conn
= active().mCurrentConnection();
94 assert(conn
); // have to have one
100 void Server::requestComplete(CSSM_RETURN
&rcode
)
102 Server
&server
= active();
103 StLock
<Mutex
> lock(server
);
104 // note: there may not be an active connection if connection setup failed
105 if (RefPointer
<Connection
> &conn
= server
.mCurrentConnection()) {
106 conn
->endWork(rcode
);
109 IFDUMPING("state", NodeCore::dumpAll());
114 // Shorthand for "current" process and session.
115 // This is the process and session for the current connection.
117 Process
&Server::process()
119 return connection().process();
122 Session
&Server::session()
124 return connection().process().session();
127 RefPointer
<Key
> Server::key(KeyHandle key
)
129 return U32HandleObject::findRef
<Key
>(key
, CSSMERR_CSP_INVALID_KEY_REFERENCE
);
132 RefPointer
<Database
> Server::database(DbHandle db
)
134 return find
<Database
>(db
, CSSMERR_DL_INVALID_DB_HANDLE
);
137 RefPointer
<KeychainDatabase
> Server::keychain(DbHandle db
)
139 return find
<KeychainDatabase
>(db
, CSSMERR_DL_INVALID_DB_HANDLE
);
142 RefPointer
<Database
> Server::optionalDatabase(DbHandle db
, bool persistent
)
144 if (persistent
&& db
!= noDb
)
147 return &process().localStore();
152 // Locate an ACL bearer (database or key) by handle
153 // The handle might be used across IPC, so we clamp it accordingly
155 AclSource
&Server::aclBearer(AclKind kind
, U32HandleObject::Handle handle
)
157 AclSource
&bearer
= U32HandleObject::find
<AclSource
>(handle
, CSSMERR_CSSM_INVALID_ADDIN_HANDLE
);
158 if (kind
!= bearer
.acl().aclKind())
159 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
);
165 // Run the server. This will not return until the server is forced to exit.
169 MachServer::run(0x10000,
170 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) |
171 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
));
176 // Handle thread overflow. MachServer will call this if it has hit its thread
177 // limit and yet still needs another thread.
179 void Server::threadLimitReached(UInt32 limit
)
181 Syslog::notice("securityd has reached its thread limit (%d) - service deadlock is possible",
187 // The primary server run-loop function.
188 // Invokes the MIG-generated main dispatch function (ucsp_server), as well
189 // as the self-send dispatch (self_server).
190 // For debug builds, look up request names in a MIG-generated table
191 // for better debug-log messages.
193 boolean_t
ucsp_server(mach_msg_header_t
*, mach_msg_header_t
*);
194 boolean_t
self_server(mach_msg_header_t
*, mach_msg_header_t
*);
197 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
199 return ucsp_server(in
, out
) || self_server(in
, out
);
204 // Set up a new Connection. This establishes the environment (process et al) as needed
205 // and registers a properly initialized Connection object to run with.
206 // Type indicates how "deep" we need to initialize (new session, process, or connection).
207 // Everything at and below that level is constructed. This is straight-forward except
208 // in the case of session re-initialization (see below).
210 void Server::setupConnection(ConnectLevel type
, Port replyPort
, Port taskPort
,
211 const audit_token_t
&auditToken
, const ClientSetupInfo
*info
)
213 Security::CommonCriteria::AuditToken
audit(auditToken
);
215 // first, make or find the process based on task port
216 StLock
<Mutex
> _(*this);
217 RefPointer
<Process
> &proc
= mProcesses
[taskPort
];
218 if (proc
&& proc
->session().sessionId() != audit
.sessionId())
219 proc
->changeSession(audit
.sessionId());
220 if (proc
&& type
== connectNewProcess
) {
221 // the client has amnesia - reset it
223 proc
->reset(taskPort
, info
, audit
);
224 proc
->changeSession(audit
.sessionId());
227 if (type
== connectNewThread
) // client error (or attack)
228 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
230 proc
= new Process(taskPort
, info
, audit
);
231 notifyIfDead(taskPort
);
232 mPids
[proc
->pid()] = proc
;
235 // now, establish a connection and register it in the server
236 Connection
*connection
= new Connection(*proc
, replyPort
);
237 if (mConnections
.contains(replyPort
)) // malicious re-entry attempt?
238 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ error code? (client error)
239 mConnections
[replyPort
] = connection
;
240 notifyIfDead(replyPort
);
244 // Handling dead-port notifications.
245 // This receives DPNs for all kinds of ports we're interested in.
247 void Server::notifyDeadName(Port port
)
249 // We need the lock to get a proper iterator on mConnections or mProcesses,
250 // but must release it before we call abort or kill, as these might take
251 // unbounded time, including calls out to token daemons etc.
253 StLock
<Mutex
> serverLock(*this);
255 // is it a connection?
256 PortMap
<Connection
>::iterator conIt
= mConnections
.find(port
);
257 if (conIt
!= mConnections
.end()) {
258 secinfo("SecServer", "%p dead connection %d", this, port
.port());
259 RefPointer
<Connection
> con
= conIt
->second
;
260 mConnections
.erase(conIt
);
266 PortMap
<Process
>::iterator procIt
= mProcesses
.find(port
);
267 if (procIt
!= mProcesses
.end()) {
268 secinfo("SecServer", "%p dead process %d", this, port
.port());
269 RefPointer
<Process
> proc
= procIt
->second
;
270 mPids
.erase(proc
->pid());
271 mProcesses
.erase(procIt
);
273 // The kill may take some time; make sure there is a spare thread around
274 // to prevent deadlocks
275 StLock
<MachServer
, &Server::busy
, &Server::idle
> _(*this);
280 // well, what IS IT?!
281 secnotice("server", "spurious dead port notification for port %d", port
.port());
286 // Handling no-senders notifications.
287 // This is currently only used for (subsidiary) service ports
289 void Server::notifyNoSenders(Port port
, mach_port_mscount_t
)
291 secinfo("SecServer", "%p dead session %d", this, port
.port());
297 // These are sent as Mach messages from ourselves to escape the limitations of
298 // the signal handler environment.
300 kern_return_t
self_server_handleSignal(mach_port_t sport
,
301 mach_port_t taskPort
, int sig
)
304 secnotice("SecServer", "signal handled %d", sig
);
305 if (taskPort
!= mach_task_self()) {
306 Syslog::error("handleSignal: received from someone other than myself");
307 mach_port_deallocate(mach_task_self(), taskPort
);
312 ServerChild::checkChildren();
315 secnotice("SecServer", "shutdown due to SIGINT");
316 Syslog::notice("securityd terminated due to SIGINT");
319 Server::active().beginShutdown();
322 fprintf(stderr
, "securityd ignoring SIGPIPE received");
325 #if defined(DEBUGDUMP)
332 fprintf(stderr
, "securityd ignoring SIGUSR2 received");
339 secnotice("SecServer", "exception handling a signal (ignored)");
341 mach_port_deallocate(mach_task_self(), taskPort
);
346 kern_return_t
self_server_handleSession(mach_port_t sport
,
347 mach_port_t taskPort
, uint32_t event
, uint64_t ident
)
350 if (taskPort
!= mach_task_self()) {
351 Syslog::error("handleSession: received from someone other than myself");
352 mach_port_deallocate(mach_task_self(), taskPort
);
355 if (event
== AUE_SESSION_END
)
356 Session::destroy(int_cast
<uint64_t, Session::SessionId
>(ident
));
358 secnotice("SecServer", "exception handling a signal (ignored)");
360 mach_port_deallocate(mach_task_self(), taskPort
);
366 // Notifier for system sleep events
368 void Server::SleepWatcher::systemWillSleep()
370 secnotice("SecServer", "%p will sleep", this);
371 Session::processSystemSleep();
372 for (set
<PowerWatcher
*>::const_iterator it
= mPowerClients
.begin(); it
!= mPowerClients
.end(); it
++)
373 (*it
)->systemWillSleep();
376 void Server::SleepWatcher::systemIsWaking()
378 secnotice("SecServer", "%p is waking", this);
379 for (set
<PowerWatcher
*>::const_iterator it
= mPowerClients
.begin(); it
!= mPowerClients
.end(); it
++)
380 (*it
)->systemIsWaking();
383 void Server::SleepWatcher::systemWillPowerOn()
385 secnotice("SecServer", "%p will power on", this);
386 Server::active().longTermActivity();
387 for (set
<PowerWatcher
*>::const_iterator it
= mPowerClients
.begin(); it
!= mPowerClients
.end(); it
++)
388 (*it
)->systemWillPowerOn();
391 void Server::SleepWatcher::add(PowerWatcher
*client
)
393 assert(mPowerClients
.find(client
) == mPowerClients
.end());
394 mPowerClients
.insert(client
);
397 void Server::SleepWatcher::remove(PowerWatcher
*client
)
399 assert(mPowerClients
.find(client
) != mPowerClients
.end());
400 mPowerClients
.erase(client
);
405 // Expose the process/pid map to the outside
407 Process
*Server::findPid(pid_t pid
) const
409 PidMap::const_iterator it
= mPids
.find(pid
);
410 return (it
== mPids
.end()) ? NULL
: it
->second
;
415 // Set delayed shutdown mode
417 void Server::waitForClients(bool waiting
)
419 mWaitForClients
= waiting
;
424 // Begin shutdown processing.
425 // We relinquish our primary state authority. From now on, we'll be
426 // kept alive (only) by our current clients.
428 static FILE *reportFile
;
430 void Server::beginShutdown()
432 StLock
<Mutex
> _(*this);
433 if (!mWaitForClients
) {
434 secnotice("SecServer", "%p shutting down now", this);
437 if (!mShuttingDown
) {
438 mShuttingDown
= true;
439 Session::invalidateAuthHosts();
440 secnotice("SecServer", "%p beginning shutdown", this);
441 shutdownReport(); // always tell me about residual clients...
442 if (verbosity() >= 2) { // ...and if we really care write to the log, too
443 reportFile
= fopen("/var/log/securityd-shutdown.log", "w");
444 shutdownReport_file();
452 // During shutdown, we report residual clients to dtrace, and allow a state dump
454 // We don't bother locking for the shuttingDown() check; it's a latching boolean
455 // and we'll be good enough without a lock.
457 void Server::eventDone()
459 StLock
<Mutex
> lock(*this);
460 if (this->shuttingDown()) {
462 if (verbosity() >= 2) {
463 secnotice("SecServer", "shutting down with %ld processes", mProcesses
.size());
464 shutdownReport_file();
469 void Server::shutdownReport()
471 PidMap mPidsCopy
= PidMap(mPids
);
472 secnotice("shutdown", "Residual clients count: %d", int(mPidsCopy
.size()));
473 for (PidMap::const_iterator it
= mPidsCopy
.begin(); it
!= mPidsCopy
.end(); ++it
) {
474 secnotice("shutdown", "Residual client: %d", it
->first
);
478 void Server::shutdownReport_file()
482 fprintf(reportFile
, "%.24s %d residual clients:\n", ctime(&now
), int(mPids
.size()));
483 for (PidMap::const_iterator it
= mPids
.begin(); it
!= mPids
.end(); ++it
) {
484 string path
= it
->second
->getPath();
485 fprintf(reportFile
, " %s (%d)\n", path
.c_str(), it
->first
);
487 fprintf(reportFile
, "\n");
491 bool Server::inDarkWake()
493 bool inDarkWake
= IOPMIsADarkWake(IOPMConnectionGetSystemCapabilities());
495 secnotice("SecServer", "Server::inDarkWake returned inDarkWake");
501 // Initialize the CSSM/MDS subsystem.
502 // This was once done lazily on demand. These days, we are setting up the
503 // system MDS here, and CSSM is pretty much always needed, so this is called
504 // early during program startup. Do note that the server may not (yet) be running.
506 void Server::loadCssm(bool mdsIsInstalled
)
510 if (!mCssm
->isActive()) {
511 StLock
<Mutex
> _(*this);
512 xpc_transaction_begin();
513 if (!mCssm
->isActive()) {
514 if (!mdsIsInstalled
) { // non-system securityd instance should not reinitialize MDS
515 secnotice("SecServer", "Installing MDS");
516 IFDEBUG(if (geteuid() == 0))
517 MDSClient::mds().install();
519 secnotice("SecServer", "CSSM initializing");
522 secnotice("SecServer", "CSSM ready with CSP %s", mCSP
->guid().toString().c_str());
524 xpc_transaction_end();
526 } catch (const UnixError
& err
) {
527 secerror("load cssm failed: %s", err
.what());
528 if (err
.unixError() == ENOSPC
) {
533 } catch (const MacOSError
& err
) {
534 secerror("load cssm failed: %s", err
.what());
536 } catch (const CommonError
& err
) {
537 secerror("load cssm failed: %d/%d", (int)err
.osStatus(), err
.unixError());
539 } catch (const std::exception
& err
) {
540 secerror("load cssm failed: %s", err
.what());
547 // LongtermActivity/lock combo
549 LongtermStLock::LongtermStLock(Mutex
&lck
)
550 : StLock
<Mutex
>(lck
, false) // don't take the lock yet
552 if (lck
.tryLock()) { // uncontested
553 this->mActive
= true;
554 } else { // contested - need backup thread
555 Server::active().longTermActivity();