]> git.saurik.com Git - apple/security.git/blob - securityd/src/server.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / securityd / src / 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 "pcscmonitor.h"
40
41 #include "agentquery.h"
42
43
44 using namespace MachPlusPlus;
45
46 //
47 // Construct an Authority
48 //
49 Authority::Authority(const char *configFile)
50 : Authorization::Engine(configFile)
51 {
52 }
53
54 Authority::~Authority()
55 {
56 }
57
58
59 //
60 // Construct the server object
61 //
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 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 //
82 Server::~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 //
94 Connection &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
105 Connection &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
114 void 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 //
129 Process &Server::process()
130 {
131 return connection().process();
132 }
133
134 Session &Server::session()
135 {
136 return connection().process().session();
137 }
138
139 RefPointer<Key> Server::key(KeyHandle key)
140 {
141 return U32HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE);
142 }
143
144 RefPointer<Database> Server::database(DbHandle db)
145 {
146 return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
147 }
148
149 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
150 {
151 return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
152 }
153
154 RefPointer<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 //
167 AclSource &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 //
179 void 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 //
191 void 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 //
205 boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *);
206 boolean_t self_server(mach_msg_header_t *, mach_msg_header_t *);
207
208
209 boolean_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 //
222 void 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 //
262 void 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 //
276 void 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 //
321 void 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 //
332 kern_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
380 kern_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 //
401 void 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
409 void 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
416 void 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
424 void Server::SleepWatcher::add(PowerWatcher *client)
425 {
426 assert(mPowerClients.find(client) == mPowerClients.end());
427 mPowerClients.insert(client);
428 }
429
430 void 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 //
440 Process *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 //
450 void 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 //
461 static FILE *reportFile;
462
463 void 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 //
489 void 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
506 void 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
524 bool 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 //
535 void 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 //
558 LongtermStLock::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 }