]> git.saurik.com Git - apple/security.git/blob - SecurityServer/process.cpp
Security-176.tar.gz
[apple/security.git] / SecurityServer / process.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 // process - track a single client process and its belongings
21 //
22 #include "process.h"
23 #include "server.h"
24 #include "session.h"
25 #include "authority.h"
26 #include "flippers.h"
27
28
29 //
30 // Construct a Process object.
31 //
32 Process::Process(Port servicePort, TaskPort taskPort,
33 const ClientSetupInfo *info, const char *identity, uid_t uid, gid_t gid)
34 : session(Session::find(servicePort)), mBusyCount(0), mDying(false),
35 mTaskPort(taskPort), mByteFlipped(false), mUid(uid), mGid(gid),
36 mClientIdent(deferred)
37 {
38 // examine info passed
39 assert(info);
40 uint32 pversion = info->version;
41 if (pversion == SSPROTOVERSION) {
42 // correct protocol, same byte order, cool
43 } else {
44 Flippers::flip(pversion);
45 if (pversion == SSPROTOVERSION) {
46 // correct protocol, reversed byte order
47 mByteFlipped = true;
48 } else {
49 // unsupported protocol version
50 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
51 }
52 }
53
54 // let's take a look at our wannabe client...
55 mPid = mTaskPort.pid();
56
57 // register with the session
58 session.addProcess(this);
59
60 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
61 this, mPid, mUid, mGid, &session,
62 mTaskPort.port(),
63 mByteFlipped ? "FLIP " : "",
64 (identity && identity[0]) ? identity : "(unknown)");
65
66 try {
67 mClientCode = CodeSigning::OSXCode::decode(identity);
68 } catch (...) {
69 secdebug("SS", "process %p(%d) identity decode threw exception", this, pid());
70 }
71 if (!mClientCode) {
72 mClientIdent = unknown; // no chance to squeeze a code identity from this
73 secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid());
74 }
75 }
76
77
78 Process::~Process()
79 {
80 assert(mBusyCount == 0); // mustn't die with Connections referencing us
81
82 // tell all our authorizations that we're gone
83 IFDEBUG(if (!mAuthorizations.empty())
84 secdebug("SS", "Process %p(%d) clearing %d authorizations",
85 this, mPid, int(mAuthorizations.size())));
86 for (AuthorizationSet::iterator it = mAuthorizations.begin();
87 it != mAuthorizations.end(); ) {
88 AuthorizationToken *auth = *it;
89 while (++it != mAuthorizations.end() && *it == auth) ; // Skip duplicates
90 if (auth->endProcess(*this))
91 delete auth;
92 }
93
94 // remove all database handles that belong to this process
95 IFDEBUG(if (!mDatabases.empty())
96 secdebug("SS", "Process %p(%d) clearing %d database handles",
97 this, mPid, int(mDatabases.size())));
98 for (DatabaseSet::iterator it = mDatabases.begin();
99 it != mDatabases.end(); it++)
100 delete *it;
101
102 // no need to lock here; the client process has no more active threads
103 secdebug("SS", "Process %p(%d) has died", this, mPid);
104
105 // release our name for the process's task port
106 if (mTaskPort)
107 mTaskPort.destroy();
108
109 // deregister from session
110 if (session.removeProcess(this))
111 delete &session;
112 }
113
114 bool Process::kill(bool keepTaskPort)
115 {
116 StLock<Mutex> _(mLock);
117 if (keepTaskPort)
118 mTaskPort = Port(); // clear port so we don't destroy it later
119 if (mBusyCount == 0) {
120 return true; // destroy me now
121 } else {
122 secdebug("SS", "Process %p(%d) destruction deferred for %d busy connections",
123 this, mPid, int(mBusyCount));
124 mDying = true;
125 return false; // destroy me later
126 }
127 }
128
129
130 //
131 // Connection management
132 //
133 void Process::beginConnection(Connection &)
134 {
135 StLock<Mutex> _(mLock);
136 mBusyCount++;
137 }
138
139 bool Process::endConnection(Connection &)
140 {
141 StLock<Mutex> _(mLock);
142 return --mBusyCount == 0 && mDying;
143 }
144
145
146 //
147 // Database management
148 //
149 void Process::addDatabase(Database *database)
150 {
151 StLock<Mutex> _(mLock);
152 mDatabases.insert(database);
153 }
154
155 void Process::removeDatabase(Database *database)
156 {
157 StLock<Mutex> _(mLock);
158 assert(mDatabases.find(database) != mDatabases.end());
159 mDatabases.erase(database);
160 }
161
162
163 //
164 // CodeSignatures implementation of Identity.
165 // The caller must make sure we have a valid (not necessarily hash-able) clientCode().
166 //
167 string Process::getPath() const
168 {
169 assert(mClientCode);
170 return mClientCode->canonicalPath();
171 }
172
173 const CssmData Process::getHash(CodeSigning::OSXSigner &signer) const
174 {
175 switch (mClientIdent) {
176 case deferred:
177 try {
178 // try to calculate our signature hash (first time use)
179 mCachedSignature.reset(mClientCode->sign(signer));
180 assert(mCachedSignature.get());
181 mClientIdent = known;
182 secdebug("SS", "process %p(%d) code signature computed", this, pid());
183 break;
184 } catch (...) {
185 // couldn't get client signature (unreadable, gone, hack attack, ...)
186 mClientIdent = unknown;
187 secdebug("SS", "process %p(%d) no code signature - anonymous", this, pid());
188 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION);
189 }
190 case known:
191 assert(mCachedSignature.get());
192 break;
193 case unknown:
194 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION);
195 }
196 return CssmData(*mCachedSignature);
197 }
198
199
200 //
201 // Authorization set maintainance
202 //
203 void Process::addAuthorization(AuthorizationToken *auth)
204 {
205 assert(auth);
206 StLock<Mutex> _(mLock);
207 mAuthorizations.insert(auth);
208 auth->addProcess(*this);
209 }
210
211 void Process::checkAuthorization(AuthorizationToken *auth)
212 {
213 assert(auth);
214 StLock<Mutex> _(mLock);
215 if (mAuthorizations.find(auth) == mAuthorizations.end())
216 MacOSError::throwMe(errAuthorizationInvalidRef);
217 }
218
219 bool Process::removeAuthorization(AuthorizationToken *auth)
220 {
221 assert(auth);
222 StLock<Mutex> _(mLock);
223 // we do everything with a single set lookup call...
224 typedef AuthorizationSet::iterator Iter;
225 Iter it = mAuthorizations.lower_bound(auth);
226 bool isLast;
227 if (it == mAuthorizations.end() || auth != *it) {
228 Syslog::error("process is missing authorization to remove"); // temp. diagnostic
229 isLast = true;
230 } else {
231 Iter next = it; ++next; // following element
232 isLast = (next == mAuthorizations.end()) || auth != *next;
233 mAuthorizations.erase(it); // remove first match
234 }
235 if (isLast) {
236 if (auth->endProcess(*this)) // ... tell it to remove us,
237 return true; // ... and tell the caller
238 }
239 return false; // keep the auth; it's still in use
240 }
241
242
243 //
244 // Notification client maintainance
245 //
246 void Process::requestNotifications(Port port, Listener::Domain domain, Listener::EventMask events)
247 {
248 new Listener(*this, port, domain, events);
249 }
250
251 void Process::stopNotifications(Port port)
252 {
253 if (!Listener::remove(port))
254 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); //@@@ bad name (should be "no such callback")
255 }
256
257 void Process::postNotification(Listener::Domain domain, Listener::Event event, const CssmData &data)
258 {
259 Listener::notify(domain, event, data);
260 }
261