]> git.saurik.com Git - apple/securityd.git/blob - src/server.cpp
af82dd77e08a011a995c0c733ddcfb349cbc89df
[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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26
27 //
28 // server - the actual SecurityServer server object
29 //
30 #include <securityd_client/ucsp.h> // knowledge of mig message sizes
31 #include "server.h"
32 #include "session.h"
33 #include "acls.h"
34 #include "notifications.h"
35 #include <mach/mach_error.h>
36
37 using namespace MachPlusPlus;
38
39 //
40 // Construct an Authority
41 //
42 Authority::Authority(const char *configFile)
43 : Authorization::Engine(configFile)
44 {
45 }
46
47 Authority::~Authority()
48 {
49 }
50
51 //
52 // Construct the server object
53 //
54 Server::Server(Authority &authority, CodeSignatures &signatures, const char *bootstrapName)
55 : MachServer(bootstrapName),
56 mBootstrapName(bootstrapName),
57 mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule),
58 mAuthority(authority),
59 mCodeSignatures(signatures)
60 {
61 // engage the subsidiary port handler for sleep notifications
62 add(sleepWatcher);
63 }
64
65
66 //
67 // Clean up the server object
68 //
69 Server::~Server()
70 {
71 //@@@ more later
72 }
73
74
75 //
76 // Locate a connection by reply port and make it the current connection
77 // of this thread. The connection will be marked busy, and can be accessed
78 // by calling Server::connection() [no argument] until it is released by
79 // calling Connection::endWork().
80 //
81 Connection &Server::connection(mach_port_t port)
82 {
83 Server &server = active();
84 StLock<Mutex> _(server);
85 Connection *conn = server.mConnections.get(port, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
86 active().mCurrentConnection() = conn;
87 conn->beginWork();
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()
101 {
102 // note: there may not be an active connection if connection setup failed
103 if (RefPointer<Connection> &conn = active().mCurrentConnection()) {
104 conn->endWork();
105 conn = NULL;
106 }
107 IFDUMPING("state", NodeCore::dumpAll());
108 }
109
110
111 //
112 // Shorthand for "current" process and session.
113 // This is the process and session for the current connection.
114 //
115 Process &Server::process()
116 {
117 return connection().process();
118 }
119
120 Session &Server::session()
121 {
122 return connection().process().session();
123 }
124
125 RefPointer<Key> Server::key(KeyHandle key)
126 {
127 return HandleObject::findRef<Key>(key, CSSMERR_CSP_INVALID_KEY_REFERENCE);
128 }
129
130 RefPointer<Database> Server::database(DbHandle db)
131 {
132 RefPointer<Database> database =
133 HandleObject::findRef<Database>(db, CSSMERR_DL_INVALID_DB_HANDLE);
134 if (database->process() != process())
135 CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
136 return database;
137 }
138
139 RefPointer<KeychainDatabase> Server::keychain(DbHandle db)
140 {
141 RefPointer<KeychainDatabase> keychain =
142 HandleObject::findRef<KeychainDatabase>(db, CSSMERR_DL_INVALID_DB_HANDLE);
143 if (keychain->process() != process())
144 CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
145 return keychain;
146 }
147
148 RefPointer<Database> Server::optionalDatabase(DbHandle db)
149 {
150 if (db == noDb)
151 return &process().localStore();
152 else
153 return database(db);
154 }
155
156
157 //
158 // Locate an ACL bearer (database or key) by handle
159 //
160 SecurityServerAcl &Server::aclBearer(AclKind kind, CSSM_HANDLE handle)
161 {
162 SecurityServerAcl &bearer =
163 HandleObject::find<SecurityServerAcl>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
164 if (kind != bearer.kind())
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_SENDER));
178 }
179
180
181 //
182 // The primary server run-loop function.
183 // Invokes the MIG-generated main dispatch function (ucsp_server).
184 // For debug builds, look up request names in a MIG-generated table
185 // for better debug-log messages.
186 //
187 boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *);
188
189 #if defined(NDEBUG)
190
191 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
192 {
193 return ucsp_server(in, out);
194 }
195
196 #else //NDEBUG
197
198 static const struct IPCName { const char *name; int ipc; } ipcNames[] =
199 { subsystem_to_name_map_ucsp }; // macro generated by MIG, from ucsp.h
200
201 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
202 {
203 const int first = ipcNames[0].ipc;
204 const char *name = (in->msgh_id >= first && in->msgh_id < first + ucsp_MSG_COUNT) ?
205 ipcNames[in->msgh_id - first].name : "OUT OF BOUNDS";
206 secdebug("SSreq", "begin %s (%d)", name, in->msgh_id);
207 boolean_t result = ucsp_server(in, out);
208 secdebug("SSreq", "end %s (%d)", name, in->msgh_id);
209 return result;
210 }
211
212 #endif //NDEBUG
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 servicePort, Port replyPort, Port taskPort,
223 const security_token_t &securityToken, const ClientSetupInfo *info, const char *identity)
224 {
225 // first, make or find the process based on task port
226 StLock<Mutex> _(*this);
227 RefPointer<Process> &proc = mProcesses[taskPort];
228 if (type == connectNewSession && proc) {
229 // The client has talked to us before and now wants to create a new session.
230 proc->changeSession(servicePort);
231 }
232 if (!proc) {
233 if (type == connectNewThread) // client error (or attack)
234 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
235 assert(info && identity);
236 proc = new Process(servicePort, taskPort, info, identity,
237 securityToken.val[0], securityToken.val[1]);
238 notifyIfDead(taskPort);
239 }
240
241 // now, establish a connection and register it in the server
242 Connection *connection = new Connection(*proc, replyPort);
243 if (mConnections.contains(replyPort)) // malicious re-entry attempt?
244 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); //@@@ error code? (client error)
245 mConnections[replyPort] = connection;
246 notifyIfDead(replyPort);
247 }
248
249
250 //
251 // Synchronously end a Connection.
252 // This is due to a request from the client, so no thread races are possible.
253 // In practice, this is optional since the DPN for the client thread reply port
254 // will destroy the connection anyway when the thread dies.
255 //
256 void Server::endConnection(Port replyPort)
257 {
258 StLock<Mutex> _(*this);
259 PortMap<Connection>::iterator it = mConnections.find(replyPort);
260 assert(it != mConnections.end());
261 it->second->terminate();
262 mConnections.erase(it);
263 }
264
265
266 //
267 // Handling dead-port notifications.
268 // This receives DPNs for all kinds of ports we're interested in.
269 //
270 void Server::notifyDeadName(Port port)
271 {
272 StLock<Mutex> _(*this);
273 secdebug("SSports", "port %d is dead", port.port());
274
275 // is it a connection?
276 PortMap<Connection>::iterator conIt = mConnections.find(port);
277 if (conIt != mConnections.end()) {
278 conIt->second->abort();
279 mConnections.erase(conIt);
280 return;
281 }
282
283 // is it a process?
284 PortMap<Process>::iterator procIt = mProcesses.find(port);
285 if (procIt != mProcesses.end()) {
286 procIt->second->kill();
287 mProcesses.erase(procIt);
288 return;
289 }
290
291 // is it a notification client?
292 if (Listener::remove(port))
293 return;
294
295 secdebug("server", "spurious dead port notification for port %d", port.port());
296 }
297
298
299 //
300 // Handling no-senders notifications.
301 // This is currently only used for (subsidiary) service ports
302 //
303 void Server::notifyNoSenders(Port port, mach_port_mscount_t)
304 {
305 secdebug("SSports", "port %d no senders", port.port());
306 Session::destroy(port);
307 }
308
309
310 //
311 // Notifier for system sleep events
312 //
313 void Server::SleepWatcher::systemWillSleep()
314 {
315 secdebug("SS", "sleep notification received");
316 Session::processSystemSleep();
317 }
318
319
320 //
321 // Return the primary Cryptographic Service Provider.
322 // This will be lazily loaded when it is first requested.
323 //
324 CssmClient::CSP &Server::getCsp()
325 {
326 if (!mCssm->isActive())
327 loadCssm();
328 return mCSP;
329 }
330
331
332 //
333 // Initialize the CSSM/MDS subsystem.
334 // This is thread-safe and can be done lazily.
335 //
336 static void initMds();
337
338 void Server::loadCssm()
339 {
340 if (!mCssm->isActive()) {
341 StLock<Mutex> _(*this);
342 if (!mCssm->isActive()) {
343 try {
344 initMds();
345 } catch (const CssmError &error) {
346 switch (error.osStatus()) {
347 case CSSMERR_DL_MDS_ERROR:
348 case CSSMERR_DL_OS_ACCESS_DENIED:
349 secdebug("SS", "MDS initialization failed; continuing");
350 Syslog::warning("MDS initialization failed; continuing");
351 break;
352 default:
353 throw;
354 }
355 }
356 secdebug("SS", "CSSM initializing");
357 mCssm->init();
358 mCSP->attach();
359 IFDEBUG(char guids[Guid::stringRepLength+1]);
360 secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString(guids));
361 }
362 }
363 }
364
365 #include <Security/mds.h>
366
367 static void initMds()
368 {
369 secdebug("SS", "MDS initializing");
370 CssmAllocatorMemoryFunctions memory(Allocator::standard());
371 MDS_FUNCS functions;
372 MDS_HANDLE handle;
373 CssmError::check(MDS_Initialize(NULL, &memory, &functions, &handle));
374 CssmError::check(MDS_Install(handle));
375 CssmError::check(MDS_Terminate(handle));
376 }