]> git.saurik.com Git - apple/securityd.git/blob - src/server.cpp
securityd-40600.tar.gz
[apple/securityd.git] / src / server.cpp
1 /*
2 * Copyright (c) 2000-2004,2009 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 mAudit(geteuid(), getpid()),
69 mVerbosity(0),
70 mWaitForClients(true), mShuttingDown(false)
71 {
72 // make me eternal (in the object mesh)
73 ref();
74
75 mAudit.registerSession();
76
77 // engage the subsidiary port handler for sleep notifications
78 add(sleepWatcher);
79 }
80
81
82 //
83 // Clean up the server object
84 //
85 Server::~Server()
86 {
87 //@@@ more later
88 }
89
90
91 //
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().
96 //
97 Connection &Server::connection(mach_port_t port, audit_token_t &auditToken)
98 {
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);
104 return *conn;
105 }
106
107 Connection &Server::connection(bool tolerant)
108 {
109 Connection *conn = active().mCurrentConnection();
110 assert(conn); // have to have one
111 if (!tolerant)
112 conn->checkWork();
113 return *conn;
114 }
115
116 void Server::requestComplete(CSSM_RETURN &rcode)
117 {
118 // note: there may not be an active connection if connection setup failed
119 if (RefPointer<Connection> &conn = active().mCurrentConnection()) {
120 conn->endWork(rcode);
121 conn = NULL;
122 }
123 IFDUMPING("state", NodeCore::dumpAll());
124 }
125
126
127 //
128 // Shorthand for "current" process and session.
129 // This is the process and session for the current connection.
130 //
131 Process &Server::process()
132 {
133 return connection().process();
134 }
135
136 Session &Server::session()
137 {
138 return connection().process().session();
139 }
140
141 RefPointer<Key> Server::key(KeyHandle key)
142 {
143 return U32HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE);
144 }
145
146 RefPointer<Database> Server::database(DbHandle db)
147 {
148 return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
149 }
150
151 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
152 {
153 return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
154 }
155
156 RefPointer<Database> Server::optionalDatabase(DbHandle db, bool persistent)
157 {
158 if (persistent && db != noDb)
159 return database(db);
160 else
161 return &process().localStore();
162 }
163
164
165 //
166 // Locate an ACL bearer (database or key) by handle
167 // The handle might be used across IPC, so we clamp it accordingly
168 //
169 AclSource &Server::aclBearer(AclKind kind, U32HandleObject::Handle handle)
170 {
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);
174 return bearer;
175 }
176
177
178 //
179 // Run the server. This will not return until the server is forced to exit.
180 //
181 void Server::run()
182 {
183 MachServer::run(0x10000,
184 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
185 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT));
186 }
187
188
189 //
190 // Handle thread overflow. MachServer will call this if it has hit its thread
191 // limit and yet still needs another thread.
192 //
193 void Server::threadLimitReached(UInt32 limit)
194 {
195 Syslog::notice("securityd has reached its thread limit (%ld) - service deadlock is possible",
196 limit);
197 }
198
199
200 //
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.
206 //
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 *);
209
210
211 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
212 {
213 return ucsp_server(in, out) || self_server(in, out);
214 }
215
216
217 //
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).
223 //
224 void Server::setupConnection(ConnectLevel type, Port servicePort, Port replyPort, Port taskPort,
225 const audit_token_t &auditToken, const ClientSetupInfo *info, const char *identity)
226 {
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);
233 }
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);
239 }
240 if (!proc) {
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;
247 }
248
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);
255 }
256
257
258 //
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.
263 //
264 void Server::endConnection(Port replyPort)
265 {
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);
271 }
272
273 //
274 // Handling dead-port notifications.
275 // This receives DPNs for all kinds of ports we're interested in.
276 //
277 void Server::notifyDeadName(Port port)
278 {
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
282
283 StLock<Mutex> serverLock(*this);
284 secdebug("SSports", "port %d is dead", port.port());
285
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);
292 serverLock.unlock();
293 con->abort();
294 return;
295 }
296
297 // is it a process?
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);
304 serverLock.unlock();
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);
308 proc->kill();
309 return;
310 }
311
312 // well, what IS IT?!
313 SECURITYD_PORTS_DEAD_ORPHAN(port);
314 secdebug("server", "spurious dead port notification for port %d", port.port());
315 }
316
317
318 //
319 // Handling no-senders notifications.
320 // This is currently only used for (subsidiary) service ports
321 //
322 void Server::notifyNoSenders(Port port, mach_port_mscount_t)
323 {
324 SECURITYD_PORTS_DEAD_SESSION(port);
325 secdebug("SSports", "port %d no senders", port.port());
326 Session::destroy(port);
327 }
328
329
330 //
331 // Handling signals.
332 // These are sent as Mach messages from ourselves to escape the limitations of
333 // the signal handler environment.
334 //
335 kern_return_t self_server_handleSignal(mach_port_t sport,
336 mach_port_t taskPort, int sig)
337 {
338 try {
339 SECURITYD_SIGNAL_HANDLED(sig);
340 if (taskPort != mach_task_self()) {
341 Syslog::error("handleSignal: received from someone other than myself");
342 return KERN_SUCCESS;
343 }
344 switch (sig) {
345 case SIGCHLD:
346 ServerChild::checkChildren();
347 break;
348 case SIGINT:
349 SECURITYD_SHUTDOWN_NOW();
350 Syslog::notice("securityd terminated due to SIGINT");
351 _exit(0);
352 case SIGTERM:
353 Server::active().beginShutdown();
354 break;
355 case SIGPIPE:
356 fprintf(stderr, "securityd ignoring SIGPIPE received");
357 break;
358
359 #if defined(DEBUGDUMP)
360 case SIGUSR1:
361 NodeCore::dumpAll();
362 break;
363 #endif //DEBUGDUMP
364
365 case SIGUSR2:
366 {
367 extern PCSCMonitor *gPCSC;
368 gPCSC->startSoftTokens();
369 break;
370 }
371
372 default:
373 assert(false);
374 }
375 } catch(...) {
376 secdebug("SS", "exception handling a signal (ignored)");
377 }
378 mach_port_deallocate(mach_task_self(), taskPort);
379 return KERN_SUCCESS;
380 }
381
382
383 //
384 // Notifier for system sleep events
385 //
386 void Server::SleepWatcher::systemWillSleep()
387 {
388 SECURITYD_POWER_SLEEP();
389 Session::processSystemSleep();
390 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
391 (*it)->systemWillSleep();
392 }
393
394 void Server::SleepWatcher::systemIsWaking()
395 {
396 SECURITYD_POWER_WAKE();
397 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
398 (*it)->systemIsWaking();
399 }
400
401 void Server::SleepWatcher::systemWillPowerOn()
402 {
403 SECURITYD_POWER_ON();
404 Server::active().longTermActivity();
405 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
406 (*it)->systemWillPowerOn();
407 }
408
409 void Server::SleepWatcher::add(PowerWatcher *client)
410 {
411 assert(mPowerClients.find(client) == mPowerClients.end());
412 mPowerClients.insert(client);
413 }
414
415 void Server::SleepWatcher::remove(PowerWatcher *client)
416 {
417 assert(mPowerClients.find(client) != mPowerClients.end());
418 mPowerClients.erase(client);
419 }
420
421
422 //
423 // Expose the process/pid map to the outside
424 //
425 Process *Server::findPid(pid_t pid) const
426 {
427 PidMap::const_iterator it = mPids.find(pid);
428 return (it == mPids.end()) ? NULL : it->second;
429 }
430
431
432 //
433 // Set delayed shutdown mode
434 //
435 void Server::waitForClients(bool waiting)
436 {
437 mWaitForClients = waiting;
438 }
439
440
441 //
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.
445 //
446 static FILE *reportFile;
447
448 void Server::beginShutdown()
449 {
450 StLock<Mutex> _(*this);
451 if (!mWaitForClients) {
452 SECURITYD_SHUTDOWN_NOW();
453 _exit(0);
454 } else {
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");
461 shutdownSnitch();
462 }
463 }
464 }
465 }
466
467
468 //
469 // During shutdown, we report residual clients to dtrace, and allow a state dump
470 // for debugging.
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.
473 //
474 void Server::eventDone()
475 {
476 if (this->shuttingDown()) {
477 StLock<Mutex> lazy(*this, false); // lazy lock acquisition
478 if (SECURITYD_SHUTDOWN_COUNT_ENABLED()) {
479 lazy.lock();
480 SECURITYD_SHUTDOWN_COUNT(mProcesses.size(), VProc::Transaction::debugCount());
481 }
482 if (verbosity() >= 2) {
483 lazy.lock();
484 shutdownSnitch();
485 }
486 IFDUMPING("shutdown", NodeCore::dumpAll());
487 }
488 }
489
490
491 void Server::shutdownSnitch()
492 {
493 time_t now;
494 time(&now);
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());
500 if (path)
501 fprintf(reportFile, " %s (%d)\n", cfString(path).c_str(), it->first);
502 else
503 fprintf(reportFile, "pid=%d (error %d)\n", it->first, int32_t(rc));
504 }
505 fprintf(reportFile, "\n");
506 fflush(reportFile);
507 }
508
509
510 //
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.
515 //
516 void Server::loadCssm(bool mdsIsInstalled)
517 {
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();
526 }
527 secdebug("SS", "CSSM initializing");
528 mCssm->init();
529 mCSP->attach();
530 secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString().c_str());
531 }
532 }
533 }
534
535
536 //
537 // LongtermActivity/lock combo
538 //
539 LongtermStLock::LongtermStLock(Mutex &lck)
540 : StLock<Mutex>(lck, false) // don't take the lock yet
541 {
542 if (lck.tryLock()) { // uncontested
543 this->mActive = true;
544 } else { // contested - need backup thread
545 Server::active().longTermActivity();
546 this->lock();
547 }
548 }