]> git.saurik.com Git - apple/securityd.git/blob - src/process.cpp
securityd-36489.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
34 #include <security_utilities/logging.h> //@@@ debug only
35 #include "agentquery.h"
36
37
38 //
39 // Construct a Process object.
40 //
41 Process::Process(Port servicePort, TaskPort taskPort,
42 const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit)
43 : mTaskPort(taskPort), mByteFlipped(false), mPid(audit.pid()), mUid(audit.euid()), mGid(audit.egid())
44 {
45 // set parent session
46 parent(Session::find(servicePort));
47
48 // let's take a look at our wannabe client...
49 if (mTaskPort.pid() != mPid) {
50 secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d) for %s",
51 mPid, mTaskPort.port(), mTaskPort.pid(),
52 (identity && identity[0]) ? identity : "(unknown)");
53 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); // you lied!
54 }
55
56 setup(info);
57 ClientIdentification::setup(this->pid());
58
59 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
60 this, mPid, mUid, mGid, &session(),
61 mTaskPort.port(),
62 mByteFlipped ? "FLIP " : "",
63 (identity && identity[0]) ? identity : "(unknown)");
64 }
65
66
67 //
68 // Screen a process setup request for an existing process.
69 // This means the client has requested intialization even though we remember having
70 // talked to it in the past. This could either be an exec(2), or the client could just
71 // have forgotten all about its securityd client state. Or it could be an attack...
72 //
73 void Process::reset(Port servicePort, TaskPort taskPort,
74 const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit)
75 {
76 if (servicePort != session().servicePort() || taskPort != mTaskPort) {
77 secdebug("SS", "Process %p(%d) reset mismatch (sp %d-%d, tp %d-%d) for %s",
78 this, pid(), servicePort.port(), session().servicePort().port(), taskPort.port(), mTaskPort.port(),
79 (identity && identity[0]) ? identity : "(unknown)");
80 Session &newSession = Session::find(servicePort);
81 Syslog::alert("Process reset %p(%d) session %d(0x%x:0x%x)->%d(0x%x:0x%x) for %s",
82 this, pid(),
83 session().servicePort().port(), &session(), session().attributes(),
84 newSession.servicePort().port(), &newSession, newSession.attributes(),
85 (identity && identity[0]) ? identity : "(unknown)");
86 //CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE); // liar
87 }
88
89 string oldPath = codePath(processCode());
90 setup(info);
91 ClientIdentification::setup(this->pid());
92 if (codePath(processCode()) == oldPath) {
93 secdebug("SS", "process %p(%d) path unchanged; assuming client-side reset", this, mPid);
94 } else {
95 secdebug("SS", "process %p(%d) path changed; assuming exec with full reset", this, mPid);
96 CodeSigningHost::reset();
97 }
98
99 secdebug("SS", "process %p(%d) has reset; now %sfor %s",
100 this, mPid, mByteFlipped ? "FLIP " : "",
101 (identity && identity[0]) ? identity : "(unknown)");
102 }
103
104
105 //
106 // Common set processing
107 //
108 void Process::setup(const ClientSetupInfo *info)
109 {
110 // process setup info
111 assert(info);
112 uint32 pversion;
113 if (info->order == 0x1234) { // right side up
114 pversion = info->version;
115 mByteFlipped = false;
116 } else if (info->order == 0x34120000) { // flip side up
117 pversion = ntohl(info->version);
118 mByteFlipped = true;
119 } else // non comprende
120 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
121
122 // check wire protocol version
123 if (pversion != SSPROTOVERSION)
124 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
125 }
126
127
128 //
129 // Clean up a Process object
130 //
131 Process::~Process()
132 {
133 // tell all our authorizations that we're gone
134 IFDEBUG(if (!mAuthorizations.empty())
135 secdebug("SS", "Process %p(%d) clearing %d authorizations",
136 this, mPid, int(mAuthorizations.size())));
137 for (AuthorizationSet::iterator it = mAuthorizations.begin();
138 it != mAuthorizations.end(); ) {
139 AuthorizationToken *auth = *it;
140 while (++it != mAuthorizations.end() && *it == auth) ; // Skip duplicates
141 if (auth->endProcess(*this))
142 delete auth;
143 }
144
145 // no need to lock here; the client process has no more active threads
146 secdebug("SS", "Process %p(%d) has died", this, mPid);
147
148 // release our name for the process's task port
149 if (mTaskPort)
150 mTaskPort.destroy();
151 }
152
153 void Process::kill()
154 {
155 StLock<Mutex> _(*this);
156
157 // release local temp store
158 mLocalStore = NULL;
159
160 // standard kill processing
161 PerProcess::kill();
162 }
163
164
165 Session& Process::session() const
166 {
167 return parent<Session>();
168 }
169
170
171 LocalDatabase &Process::localStore()
172 {
173 StLock<Mutex> _(*this);
174 if (!mLocalStore)
175 mLocalStore = new TempDatabase(*this);
176 return *mLocalStore;
177 }
178
179 Key *Process::makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes,
180 const AclEntryPrototype *owner)
181 {
182 return safer_cast<TempDatabase&>(localStore()).makeKey(key, moreAttributes, owner);
183 }
184
185
186 //
187 // Change the session of a process.
188 // This is the result of SessionCreate from a known process client.
189 //
190 void Process::changeSession(Port servicePort)
191 {
192 // re-parent
193 parent(Session::find(servicePort));
194
195 secdebug("SS", "process %p(%d) changed session to %p", this, pid(), &session());
196 }
197
198
199 //
200 // Authorization set maintainance
201 //
202 void Process::addAuthorization(AuthorizationToken *auth)
203 {
204 assert(auth);
205 StLock<Mutex> _(*this);
206 mAuthorizations.insert(auth);
207 auth->addProcess(*this);
208 }
209
210 void Process::checkAuthorization(AuthorizationToken *auth)
211 {
212 assert(auth);
213 StLock<Mutex> _(*this);
214 if (mAuthorizations.find(auth) == mAuthorizations.end())
215 MacOSError::throwMe(errAuthorizationInvalidRef);
216 }
217
218 bool Process::removeAuthorization(AuthorizationToken *auth)
219 {
220 assert(auth);
221 StLock<Mutex> _(*this);
222 // we do everything with a single set lookup call...
223 typedef AuthorizationSet::iterator Iter;
224 Iter it = mAuthorizations.lower_bound(auth);
225 bool isLast;
226 if (it == mAuthorizations.end() || auth != *it) {
227 isLast = true;
228 } else {
229 Iter next = it; ++next; // following element
230 isLast = (next == mAuthorizations.end()) || auth != *next;
231 mAuthorizations.erase(it); // remove first match
232 }
233 if (isLast) {
234 if (auth->endProcess(*this)) // ... tell it to remove us,
235 return true; // ... and tell the caller
236 }
237 return false; // keep the auth; it's still in use
238 }
239
240
241 //
242 // Debug dump support
243 //
244 #if defined(DEBUGDUMP)
245
246 void Process::dumpNode()
247 {
248 PerProcess::dumpNode();
249 if (mByteFlipped)
250 Debug::dump(" FLIPPED");
251 Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
252 mTaskPort.port(), mPid, mUid, mGid);
253 CodeSigningHost::dump();
254 ClientIdentification::dump();
255 }
256
257 #endif //DEBUGDUMP