]> git.saurik.com Git - apple/securityd.git/blob - src/server.cpp
securityd-32596.tar.gz
[apple/securityd.git] / src / server.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, 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
40 using namespace MachPlusPlus;
41
42 //
43 // Construct an Authority
44 //
45 Authority::Authority(const char *configFile)
46 : Authorization::Engine(configFile)
47 {
48 }
49
50 Authority::~Authority()
51 {
52 }
53
54 //
55 // Construct the server object
56 //
57 Server::Server(Authority &authority, CodeSignatures &signatures, const char *bootstrapName)
58 : MachServer(bootstrapName),
59 mBootstrapName(bootstrapName),
60 mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule),
61 mAuthority(authority),
62 mCodeSignatures(signatures),
63 mAudit(geteuid(), getpid())
64 {
65 // make me eternal (in the object mesh)
66 ref();
67
68 mAudit.registerSession();
69
70 // engage the subsidiary port handler for sleep notifications
71 add(sleepWatcher);
72 }
73
74
75 //
76 // Clean up the server object
77 //
78 Server::~Server()
79 {
80 //@@@ more later
81 }
82
83
84 //
85 // Locate a connection by reply port and make it the current connection
86 // of this thread. The connection will be marked busy, and can be accessed
87 // by calling Server::connection() [no argument] until it is released by
88 // calling Connection::endWork().
89 //
90 Connection &Server::connection(mach_port_t port)
91 {
92 Server &server = active();
93 StLock<Mutex> _(server);
94 Connection *conn = server.mConnections.get(port, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
95 active().mCurrentConnection() = conn;
96 conn->beginWork();
97 return *conn;
98 }
99
100 Connection &Server::connection(bool tolerant)
101 {
102 Connection *conn = active().mCurrentConnection();
103 assert(conn); // have to have one
104 if (!tolerant)
105 conn->checkWork();
106 return *conn;
107 }
108
109 void Server::requestComplete()
110 {
111 // note: there may not be an active connection if connection setup failed
112 if (RefPointer<Connection> &conn = active().mCurrentConnection()) {
113 conn->endWork();
114 conn = NULL;
115 }
116 IFDUMPING("state", NodeCore::dumpAll());
117 }
118
119
120 //
121 // Shorthand for "current" process and session.
122 // This is the process and session for the current connection.
123 //
124 Process &Server::process()
125 {
126 return connection().process();
127 }
128
129 Session &Server::session()
130 {
131 return connection().process().session();
132 }
133
134 RefPointer<Key> Server::key(KeyHandle key)
135 {
136 return HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE);
137 }
138
139 RefPointer<Database> Server::database(DbHandle db)
140 {
141 return find<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
142 }
143
144 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
145 {
146 return find<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
147 }
148
149 RefPointer<Database> Server::optionalDatabase(DbHandle db, bool persistent)
150 {
151 if (persistent && db != noDb)
152 return database(db);
153 else
154 return &process().localStore();
155 }
156
157
158 //
159 // Locate an ACL bearer (database or key) by handle
160 //
161 AclSource &Server::aclBearer(AclKind kind, CSSM_HANDLE handle)
162 {
163 AclSource &bearer = HandleObject::find<AclSource>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
164 if (kind != bearer.acl().aclKind())
165 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE);
166 return bearer;
167 }
168
169
170 //
171 // Run the server. This will not return until the server is forced to exit.
172 //
173 void Server::run()
174 {
175 MachServer::run(0x10000,
176 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
177 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT));
178 }
179
180
181 //
182 // Handle thread overflow. MachServer will call this if it has hit its thread
183 // limit and yet still needs another thread.
184 //
185 void Server::threadLimitReached(UInt32 limit)
186 {
187 Syslog::notice("securityd has reached its thread limit (%ld) - service deadlock is possible",
188 limit);
189 }
190
191
192 //
193 // The primary server run-loop function.
194 // Invokes the MIG-generated main dispatch function (ucsp_server), as well
195 // as the self-send dispatch (self_server).
196 // For debug builds, look up request names in a MIG-generated table
197 // for better debug-log messages.
198 //
199 boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *);
200 boolean_t self_server(mach_msg_header_t *, mach_msg_header_t *);
201
202 #if defined(NDEBUG)
203
204 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
205 {
206 return ucsp_server(in, out) || self_server(in, out);
207 }
208
209 #else //NDEBUG
210
211 struct IPCName { const char *name; int ipc; };
212 static IPCName ucspNames[] = { subsystem_to_name_map_ucsp }; // generated by MIG
213 static IPCName selfNames[] = { subsystem_to_name_map_self }; // generated by MIG
214
215 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
216 {
217 const int id = in->msgh_id;
218 const int ucspBase = ucspNames[0].ipc;
219 const int selfBase = selfNames[0].ipc;
220 const char *name =
221 (id >= ucspBase && id < ucspBase + ucsp_MSG_COUNT) ? ucspNames[id - ucspBase].name :
222 (id >= selfBase && id < selfBase + self_MSG_COUNT) ? selfNames[id - selfBase].name :
223 "OUT OF BOUNDS";
224 secdebug("SSreq", "begin %s (%d)", name, in->msgh_id);
225 boolean_t result = ucsp_server(in, out) || self_server(in, out);
226 secdebug("SSreq", "end %s (%d)", name, in->msgh_id);
227 return result;
228 }
229
230 #endif //NDEBUG
231
232
233 //
234 // Set up a new Connection. This establishes the environment (process et al) as needed
235 // and registers a properly initialized Connection object to run with.
236 // Type indicates how "deep" we need to initialize (new session, process, or connection).
237 // Everything at and below that level is constructed. This is straight-forward except
238 // in the case of session re-initialization (see below).
239 //
240 void Server::setupConnection(ConnectLevel type, Port servicePort, Port replyPort, Port taskPort,
241 const audit_token_t &auditToken, const ClientSetupInfo *info, const char *identity)
242 {
243 // first, make or find the process based on task port
244 StLock<Mutex> _(*this);
245 RefPointer<Process> &proc = mProcesses[taskPort];
246 if (type == connectNewSession && proc) {
247 // The client has talked to us before and now wants to create a new session.
248 proc->changeSession(servicePort);
249 }
250 if (proc && type == connectNewProcess) {
251 // the client has amnesia - reset it
252 assert(info && identity);
253 proc->reset(servicePort, taskPort, info, identity, AuditToken(auditToken));
254 }
255 if (!proc) {
256 if (type == connectNewThread) // client error (or attack)
257 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
258 assert(info && identity);
259 proc = new Process(servicePort, taskPort, info, identity, AuditToken(auditToken));
260 notifyIfDead(taskPort);
261 }
262
263 // now, establish a connection and register it in the server
264 Connection *connection = new Connection(*proc, replyPort);
265 if (mConnections.contains(replyPort)) // malicious re-entry attempt?
266 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); //@@@ error code? (client error)
267 mConnections[replyPort] = connection;
268 notifyIfDead(replyPort);
269 }
270
271
272 //
273 // Synchronously end a Connection.
274 // This is due to a request from the client, so no thread races are possible.
275 // In practice, this is optional since the DPN for the client thread reply port
276 // will destroy the connection anyway when the thread dies.
277 //
278 void Server::endConnection(Port replyPort)
279 {
280 StLock<Mutex> _(*this);
281 PortMap<Connection>::iterator it = mConnections.find(replyPort);
282 assert(it != mConnections.end());
283 it->second->terminate();
284 mConnections.erase(it);
285 }
286
287
288 //
289 // Handling dead-port notifications.
290 // This receives DPNs for all kinds of ports we're interested in.
291 //
292 void Server::notifyDeadName(Port port)
293 {
294 StLock<Mutex> _(*this);
295 secdebug("SSports", "port %d is dead", port.port());
296
297 // is it a connection?
298 PortMap<Connection>::iterator conIt = mConnections.find(port);
299 if (conIt != mConnections.end()) {
300 conIt->second->abort();
301 mConnections.erase(conIt);
302 return;
303 }
304
305 // is it a process?
306 PortMap<Process>::iterator procIt = mProcesses.find(port);
307 if (procIt != mProcesses.end()) {
308 procIt->second->kill();
309 mProcesses.erase(procIt);
310 return;
311 }
312
313 // is it a notification client?
314 if (Listener::remove(port))
315 return;
316
317 // well, what IS IT?!
318 secdebug("server", "spurious dead port notification for port %d", port.port());
319 }
320
321
322 //
323 // Handling no-senders notifications.
324 // This is currently only used for (subsidiary) service ports
325 //
326 void Server::notifyNoSenders(Port port, mach_port_mscount_t)
327 {
328 secdebug("SSports", "port %d no senders", port.port());
329 Session::destroy(port);
330 }
331
332
333 //
334 // Handling signals.
335 // These are sent as Mach messages from ourselves to escape the limitations of
336 // the signal handler environment.
337 //
338 kern_return_t self_server_handleSignal(mach_port_t sport,
339 mach_port_t taskPort, int sig)
340 {
341 try {
342 if (taskPort != mach_task_self()) {
343 Syslog::error("handleSignal: received from someone other than myself");
344 secdebug("SS", "unauthorized handleSignal");
345 return 0;
346 }
347 secdebug("SS", "dispatching indirect signal %d", sig);
348 switch (sig) {
349 case SIGCHLD:
350 ServerChild::checkChildren();
351 break;
352 case SIGINT:
353 case SIGTERM:
354 secdebug("SS", "signal %d received: terminating", sig);
355 Syslog::notice("securityd terminating due to signal %d", sig);
356 exit(0);
357 #if defined(DEBUGDUMP)
358 case SIGUSR1:
359 NodeCore::dumpAll();
360 break;
361 #endif //DEBUGDUMP
362 default:
363 assert(false);
364 }
365 } catch(...) {
366 secdebug("SS", "exception handling a signal (ignored)");
367 }
368 mach_port_deallocate(mach_task_self(), taskPort);
369 return 0;
370 }
371
372
373 //
374 // Notifier for system sleep events
375 //
376 void Server::SleepWatcher::systemWillSleep()
377 {
378 secdebug("SS", "sleep notification received");
379 Session::processSystemSleep();
380 secdebug("server", "distributing sleep event to %ld clients", mPowerClients.size());
381 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
382 (*it)->systemWillSleep();
383 }
384
385 void Server::SleepWatcher::systemIsWaking()
386 {
387 secdebug("server", "distributing wakeup event to %ld clients", mPowerClients.size());
388 for (set<PowerWatcher *>::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++)
389 (*it)->systemIsWaking();
390 }
391
392 void Server::SleepWatcher::add(PowerWatcher *client)
393 {
394 assert(mPowerClients.find(client) == mPowerClients.end());
395 mPowerClients.insert(client);
396 }
397
398 void Server::SleepWatcher::remove(PowerWatcher *client)
399 {
400 assert(mPowerClients.find(client) != mPowerClients.end());
401 mPowerClients.erase(client);
402 }
403
404
405 //
406 // Initialize the CSSM/MDS subsystem.
407 // This was once done lazily on demand. These days, we are setting up the
408 // system MDS here, and CSSM is pretty much always needed, so this is called
409 // early during program startup. Do note that the server may not (yet) be running.
410 //
411 void Server::loadCssm()
412 {
413 if (!mCssm->isActive()) {
414 StLock<Mutex> _(*this);
415 if (!mCssm->isActive()) {
416 secdebug("SS", "Installing MDS");
417 MDSClient::mds().install();
418 secdebug("SS", "CSSM initializing");
419 mCssm->init();
420 mCSP->attach();
421 secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString().c_str());
422 }
423 }
424 }