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