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