]> git.saurik.com Git - apple/security.git/blob - securityd/src/server.cpp
Security-59754.41.1.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 <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 // engage the subsidiary port handler for sleep notifications
61 add(sleepWatcher);
62 }
63
64
65 //
66 // Clean up the server object
67 //
68 Server::~Server()
69 {
70 //@@@ more later
71 }
72
73
74 //
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().
79 //
80 Connection &Server::connection(mach_port_t port, audit_token_t &auditToken)
81 {
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);
88 return *conn;
89 }
90
91 Connection &Server::connection(bool tolerant)
92 {
93 Connection *conn = active().mCurrentConnection();
94 assert(conn); // have to have one
95 if (!tolerant)
96 conn->checkWork();
97 return *conn;
98 }
99
100 void Server::requestComplete(CSSM_RETURN &rcode)
101 {
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);
107 conn = NULL;
108 }
109 IFDUMPING("state", NodeCore::dumpAll());
110 }
111
112
113 //
114 // Shorthand for "current" process and session.
115 // This is the process and session for the current connection.
116 //
117 Process &Server::process()
118 {
119 return connection().process();
120 }
121
122 Session &Server::session()
123 {
124 return connection().process().session();
125 }
126
127 RefPointer<Key> Server::key(KeyHandle key)
128 {
129 return U32HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE);
130 }
131
132 RefPointer<Database> Server::database(DbHandle db)
133 {
134 return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
135 }
136
137 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
138 {
139 return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
140 }
141
142 RefPointer<Database> Server::optionalDatabase(DbHandle db, bool persistent)
143 {
144 if (persistent && db != noDb)
145 return database(db);
146 else
147 return &process().localStore();
148 }
149
150
151 //
152 // Locate an ACL bearer (database or key) by handle
153 // The handle might be used across IPC, so we clamp it accordingly
154 //
155 AclSource &Server::aclBearer(AclKind kind, U32HandleObject::Handle handle)
156 {
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);
160 return bearer;
161 }
162
163
164 //
165 // Run the server. This will not return until the server is forced to exit.
166 //
167 void Server::run()
168 {
169 MachServer::run(0x10000,
170 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
171 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT));
172 }
173
174
175 //
176 // Handle thread overflow. MachServer will call this if it has hit its thread
177 // limit and yet still needs another thread.
178 //
179 void Server::threadLimitReached(UInt32 limit)
180 {
181 Syslog::notice("securityd has reached its thread limit (%d) - service deadlock is possible",
182 (uint32_t) limit);
183 }
184
185
186 //
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.
192 //
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 *);
195
196
197 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
198 {
199 return ucsp_server(in, out) || self_server(in, out);
200 }
201
202
203 //
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).
209 //
210 void Server::setupConnection(ConnectLevel type, Port replyPort, Port taskPort,
211 const audit_token_t &auditToken, const ClientSetupInfo *info)
212 {
213 Security::CommonCriteria::AuditToken audit(auditToken);
214
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
222 assert(info);
223 proc->reset(taskPort, info, audit);
224 proc->changeSession(audit.sessionId());
225 }
226 if (!proc) {
227 if (type == connectNewThread) // client error (or attack)
228 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
229 assert(info);
230 proc = new Process(taskPort, info, audit);
231 notifyIfDead(taskPort);
232 mPids[proc->pid()] = proc;
233 }
234
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);
241 }
242
243 //
244 // Handling dead-port notifications.
245 // This receives DPNs for all kinds of ports we're interested in.
246 //
247 void Server::notifyDeadName(Port port)
248 {
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.
252
253 StLock<Mutex> serverLock(*this);
254
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);
261 serverLock.unlock();
262 return;
263 }
264
265 // is it a process?
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);
272 serverLock.unlock();
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);
276 proc->kill();
277 return;
278 }
279
280 // well, what IS IT?!
281 secnotice("server", "spurious dead port notification for port %d", port.port());
282 }
283
284
285 //
286 // Handling no-senders notifications.
287 // This is currently only used for (subsidiary) service ports
288 //
289 void Server::notifyNoSenders(Port port, mach_port_mscount_t)
290 {
291 secinfo("SecServer", "%p dead session %d", this, port.port());
292 }
293
294
295 //
296 // Handling signals.
297 // These are sent as Mach messages from ourselves to escape the limitations of
298 // the signal handler environment.
299 //
300 kern_return_t self_server_handleSignal(mach_port_t sport,
301 mach_port_t taskPort, int sig)
302 {
303 try {
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);
308 return KERN_SUCCESS;
309 }
310 switch (sig) {
311 case SIGCHLD:
312 ServerChild::checkChildren();
313 break;
314 case SIGINT:
315 secnotice("SecServer", "shutdown due to SIGINT");
316 Syslog::notice("securityd terminated due to SIGINT");
317 _exit(0);
318 case SIGTERM:
319 Server::active().beginShutdown();
320 break;
321 case SIGPIPE:
322 fprintf(stderr, "securityd ignoring SIGPIPE received");
323 break;
324
325 #if defined(DEBUGDUMP)
326 case SIGUSR1:
327 NodeCore::dumpAll();
328 break;
329 #endif //DEBUGDUMP
330
331 case SIGUSR2:
332 fprintf(stderr, "securityd ignoring SIGUSR2 received");
333 break;
334
335 default:
336 assert(false);
337 }
338 } catch(...) {
339 secnotice("SecServer", "exception handling a signal (ignored)");
340 }
341 mach_port_deallocate(mach_task_self(), taskPort);
342 return KERN_SUCCESS;
343 }
344
345
346 kern_return_t self_server_handleSession(mach_port_t sport,
347 mach_port_t taskPort, uint32_t event, uint64_t ident)
348 {
349 try {
350 if (taskPort != mach_task_self()) {
351 Syslog::error("handleSession: received from someone other than myself");
352 mach_port_deallocate(mach_task_self(), taskPort);
353 return KERN_SUCCESS;
354 }
355 if (event == AUE_SESSION_END)
356 Session::destroy(int_cast<uint64_t, Session::SessionId>(ident));
357 } catch(...) {
358 secnotice("SecServer", "exception handling a signal (ignored)");
359 }
360 mach_port_deallocate(mach_task_self(), taskPort);
361 return KERN_SUCCESS;
362 }
363
364
365 //
366 // Notifier for system sleep events
367 //
368 void Server::SleepWatcher::systemWillSleep()
369 {
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();
374 }
375
376 void Server::SleepWatcher::systemIsWaking()
377 {
378 secnotice("SecServer", "%p is waking", this);
379 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
380 (*it)->systemIsWaking();
381 }
382
383 void Server::SleepWatcher::systemWillPowerOn()
384 {
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();
389 }
390
391 void Server::SleepWatcher::add(PowerWatcher *client)
392 {
393 assert(mPowerClients.find(client) == mPowerClients.end());
394 mPowerClients.insert(client);
395 }
396
397 void Server::SleepWatcher::remove(PowerWatcher *client)
398 {
399 assert(mPowerClients.find(client) != mPowerClients.end());
400 mPowerClients.erase(client);
401 }
402
403
404 //
405 // Expose the process/pid map to the outside
406 //
407 Process *Server::findPid(pid_t pid) const
408 {
409 PidMap::const_iterator it = mPids.find(pid);
410 return (it == mPids.end()) ? NULL : it->second;
411 }
412
413
414 //
415 // Set delayed shutdown mode
416 //
417 void Server::waitForClients(bool waiting)
418 {
419 mWaitForClients = waiting;
420 }
421
422
423 //
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.
427 //
428 static FILE *reportFile;
429
430 void Server::beginShutdown()
431 {
432 StLock<Mutex> _(*this);
433 if (!mWaitForClients) {
434 secnotice("SecServer", "%p shutting down now", this);
435 _exit(0);
436 } else {
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();
445 }
446 }
447 }
448 }
449
450
451 //
452 // During shutdown, we report residual clients to dtrace, and allow a state dump
453 // for debugging.
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.
456 //
457 void Server::eventDone()
458 {
459 StLock<Mutex> lock(*this);
460 if (this->shuttingDown()) {
461 shutdownReport();
462 if (verbosity() >= 2) {
463 secnotice("SecServer", "shutting down with %ld processes", mProcesses.size());
464 shutdownReport_file();
465 }
466 }
467 }
468
469 void Server::shutdownReport()
470 {
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);
475 }
476 }
477
478 void Server::shutdownReport_file()
479 {
480 time_t now;
481 time(&now);
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);
486 }
487 fprintf(reportFile, "\n");
488 fflush(reportFile);
489 }
490
491 bool Server::inDarkWake()
492 {
493 bool inDarkWake = IOPMIsADarkWake(IOPMConnectionGetSystemCapabilities());
494 if (inDarkWake) {
495 secnotice("SecServer", "Server::inDarkWake returned inDarkWake");
496 }
497 return inDarkWake;
498 }
499
500 //
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.
505 //
506 void Server::loadCssm(bool mdsIsInstalled)
507 {
508 try {
509
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();
518 }
519 secnotice("SecServer", "CSSM initializing");
520 mCssm->init();
521 mCSP->attach();
522 secnotice("SecServer", "CSSM ready with CSP %s", mCSP->guid().toString().c_str());
523 }
524 xpc_transaction_end();
525 }
526 } catch (const UnixError& err) {
527 secerror("load cssm failed: %s", err.what());
528 if (err.unixError() == ENOSPC) {
529 _exit(1);
530 } else {
531 abort();
532 }
533 } catch (const MacOSError& err) {
534 secerror("load cssm failed: %s", err.what());
535 abort();
536 } catch (const CommonError& err) {
537 secerror("load cssm failed: %d/%d", (int)err.osStatus(), err.unixError());
538 abort();
539 } catch (const std::exception& err) {
540 secerror("load cssm failed: %s", err.what());
541 abort();
542 }
543 }
544
545
546 //
547 // LongtermActivity/lock combo
548 //
549 LongtermStLock::LongtermStLock(Mutex &lck)
550 : StLock<Mutex>(lck, false) // don't take the lock yet
551 {
552 if (lck.tryLock()) { // uncontested
553 this->mActive = true;
554 } else { // contested - need backup thread
555 Server::active().longTermActivity();
556 this->lock();
557 }
558 }