/ securityd / src / server.cpp
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  #ifndef DARLING
 61      // engage the subsidiary port handler for sleep notifications
 62  	add(sleepWatcher);
 63  #endif
 64  }
 65  
 66  
 67  //
 68  // Clean up the server object
 69  //
 70  Server::~Server()
 71  {
 72      //@@@ more later
 73  }
 74  
 75  
 76  //
 77  // Locate a connection by reply port and make it the current connection
 78  // of this thread. The connection will be marked busy, and can be accessed
 79  // by calling Server::connection() [no argument] until it is released by
 80  // calling Connection::endWork().
 81  //
 82  Connection &Server::connection(mach_port_t port, audit_token_t &auditToken)
 83  {
 84  	Server &server = active();
 85  	StLock<Mutex> _(server);
 86  	Connection *conn = server.mConnections.get(port, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
 87  	conn->process().checkSession(auditToken);
 88  	active().mCurrentConnection() = conn;
 89  	conn->beginWork(auditToken);
 90  	return *conn;
 91  }
 92  
 93  Connection &Server::connection(bool tolerant)
 94  {
 95  	Connection *conn = active().mCurrentConnection();
 96  	assert(conn);	// have to have one
 97  	if (!tolerant)
 98  		conn->checkWork();
 99  	return *conn;
100  }
101  
102  void Server::requestComplete(CSSM_RETURN &rcode)
103  {
104      Server &server = active();
105      StLock<Mutex> lock(server);
106  	// note: there may not be an active connection if connection setup failed
107  	if (RefPointer<Connection> &conn = server.mCurrentConnection()) {
108  		conn->endWork(rcode);
109  		conn = NULL;
110  	}
111  	IFDUMPING("state", NodeCore::dumpAll());
112  }
113  
114  
115  //
116  // Shorthand for "current" process and session.
117  // This is the process and session for the current connection.
118  //
119  Process &Server::process()
120  {
121  	return connection().process();
122  }
123  
124  Session &Server::session()
125  {
126  	return connection().process().session();
127  }
128  
129  RefPointer<Key> Server::key(KeyHandle key)
130  {
131  	return U32HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE);
132  }
133  
134  RefPointer<Database> Server::database(DbHandle db)
135  {
136  	return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
137  }
138  
139  RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
140  {
141  	return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
142  }
143  
144  RefPointer<Database> Server::optionalDatabase(DbHandle db, bool persistent)
145  {
146  	if (persistent && db != noDb)
147  		return database(db);
148  	else
149  		return &process().localStore();
150  }
151  
152  
153  //
154  // Locate an ACL bearer (database or key) by handle
155  // The handle might be used across IPC, so we clamp it accordingly
156  //
157  AclSource &Server::aclBearer(AclKind kind, U32HandleObject::Handle handle)
158  {
159  	AclSource &bearer = U32HandleObject::find<AclSource>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
160  	if (kind != bearer.acl().aclKind())
161  		CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE);
162  	return bearer;
163  }
164  
165  
166  //
167  // Run the server. This will not return until the server is forced to exit.
168  //
169  void Server::run()
170  {
171  	MachServer::run(0x10000,
172          MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
173          MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT));
174  }
175  
176  
177  //
178  // Handle thread overflow. MachServer will call this if it has hit its thread
179  // limit and yet still needs another thread.
180  //
181  void Server::threadLimitReached(UInt32 limit)
182  {
183  	Syslog::notice("securityd has reached its thread limit (%d) - service deadlock is possible",
184  		(uint32_t) limit);
185  }
186  
187  
188  //
189  // The primary server run-loop function.
190  // Invokes the MIG-generated main dispatch function (ucsp_server), as well
191  // as the self-send dispatch (self_server).
192  // For debug builds, look up request names in a MIG-generated table
193  // for better debug-log messages.
194  //
195  boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *);
196  boolean_t self_server(mach_msg_header_t *, mach_msg_header_t *);
197  
198  
199  boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
200  {
201  	return ucsp_server(in, out) || self_server(in, out);
202  }
203  
204  
205  //
206  // Set up a new Connection. This establishes the environment (process et al) as needed
207  // and registers a properly initialized Connection object to run with.
208  // Type indicates how "deep" we need to initialize (new session, process, or connection).
209  // Everything at and below that level is constructed. This is straight-forward except
210  // in the case of session re-initialization (see below).
211  //
212  void Server::setupConnection(ConnectLevel type, Port replyPort, Port taskPort,
213      const audit_token_t &auditToken, const ClientSetupInfo *info)
214  {
215  	Security::CommonCriteria::AuditToken audit(auditToken);
216  	
217  	// first, make or find the process based on task port
218  	StLock<Mutex> _(*this);
219  	RefPointer<Process> &proc = mProcesses[taskPort];
220  	if (proc && proc->session().sessionId() != audit.sessionId())
221  		proc->changeSession(audit.sessionId());
222  	if (proc && type == connectNewProcess) {
223  		// the client has amnesia - reset it
224  		assert(info);
225  		proc->reset(taskPort, info, audit);
226  		proc->changeSession(audit.sessionId());
227  	}
228  	if (!proc) {
229  		if (type == connectNewThread)	// client error (or attack)
230  			CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
231  		assert(info);
232  		proc = new Process(taskPort, info, audit);
233  		notifyIfDead(taskPort);
234  		mPids[proc->pid()] = proc;
235  	}
236  
237  	// now, establish a connection and register it in the server
238  	Connection *connection = new Connection(*proc, replyPort);
239  	if (mConnections.contains(replyPort))   // malicious re-entry attempt?
240  		CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);	//@@@ error code? (client error)
241  	mConnections[replyPort] = connection;
242  	notifyIfDead(replyPort);
243  }
244  
245  //
246  // Handling dead-port notifications.
247  // This receives DPNs for all kinds of ports we're interested in.
248  //
249  void Server::notifyDeadName(Port port)
250  {
251  	// We need the lock to get a proper iterator on mConnections or mProcesses,
252  	// but must release it before we call abort or kill, as these might take 
253  	// unbounded time, including calls out to token daemons etc.
254  	
255  	StLock<Mutex> serverLock(*this);
256  
257      // is it a connection?
258      PortMap<Connection>::iterator conIt = mConnections.find(port);
259      if (conIt != mConnections.end()) {
260          secinfo("SecServer", "%p dead connection %d", this, port.port());
261          RefPointer<Connection> con = conIt->second;
262  		mConnections.erase(conIt);
263          serverLock.unlock();
264          return;
265      }
266      
267      // is it a process?
268      PortMap<Process>::iterator procIt = mProcesses.find(port);
269      if (procIt != mProcesses.end()) {
270          secinfo("SecServer", "%p dead process %d", this, port.port());
271          RefPointer<Process> proc = procIt->second;
272  		mPids.erase(proc->pid());
273  		mProcesses.erase(procIt);
274          serverLock.unlock();
275  		// The kill may take some time; make sure there is a spare thread around
276  		// to prevent deadlocks
277  		StLock<MachServer, &Server::busy, &Server::idle> _(*this);
278  		proc->kill();
279          return;
280      }
281      
282  	// well, what IS IT?!
283  	secnotice("server", "spurious dead port notification for port %d", port.port());
284  }
285  
286  
287  //
288  // Handling no-senders notifications.
289  // This is currently only used for (subsidiary) service ports
290  //
291  void Server::notifyNoSenders(Port port, mach_port_mscount_t)
292  {
293      secinfo("SecServer", "%p dead session %d", this, port.port());
294  }
295  
296  
297  //
298  // Handling signals.
299  // These are sent as Mach messages from ourselves to escape the limitations of
300  // the signal handler environment.
301  //
302  kern_return_t self_server_handleSignal(mach_port_t sport,
303  	audit_token_t auditToken, int sig)
304  {
305      try {
306          secnotice("SecServer", "signal handled %d", sig);
307          if (audit_token_to_pid(auditToken) != getpid()) {
308              Syslog::error("handleSignal: received from someone other than myself");
309  			return KERN_SUCCESS;
310  		}
311  		switch (sig) {
312  		case SIGCHLD:
313  			ServerChild::checkChildren();
314  			break;
315  		case SIGINT:
316              secnotice("SecServer", "shutdown due to SIGINT");
317  			Syslog::notice("securityd terminated due to SIGINT");
318  			_exit(0);
319  		case SIGTERM:
320  			Server::active().beginShutdown();
321  			break;
322  		case SIGPIPE:
323  			fprintf(stderr, "securityd ignoring SIGPIPE received");
324  			break;
325  
326  #if defined(DEBUGDUMP)
327  		case SIGUSR1:
328  			NodeCore::dumpAll();
329  			break;
330  #endif //DEBUGDUMP
331  
332  		case SIGUSR2:
333              fprintf(stderr, "securityd ignoring SIGUSR2 received");
334              break;
335  
336  		default:
337  			assert(false);
338          }
339      } catch(...) {
340  		secnotice("SecServer", "exception handling a signal (ignored)");
341  	}
342      return KERN_SUCCESS;
343  }
344  
345  
346  kern_return_t self_server_handleSession(mach_port_t sport,
347  	audit_token_t auditToken, uint32_t event, uint64_t ident)
348  {
349      try {
350          if (audit_token_to_pid(auditToken) != getpid()) {
351              Syslog::error("handleSession: received from someone other than myself");
352  			return KERN_SUCCESS;
353  		}
354  		if (event == AUE_SESSION_END)
355              Session::destroy(int_cast<uint64_t, Session::SessionId>(ident));
356      } catch(...) {
357  		secnotice("SecServer", "exception handling a signal (ignored)");
358  	}
359      return KERN_SUCCESS;
360  }
361  
362  
363  //
364  // Notifier for system sleep events
365  //
366  void Server::SleepWatcher::systemWillSleep()
367  {
368      secnotice("SecServer", "%p will sleep", this);
369      Session::processSystemSleep();
370  	for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
371  		(*it)->systemWillSleep();
372  }
373  
374  void Server::SleepWatcher::systemIsWaking()
375  {
376      secnotice("SecServer", "%p is waking", this);
377  	for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
378  		(*it)->systemIsWaking();
379  }
380  
381  void Server::SleepWatcher::systemWillPowerOn()
382  {
383      secnotice("SecServer", "%p will power on", this);
384  	Server::active().longTermActivity();
385  	for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
386  		(*it)->systemWillPowerOn();
387  }
388  
389  void Server::SleepWatcher::add(PowerWatcher *client)
390  {
391  	assert(mPowerClients.find(client) == mPowerClients.end());
392  	mPowerClients.insert(client);
393  }
394  
395  void Server::SleepWatcher::remove(PowerWatcher *client)
396  {
397  	assert(mPowerClients.find(client) != mPowerClients.end());
398  	mPowerClients.erase(client);
399  }
400  
401  
402  //
403  // Expose the process/pid map to the outside
404  //
405  Process *Server::findPid(pid_t pid) const
406  {
407  	PidMap::const_iterator it = mPids.find(pid);
408  	return (it == mPids.end()) ? NULL : it->second;
409  }
410  
411  
412  //
413  // Set delayed shutdown mode
414  //
415  void Server::waitForClients(bool waiting)
416  {
417  	mWaitForClients = waiting;
418  }
419  
420  
421  //
422  // Begin shutdown processing.
423  // We relinquish our primary state authority. From now on, we'll be
424  // kept alive (only) by our current clients.
425  //
426  static FILE *reportFile;
427  
428  void Server::beginShutdown()
429  {
430  	StLock<Mutex> _(*this);
431  	if (!mWaitForClients) {
432          secnotice("SecServer", "%p shutting down now", this);
433  		_exit(0);
434  	} else {
435  		if (!mShuttingDown) {
436  			mShuttingDown = true;
437              Session::invalidateAuthHosts();
438              secnotice("SecServer", "%p beginning shutdown", this);
439              shutdownReport();           // always tell me about residual clients...
440  			if (verbosity() >= 2) {     // ...and if we really care write to the log, too
441  				reportFile = fopen("/var/log/securityd-shutdown.log", "w");
442  				shutdownReport_file();
443  			}
444  		}
445  	}
446  }
447  
448  
449  //
450  // During shutdown, we report residual clients to dtrace, and allow a state dump
451  // for debugging.
452  // We don't bother locking for the shuttingDown() check; it's a latching boolean
453  // and we'll be good enough without a lock.
454  //
455  void Server::eventDone()
456  {
457      StLock<Mutex> lock(*this);
458  	if (this->shuttingDown()) {
459          shutdownReport();
460  		if (verbosity() >= 2) {
461              secnotice("SecServer", "shutting down with %ld processes", mProcesses.size());
462  			shutdownReport_file();
463  		}
464  	}
465  }
466  
467  void Server::shutdownReport()
468  {
469      PidMap mPidsCopy = PidMap(mPids);
470      secnotice("shutdown", "Residual clients count: %d", int(mPidsCopy.size()));
471      for (PidMap::const_iterator it = mPidsCopy.begin(); it != mPidsCopy.end(); ++it) {
472          secnotice("shutdown", "Residual client: %d", it->first);
473      }
474  }
475  
476  void Server::shutdownReport_file()
477  {
478  	time_t now;
479  	time(&now);
480  	fprintf(reportFile, "%.24s %d residual clients:\n",	ctime(&now), int(mPids.size()));
481  	for (PidMap::const_iterator it = mPids.begin(); it != mPids.end(); ++it) {
482  		string path = it->second->getPath();
483  		fprintf(reportFile, " %s (%d)\n", path.c_str(), it->first);
484  	}
485  	fprintf(reportFile, "\n");
486  	fflush(reportFile);
487  }
488  
489  bool Server::inDarkWake()
490  {
491      bool inDarkWake = IOPMIsADarkWake(IOPMConnectionGetSystemCapabilities());
492      if (inDarkWake) {
493          secnotice("SecServer", "Server::inDarkWake returned inDarkWake");
494      }
495      return inDarkWake;
496  }
497  
498  //
499  // Initialize the CSSM/MDS subsystem.
500  // This was once done lazily on demand. These days, we are setting up the
501  // system MDS here, and CSSM is pretty much always needed, so this is called
502  // early during program startup. Do note that the server may not (yet) be running.
503  //
504  void Server::loadCssm(bool mdsIsInstalled)
505  {
506      try {
507  
508  	if (!mCssm->isActive()) {
509  		StLock<Mutex> _(*this);
510          xpc_transaction_begin();
511  		if (!mCssm->isActive()) {
512              if (!mdsIsInstalled) {  // non-system securityd instance should not reinitialize MDS
513                  secnotice("SecServer", "Installing MDS");
514                  IFDEBUG(if (geteuid() == 0))
515  				MDSClient::mds().install();
516              }
517  			secnotice("SecServer", "CSSM initializing");
518  			mCssm->init();
519  			mCSP->attach();
520  			secnotice("SecServer", "CSSM ready with CSP %s", mCSP->guid().toString().c_str());
521  		}
522          xpc_transaction_end();
523  	}
524      } catch (const UnixError& err) {
525          secerror("load cssm failed: %s", err.what());
526          if (err.unixError() == ENOSPC) {
527              _exit(1);
528          } else {
529              abort();
530          }
531      } catch (const MacOSError& err) {
532          secerror("load cssm failed: %s", err.what());
533          abort();
534      } catch (const CommonError& err) {
535          secerror("load cssm failed: %d/%d", (int)err.osStatus(), err.unixError());
536          abort();
537      } catch (const std::exception& err) {
538          secerror("load cssm failed: %s", err.what());
539          abort();
540      }
541  }
542  
543  
544  //
545  // LongtermActivity/lock combo
546  //
547  LongtermStLock::LongtermStLock(Mutex &lck)
548  	: StLock<Mutex>(lck, false)	// don't take the lock yet
549  {
550  	if (lck.tryLock()) {	// uncontested
551  		this->mActive = true;
552  	} else {				// contested - need backup thread
553  		Server::active().longTermActivity();
554  		this->lock();
555  	}
556  }