2 * Copyright (c) 2000-2004,2009 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 "pcscmonitor.h"
41 #include "agentquery.h"
44 using namespace MachPlusPlus
;
47 // Construct an Authority
49 Authority::Authority(const char *configFile
)
50 : Authorization::Engine(configFile
)
54 Authority::~Authority()
60 // Construct the server object
62 Server::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 mAudit(geteuid(), getpid()),
70 mWaitForClients(true), mShuttingDown(false)
72 // make me eternal (in the object mesh)
75 mAudit
.registerSession();
77 // engage the subsidiary port handler for sleep notifications
83 // Clean up the server object
92 // Locate a connection by reply port and make it the current connection
93 // of this thread. The connection will be marked busy, and can be accessed
94 // by calling Server::connection() [no argument] until it is released by
95 // calling Connection::endWork().
97 Connection
&Server::connection(mach_port_t port
, audit_token_t
&auditToken
)
99 Server
&server
= active();
100 StLock
<Mutex
> _(server
);
101 Connection
*conn
= server
.mConnections
.get(port
, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE
);
102 active().mCurrentConnection() = conn
;
103 conn
->beginWork(auditToken
);
107 Connection
&Server::connection(bool tolerant
)
109 Connection
*conn
= active().mCurrentConnection();
110 assert(conn
); // have to have one
116 void Server::requestComplete(CSSM_RETURN
&rcode
)
118 // note: there may not be an active connection if connection setup failed
119 if (RefPointer
<Connection
> &conn
= active().mCurrentConnection()) {
120 conn
->endWork(rcode
);
123 IFDUMPING("state", NodeCore::dumpAll());
128 // Shorthand for "current" process and session.
129 // This is the process and session for the current connection.
131 Process
&Server::process()
133 return connection().process();
136 Session
&Server::session()
138 return connection().process().session();
141 RefPointer
<Key
> Server::key(KeyHandle key
)
143 return U32HandleObject::findRef
<Key
>(key
, CSSMERR_CSP_INVALID_KEY_REFERENCE
);
146 RefPointer
<Database
> Server::database(DbHandle db
)
148 return find
<Database
>(db
, CSSMERR_DL_INVALID_DB_HANDLE
);
151 RefPointer
<KeychainDatabase
> Server::keychain(DbHandle db
)
153 return find
<KeychainDatabase
>(db
, CSSMERR_DL_INVALID_DB_HANDLE
);
156 RefPointer
<Database
> Server::optionalDatabase(DbHandle db
, bool persistent
)
158 if (persistent
&& db
!= noDb
)
161 return &process().localStore();
166 // Locate an ACL bearer (database or key) by handle
167 // The handle might be used across IPC, so we clamp it accordingly
169 AclSource
&Server::aclBearer(AclKind kind
, U32HandleObject::Handle handle
)
171 AclSource
&bearer
= U32HandleObject::find
<AclSource
>(handle
, CSSMERR_CSSM_INVALID_ADDIN_HANDLE
);
172 if (kind
!= bearer
.acl().aclKind())
173 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
);
179 // Run the server. This will not return until the server is forced to exit.
183 MachServer::run(0x10000,
184 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) |
185 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
));
190 // Handle thread overflow. MachServer will call this if it has hit its thread
191 // limit and yet still needs another thread.
193 void Server::threadLimitReached(UInt32 limit
)
195 Syslog::notice("securityd has reached its thread limit (%ld) - service deadlock is possible",
201 // The primary server run-loop function.
202 // Invokes the MIG-generated main dispatch function (ucsp_server), as well
203 // as the self-send dispatch (self_server).
204 // For debug builds, look up request names in a MIG-generated table
205 // for better debug-log messages.
207 boolean_t
ucsp_server(mach_msg_header_t
*, mach_msg_header_t
*);
208 boolean_t
self_server(mach_msg_header_t
*, mach_msg_header_t
*);
211 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
213 return ucsp_server(in
, out
) || self_server(in
, out
);
218 // Set up a new Connection. This establishes the environment (process et al) as needed
219 // and registers a properly initialized Connection object to run with.
220 // Type indicates how "deep" we need to initialize (new session, process, or connection).
221 // Everything at and below that level is constructed. This is straight-forward except
222 // in the case of session re-initialization (see below).
224 void Server::setupConnection(ConnectLevel type
, Port servicePort
, Port replyPort
, Port taskPort
,
225 const audit_token_t
&auditToken
, const ClientSetupInfo
*info
, const char *identity
)
227 // first, make or find the process based on task port
228 StLock
<Mutex
> _(*this);
229 RefPointer
<Process
> &proc
= mProcesses
[taskPort
];
230 if (type
== connectNewSession
&& proc
) {
231 // The client has talked to us before and now wants to create a new session.
232 proc
->changeSession(servicePort
);
234 if (proc
&& type
== connectNewProcess
) {
235 // the client has amnesia - reset it
236 assert(info
&& identity
);
237 proc
->reset(servicePort
, taskPort
, info
, identity
, AuditToken(auditToken
));
238 proc
->changeSession(servicePort
);
241 if (type
== connectNewThread
) // client error (or attack)
242 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
243 assert(info
&& identity
);
244 proc
= new Process(servicePort
, taskPort
, info
, identity
, AuditToken(auditToken
));
245 notifyIfDead(taskPort
);
246 mPids
[proc
->pid()] = proc
;
249 // now, establish a connection and register it in the server
250 Connection
*connection
= new Connection(*proc
, replyPort
);
251 if (mConnections
.contains(replyPort
)) // malicious re-entry attempt?
252 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ error code? (client error)
253 mConnections
[replyPort
] = connection
;
254 notifyIfDead(replyPort
);
259 // Synchronously end a Connection.
260 // This is due to a request from the client, so no thread races are possible.
261 // In practice, this is optional since the DPN for the client thread reply port
262 // will destroy the connection anyway when the thread dies.
264 void Server::endConnection(Port replyPort
)
266 StLock
<Mutex
> _(*this);
267 PortMap
<Connection
>::iterator it
= mConnections
.find(replyPort
);
268 assert(it
!= mConnections
.end());
269 it
->second
->terminate();
270 mConnections
.erase(it
);
274 // Handling dead-port notifications.
275 // This receives DPNs for all kinds of ports we're interested in.
277 void Server::notifyDeadName(Port port
)
279 // We need the lock to get a proper iterator on mConnections or mProcesses,
280 // but must release it before we call abort or kill, as these might also
281 // need the server lock
283 StLock
<Mutex
> serverLock(*this);
284 secdebug("SSports", "port %d is dead", port
.port());
286 // is it a connection?
287 PortMap
<Connection
>::iterator conIt
= mConnections
.find(port
);
288 if (conIt
!= mConnections
.end()) {
289 SECURITYD_PORTS_DEAD_CONNECTION(port
);
290 RefPointer
<Connection
> con
= conIt
->second
;
291 mConnections
.erase(conIt
);
298 PortMap
<Process
>::iterator procIt
= mProcesses
.find(port
);
299 if (procIt
!= mProcesses
.end()) {
300 SECURITYD_PORTS_DEAD_PROCESS(port
);
301 RefPointer
<Process
> proc
= procIt
->second
;
302 mPids
.erase(proc
->pid());
303 mProcesses
.erase(procIt
);
305 // The kill may take some time; make sure there is a spare thread around
306 // to prevent deadlocks
307 StLock
<MachServer
, &Server::busy
, &Server::idle
> _(*this);
312 // well, what IS IT?!
313 SECURITYD_PORTS_DEAD_ORPHAN(port
);
314 secdebug("server", "spurious dead port notification for port %d", port
.port());
319 // Handling no-senders notifications.
320 // This is currently only used for (subsidiary) service ports
322 void Server::notifyNoSenders(Port port
, mach_port_mscount_t
)
324 SECURITYD_PORTS_DEAD_SESSION(port
);
325 secdebug("SSports", "port %d no senders", port
.port());
326 Session::destroy(port
);
332 // These are sent as Mach messages from ourselves to escape the limitations of
333 // the signal handler environment.
335 kern_return_t
self_server_handleSignal(mach_port_t sport
,
336 mach_port_t taskPort
, int sig
)
339 SECURITYD_SIGNAL_HANDLED(sig
);
340 if (taskPort
!= mach_task_self()) {
341 Syslog::error("handleSignal: received from someone other than myself");
346 ServerChild::checkChildren();
349 SECURITYD_SHUTDOWN_NOW();
350 Syslog::notice("securityd terminated due to SIGINT");
353 Server::active().beginShutdown();
356 fprintf(stderr
, "securityd ignoring SIGPIPE received");
359 #if defined(DEBUGDUMP)
367 extern PCSCMonitor
*gPCSC
;
368 gPCSC
->startSoftTokens();
376 secdebug("SS", "exception handling a signal (ignored)");
378 mach_port_deallocate(mach_task_self(), taskPort
);
384 // Notifier for system sleep events
386 void Server::SleepWatcher::systemWillSleep()
388 SECURITYD_POWER_SLEEP();
389 Session::processSystemSleep();
390 for (set
<PowerWatcher
*>::const_iterator it
= mPowerClients
.begin(); it
!= mPowerClients
.end(); it
++)
391 (*it
)->systemWillSleep();
394 void Server::SleepWatcher::systemIsWaking()
396 SECURITYD_POWER_WAKE();
397 for (set
<PowerWatcher
*>::const_iterator it
= mPowerClients
.begin(); it
!= mPowerClients
.end(); it
++)
398 (*it
)->systemIsWaking();
401 void Server::SleepWatcher::systemWillPowerOn()
403 SECURITYD_POWER_ON();
404 Server::active().longTermActivity();
405 for (set
<PowerWatcher
*>::const_iterator it
= mPowerClients
.begin(); it
!= mPowerClients
.end(); it
++)
406 (*it
)->systemWillPowerOn();
409 void Server::SleepWatcher::add(PowerWatcher
*client
)
411 assert(mPowerClients
.find(client
) == mPowerClients
.end());
412 mPowerClients
.insert(client
);
415 void Server::SleepWatcher::remove(PowerWatcher
*client
)
417 assert(mPowerClients
.find(client
) != mPowerClients
.end());
418 mPowerClients
.erase(client
);
423 // Expose the process/pid map to the outside
425 Process
*Server::findPid(pid_t pid
) const
427 PidMap::const_iterator it
= mPids
.find(pid
);
428 return (it
== mPids
.end()) ? NULL
: it
->second
;
433 // Set delayed shutdown mode
435 void Server::waitForClients(bool waiting
)
437 mWaitForClients
= waiting
;
442 // Begin shutdown processing.
443 // We relinquish our primary state authority. From now on, we'll be
444 // kept alive (only) by our current clients.
446 static FILE *reportFile
;
448 void Server::beginShutdown()
450 StLock
<Mutex
> _(*this);
451 if (!mWaitForClients
) {
452 SECURITYD_SHUTDOWN_NOW();
455 if (!mShuttingDown
) {
456 mShuttingDown
= true;
457 Session::invalidateAuthHosts();
458 SECURITYD_SHUTDOWN_BEGIN();
459 if (verbosity() >= 2) {
460 reportFile
= fopen("/var/log/securityd-shutdown.log", "w");
469 // During shutdown, we report residual clients to dtrace, and allow a state dump
471 // We don't bother locking for the shuttingDown() check; it's a latching boolean
472 // and we'll be good enough without a lock.
474 void Server::eventDone()
476 if (this->shuttingDown()) {
477 StLock
<Mutex
> lazy(*this, false); // lazy lock acquisition
478 if (SECURITYD_SHUTDOWN_COUNT_ENABLED()) {
480 SECURITYD_SHUTDOWN_COUNT(mProcesses
.size(), VProc::Transaction::debugCount());
482 if (verbosity() >= 2) {
486 IFDUMPING("shutdown", NodeCore::dumpAll());
491 void Server::shutdownSnitch()
495 fprintf(reportFile
, "%.24s %d residual clients:\n", ctime(&now
), int(mPids
.size()));
496 for (PidMap::const_iterator it
= mPids
.begin(); it
!= mPids
.end(); ++it
)
497 if (SecCodeRef clientCode
= it
->second
->processCode()) {
498 CFRef
<CFURLRef
> path
;
499 OSStatus rc
= SecCodeCopyPath(clientCode
, kSecCSDefaultFlags
, &path
.aref());
501 fprintf(reportFile
, " %s (%d)\n", cfString(path
).c_str(), it
->first
);
503 fprintf(reportFile
, "pid=%d (error %d)\n", it
->first
, int32_t(rc
));
505 fprintf(reportFile
, "\n");
511 // Initialize the CSSM/MDS subsystem.
512 // This was once done lazily on demand. These days, we are setting up the
513 // system MDS here, and CSSM is pretty much always needed, so this is called
514 // early during program startup. Do note that the server may not (yet) be running.
516 void Server::loadCssm(bool mdsIsInstalled
)
518 if (!mCssm
->isActive()) {
519 StLock
<Mutex
> _(*this);
520 VProc::Transaction xact
;
521 if (!mCssm
->isActive()) {
522 if (!mdsIsInstalled
) { // non-system securityd instance should not reinitialize MDS
523 secdebug("SS", "Installing MDS");
524 IFDEBUG(if (geteuid() == 0))
525 MDSClient::mds().install();
527 secdebug("SS", "CSSM initializing");
530 secdebug("SS", "CSSM ready with CSP %s", mCSP
->guid().toString().c_str());
537 // LongtermActivity/lock combo
539 LongtermStLock::LongtermStLock(Mutex
&lck
)
540 : StLock
<Mutex
>(lck
, false) // don't take the lock yet
542 if (lck
.tryLock()) { // uncontested
543 this->mActive
= true;
544 } else { // contested - need backup thread
545 Server::active().longTermActivity();