]> git.saurik.com Git - apple/securityd.git/blob - src/process.cpp
securityd-26674.tar.gz
[apple/securityd.git] / src / process.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // process - track a single client process and its belongings
27 //
28 #include "process.h"
29 #include "server.h"
30 #include "session.h"
31 #include "tempdatabase.h"
32 #include "authority.h"
33 #include "flippers.h"
34
35
36 //
37 // Construct a Process object.
38 //
39 Process::Process(Port servicePort, TaskPort taskPort,
40 const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit)
41 : mTaskPort(taskPort), mByteFlipped(false), mPid(audit.pid()), mUid(audit.euid()), mGid(audit.egid())
42 {
43 // set parent session
44 parent(Session::find(servicePort));
45
46 // let's take a look at our wannabe client...
47 if (mTaskPort.pid() != mPid) {
48 secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d) for %s",
49 mPid, mTaskPort.port(), mTaskPort.pid(),
50 (identity && identity[0]) ? identity : "(unknown)");
51 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); // you lied!
52 }
53
54 setup(info, identity);
55
56 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
57 this, mPid, mUid, mGid, &session(),
58 mTaskPort.port(),
59 mByteFlipped ? "FLIP " : "",
60 (identity && identity[0]) ? identity : "(unknown)");
61 }
62
63
64 //
65 // Screen a process setup request for an existing process.
66 // This usually means the client has called exec(2) and forgotten all about itself.
67 // Though it could be a nefarious attempt to fool us...
68 //
69 void Process::reset(Port servicePort, TaskPort taskPort,
70 const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit)
71 {
72 if (servicePort != session().servicePort() || taskPort != mTaskPort) {
73 secdebug("SS", "Process %p(%d) reset mismatch (sp %d-%d, tp %d-%d) for %s",
74 this, pid(), servicePort.port(), session().servicePort().port(), taskPort.port(), mTaskPort.port(),
75 (identity && identity[0]) ? identity : "(unknown)");
76 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); // liar
77 }
78
79 setup(info, identity);
80
81 secdebug("SS", "process %p(%d) has reset; now %sfor %s",
82 this, mPid, mByteFlipped ? "FLIP " : "",
83 (identity && identity[0]) ? identity : "(unknown)");
84 }
85
86
87 //
88 // Common set processing
89 //
90 void Process::setup(const ClientSetupInfo *info, const char *identity)
91 {
92 // process setup info
93 assert(info);
94 uint32 pversion;
95 if (info->order == 0x1234) { // right side up
96 pversion = info->version;
97 } else if (info->order == 0x34120000) { // flip side up
98 pversion = ntohl(info->version);
99 mByteFlipped = true;
100 } else // non comprende
101 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
102
103 // check wire protocol version
104 if (pversion != SSPROTOVERSION)
105 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
106
107 // process identity (if given)
108 try {
109 mClientCode = OSXCode::decode(identity);
110 mClientIdent = deferred; // will calculate code identity when needed
111 } catch (...) {
112 secdebug("SS", "process %p(%d) identity decode threw exception", this, pid());
113 mClientCode = NULL;
114 mClientIdent = unknown; // no chance to squeeze a code identity from this
115 secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid());
116 }
117 }
118
119
120 //
121 // Clean up a Process object
122 //
123 Process::~Process()
124 {
125 // tell all our authorizations that we're gone
126 IFDEBUG(if (!mAuthorizations.empty())
127 secdebug("SS", "Process %p(%d) clearing %d authorizations",
128 this, mPid, int(mAuthorizations.size())));
129 for (AuthorizationSet::iterator it = mAuthorizations.begin();
130 it != mAuthorizations.end(); ) {
131 AuthorizationToken *auth = *it;
132 while (++it != mAuthorizations.end() && *it == auth) ; // Skip duplicates
133 if (auth->endProcess(*this))
134 delete auth;
135 }
136
137 // no need to lock here; the client process has no more active threads
138 secdebug("SS", "Process %p(%d) has died", this, mPid);
139
140 // release our name for the process's task port
141 if (mTaskPort)
142 mTaskPort.destroy();
143 }
144
145 void Process::kill()
146 {
147 StLock<Mutex> _(*this);
148
149 // release local temp store
150 mLocalStore = NULL;
151
152 // standard kill processing
153 PerProcess::kill();
154 }
155
156
157 Session& Process::session() const
158 {
159 return parent<Session>();
160 }
161
162
163 LocalDatabase &Process::localStore()
164 {
165 StLock<Mutex> _(*this);
166 if (!mLocalStore)
167 mLocalStore = new TempDatabase(*this);
168 return *mLocalStore;
169 }
170
171 Key *Process::makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes,
172 const AclEntryPrototype *owner)
173 {
174 return safer_cast<TempDatabase&>(localStore()).makeKey(key, moreAttributes, owner);
175 }
176
177
178 //
179 // Change the session of a process.
180 // This is the result of SessionCreate from a known process client.
181 //
182 void Process::changeSession(Port servicePort)
183 {
184 // re-parent
185 parent(Session::find(servicePort));
186
187 secdebug("SS", "process %p(%d) changed session to %p", this, pid(), &session());
188 }
189
190
191 //
192 // CodeSignatures implementation of Identity.
193 // The caller must make sure we have a valid (not necessarily hash-able) clientCode().
194 //
195 string Process::getPath() const
196 {
197 assert(mClientCode);
198 return mClientCode->canonicalPath();
199 }
200
201 const CssmData Process::getHash(CodeSigning::OSXSigner &signer) const
202 {
203 switch (mClientIdent) {
204 case deferred:
205 try {
206 // try to calculate our signature hash (first time use)
207 mCachedSignature.reset(mClientCode->sign(signer));
208 assert(mCachedSignature.get());
209 mClientIdent = known;
210 secdebug("SS", "process %p(%d) code signature computed", this, pid());
211 break;
212 } catch (...) {
213 // couldn't get client signature (unreadable, gone, hack attack, ...)
214 mClientIdent = unknown;
215 secdebug("SS", "process %p(%d) no code signature - anonymous", this, pid());
216 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION);
217 }
218 case known:
219 assert(mCachedSignature.get());
220 break;
221 case unknown:
222 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION);
223 }
224 return CssmData(*mCachedSignature);
225 }
226
227
228 //
229 // Authorization set maintainance
230 //
231 void Process::addAuthorization(AuthorizationToken *auth)
232 {
233 assert(auth);
234 StLock<Mutex> _(*this);
235 mAuthorizations.insert(auth);
236 auth->addProcess(*this);
237 }
238
239 void Process::checkAuthorization(AuthorizationToken *auth)
240 {
241 assert(auth);
242 StLock<Mutex> _(*this);
243 if (mAuthorizations.find(auth) == mAuthorizations.end())
244 MacOSError::throwMe(errAuthorizationInvalidRef);
245 }
246
247 bool Process::removeAuthorization(AuthorizationToken *auth)
248 {
249 assert(auth);
250 StLock<Mutex> _(*this);
251 // we do everything with a single set lookup call...
252 typedef AuthorizationSet::iterator Iter;
253 Iter it = mAuthorizations.lower_bound(auth);
254 bool isLast;
255 if (it == mAuthorizations.end() || auth != *it) {
256 isLast = true;
257 } else {
258 Iter next = it; ++next; // following element
259 isLast = (next == mAuthorizations.end()) || auth != *next;
260 mAuthorizations.erase(it); // remove first match
261 }
262 if (isLast) {
263 if (auth->endProcess(*this)) // ... tell it to remove us,
264 return true; // ... and tell the caller
265 }
266 return false; // keep the auth; it's still in use
267 }
268
269
270 //
271 // Notification client maintainance
272 //
273 void Process::requestNotifications(Port port, SecurityServer::NotificationDomain domain, SecurityServer::NotificationMask events)
274 {
275 new ProcessListener(*this, port, domain, events);
276 }
277
278 void Process::stopNotifications(Port port)
279 {
280 if (!Listener::remove(port))
281 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); //@@@ bad name (should be "no such callback")
282 }
283
284
285 //
286 // Debug dump support
287 //
288 #if defined(DEBUGDUMP)
289
290 void Process::dumpNode()
291 {
292 PerProcess::dumpNode();
293 if (mByteFlipped)
294 Debug::dump(" FLIPPED");
295 Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
296 mTaskPort.port(), mPid, mUid, mGid);
297 if (mClientCode) {
298 Debug::dump(" client=%s", mClientCode->canonicalPath().c_str());
299 switch (mClientIdent) {
300 case deferred:
301 break;
302 case known:
303 Debug::dump("[OK]");
304 break;
305 case unknown:
306 Debug::dump("[UNKNOWN]");
307 break;
308 }
309 } else {
310 Debug::dump(" NO CLIENT ID");
311 }
312 }
313
314 #endif //DEBUGDUMP