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
&myAuthority
, const char *bootstrapName
)
36 : MachServer(bootstrapName
),
37 mBootstrapName(bootstrapName
),
38 mCurrentConnection(false),
39 mCSPModule(gGuidAppleCSP
, mCssm
), mCSP(mCSPModule
),
40 mAuthority(myAuthority
)
42 // engage the subsidiary port handler for sleep notifications
48 // Clean up the server object
57 // Locate a connection by reply port and make it the current connection
58 // of this thread. The connection will be marked busy, and can be accessed
59 // by calling Server::connection() [no argument] until it is released by
60 // calling Connection::endWork().
62 Connection
&Server::connection(mach_port_t port
)
64 Server
&server
= active();
65 StLock
<Mutex
> _(server
.lock
);
66 if (Connection
*conn
= server
.connections
[port
]) {
67 active().mCurrentConnection
= conn
;
71 // unknown client port -- could be a hack attempt
72 CssmError::throwMe(CSSM_ERRCODE_INVALID_CONTEXT_HANDLE
);
75 Connection
&Server::connection(bool tolerant
)
77 Connection
*conn
= active().mCurrentConnection
;
78 assert(conn
); // have to have one
84 void Server::requestComplete()
86 // note: there may not be an active connection if connection setup failed
87 if (Connection
*conn
= active().mCurrentConnection
) {
90 active().mCurrentConnection
= NULL
;
96 // Locate an ACL bearer (database or key) by handle
98 SecurityServerAcl
&Server::aclBearer(AclKind kind
, CSSM_HANDLE handle
)
100 SecurityServerAcl
&bearer
= findHandle
<SecurityServerAcl
>(handle
);
101 if (kind
!= bearer
.kind())
102 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
);
108 // Run the server. This will not return until the server is forced to exit.
112 MachServer::run(0x10000,
113 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) |
114 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
));
119 // The primary server run-loop function.
120 // Invokes the MIG-generated main dispatch function (ucsp_server).
121 // For debug builds, look up request names in a MIG-generated table
122 // for better debug-log messages.
124 boolean_t
ucsp_server(mach_msg_header_t
*, mach_msg_header_t
*);
128 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
130 return ucsp_server(in
, out
);
135 static const struct IPCName
{ const char *name
; int ipc
; } ipcNames
[] =
136 { subsystem_to_name_map_ucsp
}; // macro generated by MIG, from ucsp.h
138 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
140 const int first
= ipcNames
[0].ipc
;
141 assert(in
->msgh_id
>= first
&& in
->msgh_id
< first
+ ucsp_MSG_COUNT
);
142 const char *name
= ipcNames
[in
->msgh_id
- first
].name
;
143 debug("SSreq", "begin %s (%d)", name
, in
->msgh_id
);
144 boolean_t result
= ucsp_server(in
, out
);
145 debug("SSreq", "end %s (%d)", name
, in
->msgh_id
);
153 // Set up a new Connection. This establishes the environment (process et al) as needed
154 // and registers a properly initialized Connection object to run with.
156 void Server::setupConnection(Port servicePort
, Port replyPort
, Port taskPort
,
157 const security_token_t
&securityToken
, const char *identity
)
159 // first, make or find the process based on task port
160 StLock
<Mutex
> _(lock
);
161 Process
* &proc
= processes
[taskPort
];
163 proc
= new Process(servicePort
, taskPort
, identity
,
164 securityToken
.val
[0], securityToken
.val
[1]);
165 notifyIfDead(taskPort
);
168 // now, establish a connection and register it in the server
169 Connection
*connection
= new Connection(*proc
, replyPort
);
170 if (connections
[replyPort
]) // malicious re-entry attempt?
171 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ error code? (client error)
172 connections
[replyPort
] = connection
;
173 notifyIfDead(replyPort
);
178 // Synchronously end a Connection.
179 // This is due to a request from the client, so no thread races are possible.
181 void Server::endConnection(Port replyPort
)
183 StLock
<Mutex
> _(lock
);
184 Connection
*connection
= connections
[replyPort
];
186 connections
.erase(replyPort
);
187 connection
->terminate();
193 // Take an existing Connection/Process combo. Tear them down even though
194 // the client-side thread/process is still alive and construct new ones in their place.
195 // This is a high-wire act with a frayed net. We use it ONLY to deal with clients
196 // who change their Session (by changing their bootstrap subset port) in mid-stream.
197 // In other words, this is a hack that the client would be well advised to avoid.
198 // (Avoid it by calling SessionCreate before calling any other Security interfaces in
199 // the process's life.)
202 Process
*Server::resetConnection()
204 Connection
*oldConnection
= mCurrentConnection
;
205 Process
*oldProcess
= &oldConnection
->process
;
206 debug("SS", "reset process %p connection %p for session switch",
207 oldProcess
, oldConnection
);
209 Port replyPort
= oldConnection
->clientPort();
211 oldConnection
->endWork();
212 oldConnection
->abort(true);
213 delete oldConnection
;
217 Process
* &proc
= processes
[oldProcess
->taskPort()];
218 proc
= new Process(*oldProcess
);
221 Connection
*connection
= new Connection(*proc
, replyPort
);
222 connections
[replyPort
] = connection
;
223 mCurrentConnection
= connection
;
224 connection
->beginWork();
232 // Handling dead-port notifications.
233 // This receives DPNs for all kinds of ports we're interested in.
235 void Server::notifyDeadName(Port port
)
237 StLock
<Mutex
> _(lock
);
238 debug("SSports", "port %d is dead", port
.port());
240 // is it a connection?
241 ConnectionMap::iterator conIt
= connections
.find(port
);
242 if (conIt
!= connections
.end()) {
243 Connection
*connection
= conIt
->second
;
244 if (connection
->abort())
246 connections
.erase(conIt
);
251 ProcessMap::iterator procIt
= processes
.find(port
);
252 if (procIt
!= processes
.end()) {
253 Process
*process
= procIt
->second
;
256 processes
.erase(procIt
);
260 // is it a notification client?
261 if (Listener::remove(port
))
264 debug("server", "spurious dead port notification for port %d", port
.port());
269 // Handling no-senders notifications.
270 // This is currently only used for (subsidiary) service ports
272 void Server::notifyNoSenders(Port port
, mach_port_mscount_t
)
274 debug("SSports", "port %d no senders", port
.port());
275 Session::eliminate(port
);
280 // Notifier for system sleep events
282 void Server::SleepWatcher::systemWillSleep()
284 debug("SS", "sleep notification received");
285 Database::lockAllDatabases(true);
290 // Return the primary Cryptographic Service Provider.
291 // This will be lazily loaded when it is first requested.
293 CssmClient::CSP
&Server::getCsp()
295 if (!mCssm
->isActive())
302 // Initialize the CSSM/MDS subsystem.
303 // This is thread-safe and can be done lazily.
305 static void initMds();
307 void Server::loadCssm()
309 if (!mCssm
->isActive()) {
310 StLock
<Mutex
> _(lock
);
311 if (!mCssm
->isActive()) {
313 debug("SS", "CSSM initializing");
316 char guids
[Guid::stringRepLength
+1];
317 IFDEBUG(debug("SS", "CSSM ready with CSP %s", mCSP
->guid().toString(guids
)));
322 #include <Security/mds.h>
324 static void initMds()
326 debug("SS", "MDS initializing");
327 CssmAllocatorMemoryFunctions
memory(CssmAllocator::standard());
330 CssmError::check(MDS_Initialize(NULL
, &memory
, &functions
, &handle
));
331 CssmError::check(MDS_Install(handle
));
332 CssmError::check(MDS_Terminate(handle
));