2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // server - the actual SecurityServer server object
25 #include "notifications.h"
27 #include <mach/mach_error.h>
29 using namespace MachPlusPlus
;
33 // Construct the server object
35 Server::Server(Authority
&authority
, CodeSignatures
&signatures
, const char *bootstrapName
)
36 : MachServer(bootstrapName
),
37 mBootstrapName(bootstrapName
),
38 mCurrentConnection(false),
39 mCSPModule(gGuidAppleCSP
, mCssm
), mCSP(mCSPModule
),
40 mAuthority(authority
),
41 mCodeSignatures(signatures
)
43 // engage the subsidiary port handler for sleep notifications
49 // Clean up the server object
58 // Locate a connection by reply port and make it the current connection
59 // of this thread. The connection will be marked busy, and can be accessed
60 // by calling Server::connection() [no argument] until it is released by
61 // calling Connection::endWork().
63 Connection
&Server::connection(mach_port_t port
)
65 Server
&server
= active();
66 StLock
<Mutex
> _(server
.lock
);
67 ConnectionMap::iterator it
= server
.connections
.find(port
);
68 if (it
== server
.connections
.end()) // unknown client port -- could be a hack attempt
69 CssmError::throwMe(CSSM_ERRCODE_INVALID_CONTEXT_HANDLE
);
70 Connection
*conn
= it
->second
;
71 active().mCurrentConnection
= conn
;
76 Connection
&Server::connection(bool tolerant
)
78 Connection
*conn
= active().mCurrentConnection
;
79 assert(conn
); // have to have one
85 void Server::requestComplete()
87 // note: there may not be an active connection if connection setup failed
88 if (Connection
*conn
= active().mCurrentConnection
) {
91 active().mCurrentConnection
= NULL
;
97 // Locate an ACL bearer (database or key) by handle
99 SecurityServerAcl
&Server::aclBearer(AclKind kind
, CSSM_HANDLE handle
)
101 SecurityServerAcl
&bearer
= findHandle
<SecurityServerAcl
>(handle
);
102 if (kind
!= bearer
.kind())
103 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
);
109 // Run the server. This will not return until the server is forced to exit.
113 MachServer::run(0x10000,
114 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) |
115 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
));
120 // The primary server run-loop function.
121 // Invokes the MIG-generated main dispatch function (ucsp_server).
122 // For debug builds, look up request names in a MIG-generated table
123 // for better debug-log messages.
125 boolean_t
ucsp_server(mach_msg_header_t
*, mach_msg_header_t
*);
129 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
131 return ucsp_server(in
, out
);
136 static const struct IPCName
{ const char *name
; int ipc
; } ipcNames
[] =
137 { subsystem_to_name_map_ucsp
}; // macro generated by MIG, from ucsp.h
139 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
141 const int first
= ipcNames
[0].ipc
;
142 const char *name
= (in
->msgh_id
>= first
&& in
->msgh_id
< first
+ ucsp_MSG_COUNT
) ?
143 ipcNames
[in
->msgh_id
- first
].name
: "OUT OF BOUNDS";
144 secdebug("SSreq", "begin %s (%d)", name
, in
->msgh_id
);
145 boolean_t result
= ucsp_server(in
, out
);
146 secdebug("SSreq", "end %s (%d)", name
, in
->msgh_id
);
154 // Set up a new Connection. This establishes the environment (process et al) as needed
155 // and registers a properly initialized Connection object to run with.
156 // Type indicates how "deep" we need to initialize (new session, process, or connection).
157 // Everything at and below that level is constructed. This is straight-forward except
158 // in the case of session re-initialization (see below).
160 void Server::setupConnection(ConnectLevel type
, Port servicePort
, Port replyPort
, Port taskPort
,
161 const security_token_t
&securityToken
, const ClientSetupInfo
*info
, const char *identity
)
163 // first, make or find the process based on task port
164 StLock
<Mutex
> _(lock
);
165 Process
* &proc
= processes
[taskPort
];
166 if (type
== connectNewSession
&& proc
) {
167 // The client has talked to us before and now wants to create a new session.
168 // We'll unmoor the old process object and cast it adrift (it will die either now
169 // or later following the usual deferred-death mechanics).
170 // The connection object will die (it's probably already dead) because the client
171 // has destroyed its replyPort. So we don't worry about this here.
172 secdebug("server", "session setup - marooning old process %p(%d) of session %p",
173 proc
, proc
->pid(), &proc
->session
);
174 if (proc
->kill(true))
179 if (type
== connectNewThread
) // client error (or attack)
180 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
181 assert(info
&& identity
);
182 proc
= new Process(servicePort
, taskPort
, info
, identity
,
183 securityToken
.val
[0], securityToken
.val
[1]);
184 notifyIfDead(taskPort
);
187 // now, establish a connection and register it in the server
188 Connection
*connection
= new Connection(*proc
, replyPort
);
189 if (connections
[replyPort
]) // malicious re-entry attempt?
190 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ error code? (client error)
191 connections
[replyPort
] = connection
;
192 notifyIfDead(replyPort
);
197 // Synchronously end a Connection.
198 // This is due to a request from the client, so no thread races are possible.
200 void Server::endConnection(Port replyPort
)
202 StLock
<Mutex
> _(lock
);
203 Connection
*connection
= connections
[replyPort
];
205 connections
.erase(replyPort
);
206 connection
->terminate();
212 // Handling dead-port notifications.
213 // This receives DPNs for all kinds of ports we're interested in.
215 void Server::notifyDeadName(Port port
)
217 StLock
<Mutex
> _(lock
);
218 secdebug("SSports", "port %d is dead", port
.port());
220 // is it a connection?
221 ConnectionMap::iterator conIt
= connections
.find(port
);
222 if (conIt
!= connections
.end()) {
223 Connection
*connection
= conIt
->second
;
224 if (connection
->abort())
226 connections
.erase(conIt
);
231 ProcessMap::iterator procIt
= processes
.find(port
);
232 if (procIt
!= processes
.end()) {
233 Process
*process
= procIt
->second
;
236 processes
.erase(procIt
);
240 // is it a notification client?
241 if (Listener::remove(port
))
244 secdebug("server", "spurious dead port notification for port %d", port
.port());
249 // Handling no-senders notifications.
250 // This is currently only used for (subsidiary) service ports
252 void Server::notifyNoSenders(Port port
, mach_port_mscount_t
)
254 secdebug("SSports", "port %d no senders", port
.port());
255 Session::eliminate(port
);
260 // Notifier for system sleep events
262 void Server::SleepWatcher::systemWillSleep()
264 secdebug("SS", "sleep notification received");
265 Session::lockAllDatabases(true);
270 // Return the primary Cryptographic Service Provider.
271 // This will be lazily loaded when it is first requested.
273 CssmClient::CSP
&Server::getCsp()
275 if (!mCssm
->isActive())
282 // Initialize the CSSM/MDS subsystem.
283 // This is thread-safe and can be done lazily.
285 static void initMds();
287 void Server::loadCssm()
289 if (!mCssm
->isActive()) {
290 StLock
<Mutex
> _(lock
);
291 if (!mCssm
->isActive()) {
294 } catch (const CssmError
&error
) {
295 switch (error
.cssmError()) {
296 case CSSMERR_DL_MDS_ERROR
:
297 case CSSMERR_DL_OS_ACCESS_DENIED
:
298 secdebug("SS", "MDS initialization failed; continuing");
299 Syslog::warning("MDS initialization failed; continuing");
305 secdebug("SS", "CSSM initializing");
308 IFDEBUG(char guids
[Guid::stringRepLength
+1]);
309 secdebug("SS", "CSSM ready with CSP %s", mCSP
->guid().toString(guids
));
314 #include <Security/mds.h>
316 static void initMds()
318 secdebug("SS", "MDS initializing");
319 CssmAllocatorMemoryFunctions
memory(CssmAllocator::standard());
322 CssmError::check(MDS_Initialize(NULL
, &memory
, &functions
, &handle
));
323 CssmError::check(MDS_Install(handle
));
324 CssmError::check(MDS_Terminate(handle
));