]> git.saurik.com Git - apple/security.git/blob - SecurityServer/server.cpp
Security-28.tar.gz
[apple/security.git] / SecurityServer / server.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // server - the actual SecurityServer server object
21 //
22 #include "server.h"
23 #include "session.h"
24 #include "acls.h"
25 #include <mach/mach_error.h>
26
27 using namespace MachPlusPlus;
28
29
30 //
31 // Construct the server object
32 //
33 Server::Server(Authority &myAuthority, const char *bootstrapName)
34 : MachServer(bootstrapName),
35 mCurrentConnection(false),
36 mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule),
37 mAuthority(myAuthority)
38 {
39 // engage the subsidiary port handler for sleep notifications
40 add(sleepWatcher);
41 }
42
43
44 //
45 // Clean up the server object
46 //
47 Server::~Server()
48 {
49 //@@@ more later
50 }
51
52
53 //
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().
58 //
59 Connection &Server::connection(mach_port_t port)
60 {
61 Server &server = active();
62 StLock<Mutex> _(server.lock);
63 if (Connection *conn = server.connections[port]) {
64 active().mCurrentConnection = conn;
65 conn->beginWork();
66 return *conn;
67 }
68 // unknown client port -- could be a hack attempt
69 CssmError::throwMe(CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
70 }
71
72 Connection &Server::connection(bool tolerant)
73 {
74 Connection *conn = active().mCurrentConnection;
75 assert(conn); // have to have one
76 if (!tolerant)
77 conn->checkWork();
78 return *conn;
79 }
80
81 void Server::requestComplete()
82 {
83 // note: there may not be an active connection if connection setup failed
84 if (Connection *conn = active().mCurrentConnection) {
85 if (conn->endWork())
86 delete conn;
87 active().mCurrentConnection = NULL;
88 }
89 }
90
91
92 //
93 // Locate an ACL bearer (database or key) by handle
94 //
95 SecurityServerAcl &Server::aclBearer(AclKind kind, CSSM_HANDLE handle)
96 {
97 SecurityServerAcl &bearer = findHandle<SecurityServerAcl>(handle);
98 if (kind != bearer.kind())
99 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE);
100 return bearer;
101 }
102
103
104 //
105 // Run the server. This will not return until the server is forced to exit.
106 //
107 void Server::run()
108 {
109 MachServer::run(0x10000,
110 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
111 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER));
112 }
113
114
115 //
116 // The server run-loop function
117 //
118 boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *);
119
120 boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
121 {
122 return ucsp_server(in, out);
123 }
124
125
126 //
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.
129 //
130 void Server::setupConnection(Port replyPort, Port taskPort,
131 const security_token_t &securityToken, const char *identity)
132 {
133 // first, make or find the process based on task port
134 StLock<Mutex> _(lock);
135 Process * &proc = processes[taskPort];
136 if (proc == NULL) {
137 proc = new Process(taskPort, identity, securityToken.val[0], securityToken.val[1]);
138 notifyIfDead(taskPort);
139 }
140
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);
147 }
148
149
150 //
151 // Synchronously end a Connection.
152 // This is due to a request from the client, so no thread races are possible.
153 //
154 void Server::endConnection(Port replyPort)
155 {
156 StLock<Mutex> _(lock);
157 Connection *connection = connections[replyPort];
158 assert(connection);
159 connections.erase(replyPort);
160 connection->terminate();
161 delete connection;
162 }
163
164
165 //
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.)
173 //
174 Process *Server::resetConnection()
175 {
176 Connection *oldConnection = mCurrentConnection;
177 Process *oldProcess = &oldConnection->process;
178 debug("SS", "reset process %p connection %p for session switch",
179 oldProcess, oldConnection);
180
181 Port replyPort = oldConnection->clientPort();
182
183 oldConnection->endWork();
184 oldConnection->abort(true);
185 delete oldConnection;
186
187 oldProcess->kill();
188
189 Process * &proc = processes[oldProcess->taskPort()];
190 proc = new Process(*oldProcess);
191 delete oldProcess;
192
193 Connection *connection = new Connection(*proc, replyPort);
194 connections[replyPort] = connection;
195 mCurrentConnection = connection;
196 connection->beginWork();
197
198 return proc;
199 }
200
201
202 //
203 // Handling dead-port notifications.
204 // This receives DPNs for all kinds of ports we're interested in.
205 //
206 void Server::notifyDeadName(Port port)
207 {
208 StLock<Mutex> _(lock);
209
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())
215 delete connection;
216 connections.erase(conIt);
217 return;
218 }
219
220 // is it a process?
221 ProcessMap::iterator procIt = processes.find(port);
222 if (procIt != processes.end()) {
223 Process *process = procIt->second;
224 if (process->kill())
225 delete process;
226 processes.erase(procIt);
227 return;
228 }
229
230 // well, it better be a session
231 Session::eliminate(Bootstrap(port));
232 }
233
234
235 //
236 // Notifier for system sleep events
237 //
238 void Server::SleepWatcher::systemWillSleep()
239 {
240 debug("SS", "sleep notification received");
241 Database::lockAllDatabases(true);
242 }
243
244
245 //
246 // Return the primary Cryptographic Service Provider.
247 // This will be lazily loaded when it is first requested.
248 //
249 CssmClient::CSP &Server::getCsp()
250 {
251 //@@@ not officially pthread-kosher. Use a ModuleNexus here?
252 if (!mCssm->isActive()) {
253 // first time load
254 //@@@ should we abort the server if this fails? What point continuing?
255 StLock<Mutex> _(lock);
256 debug("SS", "CSSM initializing");
257 mCssm->init();
258 mCSP->attach();
259 char guids[Guid::stringRepLength+1];
260 IFDEBUG(debug("SS", "CSSM ready with CSP %s", mCSP->guid().toString(guids)));
261 }
262 return mCSP;
263 }