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 <mach/mach_error.h>
27 using namespace MachPlusPlus
;
31 // Construct the server object
33 Server::Server(Authority
&myAuthority
, const char *bootstrapName
)
34 : MachServer(bootstrapName
),
35 mCurrentConnection(false),
36 mCSPModule(gGuidAppleCSP
, mCssm
), mCSP(mCSPModule
),
37 mAuthority(myAuthority
)
39 // engage the subsidiary port handler for sleep notifications
45 // Clean up the server object
54 // Locate a connection by reply port and make it the current connection
55 // of this thread. The connection will be marked busy, and can be accessed
56 // by calling Server::connection() [no argument] until it is released by
57 // calling Connection::endWork().
59 Connection
&Server::connection(mach_port_t port
)
61 Server
&server
= active();
62 StLock
<Mutex
> _(server
.lock
);
63 if (Connection
*conn
= server
.connections
[port
]) {
64 active().mCurrentConnection
= conn
;
68 // unknown client port -- could be a hack attempt
69 CssmError::throwMe(CSSM_ERRCODE_INVALID_CONTEXT_HANDLE
);
72 Connection
&Server::connection(bool tolerant
)
74 Connection
*conn
= active().mCurrentConnection
;
75 assert(conn
); // have to have one
81 void Server::requestComplete()
83 // note: there may not be an active connection if connection setup failed
84 if (Connection
*conn
= active().mCurrentConnection
) {
87 active().mCurrentConnection
= NULL
;
93 // Locate an ACL bearer (database or key) by handle
95 SecurityServerAcl
&Server::aclBearer(AclKind kind
, CSSM_HANDLE handle
)
97 SecurityServerAcl
&bearer
= findHandle
<SecurityServerAcl
>(handle
);
98 if (kind
!= bearer
.kind())
99 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
);
105 // Run the server. This will not return until the server is forced to exit.
109 MachServer::run(0x10000,
110 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) |
111 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
));
116 // The server run-loop function
118 boolean_t
ucsp_server(mach_msg_header_t
*, mach_msg_header_t
*);
120 boolean_t
Server::handle(mach_msg_header_t
*in
, mach_msg_header_t
*out
)
122 return ucsp_server(in
, out
);
127 // Set up a new Connection. This establishes the environment (process et al) as needed
128 // and registers a properly initialized Connection object to run with.
130 void Server::setupConnection(Port replyPort
, Port taskPort
,
131 const security_token_t
&securityToken
, const char *identity
)
133 // first, make or find the process based on task port
134 StLock
<Mutex
> _(lock
);
135 Process
* &proc
= processes
[taskPort
];
137 proc
= new Process(taskPort
, identity
, securityToken
.val
[0], securityToken
.val
[1]);
138 notifyIfDead(taskPort
);
141 // now, establish a connection and register it in the server
142 Connection
*connection
= new Connection(*proc
, replyPort
);
143 if (connections
[replyPort
]) // malicious re-entry attempt?
144 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ error code? (client error)
145 connections
[replyPort
] = connection
;
146 notifyIfDead(replyPort
);
151 // Synchronously end a Connection.
152 // This is due to a request from the client, so no thread races are possible.
154 void Server::endConnection(Port replyPort
)
156 StLock
<Mutex
> _(lock
);
157 Connection
*connection
= connections
[replyPort
];
159 connections
.erase(replyPort
);
160 connection
->terminate();
166 // Take an existing Connection/Process combo. Tear them down even though
167 // the client-side thread/process is still alive and construct new ones in their place.
168 // This is a high-wire act with a frayed net. We use it ONLY to deal with clients
169 // who change their Session (by changing their bootstrap subset port) in mid-stream.
170 // In other words, this is a hack that the client would be well advised to avoid.
171 // (Avoid it by calling SessionCreate before calling any other Security interfaces in
172 // the process's life.)
174 Process
*Server::resetConnection()
176 Connection
*oldConnection
= mCurrentConnection
;
177 Process
*oldProcess
= &oldConnection
->process
;
178 debug("SS", "reset process %p connection %p for session switch",
179 oldProcess
, oldConnection
);
181 Port replyPort
= oldConnection
->clientPort();
183 oldConnection
->endWork();
184 oldConnection
->abort(true);
185 delete oldConnection
;
189 Process
* &proc
= processes
[oldProcess
->taskPort()];
190 proc
= new Process(*oldProcess
);
193 Connection
*connection
= new Connection(*proc
, replyPort
);
194 connections
[replyPort
] = connection
;
195 mCurrentConnection
= connection
;
196 connection
->beginWork();
203 // Handling dead-port notifications.
204 // This receives DPNs for all kinds of ports we're interested in.
206 void Server::notifyDeadName(Port port
)
208 StLock
<Mutex
> _(lock
);
210 // is it a connection?
211 ConnectionMap::iterator conIt
= connections
.find(port
);
212 if (conIt
!= connections
.end()) {
213 Connection
*connection
= conIt
->second
;
214 if (connection
->abort())
216 connections
.erase(conIt
);
221 ProcessMap::iterator procIt
= processes
.find(port
);
222 if (procIt
!= processes
.end()) {
223 Process
*process
= procIt
->second
;
226 processes
.erase(procIt
);
230 // well, it better be a session
231 Session::eliminate(Bootstrap(port
));
236 // Notifier for system sleep events
238 void Server::SleepWatcher::systemWillSleep()
240 debug("SS", "sleep notification received");
241 Database::lockAllDatabases(true);
246 // Return the primary Cryptographic Service Provider.
247 // This will be lazily loaded when it is first requested.
249 CssmClient::CSP
&Server::getCsp()
251 //@@@ not officially pthread-kosher. Use a ModuleNexus here?
252 if (!mCssm
->isActive()) {
254 //@@@ should we abort the server if this fails? What point continuing?
255 StLock
<Mutex
> _(lock
);
256 debug("SS", "CSSM initializing");
259 char guids
[Guid::stringRepLength
+1];
260 IFDEBUG(debug("SS", "CSSM ready with CSP %s", mCSP
->guid().toString(guids
)));