2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
28 // server - the actual SecurityServer server object
30 #include <securityd_client/ucsp.h> // knowledge of mig message sizes
34 #include "notifications.h"
35 #include <mach/mach_error.h>
37 using namespace MachPlusPlus
;
40 // Construct an Authority
42 Authority::Authority(const char *configFile
)
43 : Authorization::Engine(configFile
)
47 Authority::~Authority()
52 // Construct the server object
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
)
61 // engage the subsidiary port handler for sleep notifications
67 // Clean up the server object
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().
81 Connection
&Server::connection(mach_port_t port
)
83 Server
&server
= active();
84 StLock
<Mutex
> _(server
);
85 Connection
*conn
= server
.mConnections
.get(port
, CSSM_ERRCODE_INVALID_CONTEXT_HANDLE
);
86 active().mCurrentConnection() = conn
;
91 Connection
&Server::connection(bool tolerant
)
93 Connection
*conn
= active().mCurrentConnection();
94 assert(conn
); // have to have one
100 void Server::requestComplete()
102 // note: there may not be an active connection if connection setup failed
103 if (RefPointer
<Connection
> &conn
= active().mCurrentConnection()) {
107 IFDUMPING("state", NodeCore::dumpAll());
112 // Shorthand for "current" process and session.
113 // This is the process and session for the current connection.
115 Process
&Server::process()
117 return connection().process();
120 Session
&Server::session()
122 return connection().process().session();
125 RefPointer
<Key
> Server::key(KeyHandle key
)
127 return HandleObject::findRef
<Key
>(key
, CSSMERR_CSP_INVALID_KEY_REFERENCE
);
130 RefPointer
<Database
> Server::database(DbHandle db
)
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
);
139 RefPointer
<KeychainDatabase
> Server::keychain(DbHandle db
)
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
);
148 RefPointer
<Database
> Server::optionalDatabase(DbHandle db
)
151 return &process().localStore();
158 // Locate an ACL bearer (database or key) by handle
160 SecurityServerAcl
&Server::aclBearer(AclKind kind
, CSSM_HANDLE handle
)
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
);
171 // Run the server. This will not return until the server is forced to exit.
175 MachServer::run(0x10000,
176 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) |
177 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
));
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.
187 boolean_t
ucsp_server(mach_msg_header_t
*, mach_msg_header_t
*);
191 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
193 return ucsp_server(in
, out
);
198 static const struct IPCName
{ const char *name
; int ipc
; } ipcNames
[] =
199 { subsystem_to_name_map_ucsp
}; // macro generated by MIG, from ucsp.h
201 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
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
);
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).
222 void Server::setupConnection(ConnectLevel type
, Port servicePort
, Port replyPort
, Port taskPort
,
223 const security_token_t
&securityToken
, const ClientSetupInfo
*info
, const char *identity
)
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
);
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
);
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
);
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.
256 void Server::endConnection(Port replyPort
)
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
);
267 // Handling dead-port notifications.
268 // This receives DPNs for all kinds of ports we're interested in.
270 void Server::notifyDeadName(Port port
)
272 StLock
<Mutex
> _(*this);
273 secdebug("SSports", "port %d is dead", port
.port());
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
);
284 PortMap
<Process
>::iterator procIt
= mProcesses
.find(port
);
285 if (procIt
!= mProcesses
.end()) {
286 procIt
->second
->kill();
287 mProcesses
.erase(procIt
);
291 // is it a notification client?
292 if (Listener::remove(port
))
295 secdebug("server", "spurious dead port notification for port %d", port
.port());
300 // Handling no-senders notifications.
301 // This is currently only used for (subsidiary) service ports
303 void Server::notifyNoSenders(Port port
, mach_port_mscount_t
)
305 secdebug("SSports", "port %d no senders", port
.port());
306 Session::destroy(port
);
311 // Notifier for system sleep events
313 void Server::SleepWatcher::systemWillSleep()
315 secdebug("SS", "sleep notification received");
316 Session::processSystemSleep();
321 // Return the primary Cryptographic Service Provider.
322 // This will be lazily loaded when it is first requested.
324 CssmClient::CSP
&Server::getCsp()
326 if (!mCssm
->isActive())
333 // Initialize the CSSM/MDS subsystem.
334 // This is thread-safe and can be done lazily.
336 static void initMds();
338 void Server::loadCssm()
340 if (!mCssm
->isActive()) {
341 StLock
<Mutex
> _(*this);
342 if (!mCssm
->isActive()) {
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");
356 secdebug("SS", "CSSM initializing");
359 IFDEBUG(char guids
[Guid::stringRepLength
+1]);
360 secdebug("SS", "CSSM ready with CSP %s", mCSP
->guid().toString(guids
));
365 #include <Security/mds.h>
367 static void initMds()
369 secdebug("SS", "MDS initializing");
370 CssmAllocatorMemoryFunctions
memory(Allocator::standard());
373 CssmError::check(MDS_Initialize(NULL
, &memory
, &functions
, &handle
));
374 CssmError::check(MDS_Install(handle
));
375 CssmError::check(MDS_Terminate(handle
));