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