]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2000-2009,2012 Apple 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 | StLock<Mutex> _(*this); | |
46 | ||
47 | // set parent session | |
48 | parent(Session::find(audit.sessionId(), true)); | |
49 | ||
50 | // let's take a look at our wannabe client... | |
51 | if (mTaskPort.pid() != mPid) { | |
52 | secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d)", | |
53 | mPid, mTaskPort.port(), mTaskPort.pid()); | |
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(TaskPort taskPort, const ClientSetupInfo *info, const CommonCriteria::AuditToken &audit) | |
80 | { | |
81 | StLock<Mutex> _(*this); | |
82 | if (taskPort != mTaskPort) { | |
83 | secdebug("SS", "Process %p(%d) reset mismatch (tp %d-%d)", | |
84 | this, pid(), taskPort.port(), mTaskPort.port()); | |
85 | //@@@ CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE); // liar | |
86 | } | |
87 | setup(info); | |
88 | CFCopyRef<SecCodeRef> oldCode = processCode(); | |
89 | ||
90 | ClientIdentification::setup(this->pid()); // re-constructs processCode() | |
91 | if (CFEqual(oldCode, processCode())) { | |
92 | SECURITYD_CLIENT_RESET_AMNESIA(this); | |
93 | } else { | |
94 | SECURITYD_CLIENT_RESET_FULL(this); | |
95 | CodeSigningHost::reset(); | |
96 | } | |
97 | } | |
98 | ||
99 | ||
100 | // | |
101 | // Common set processing | |
102 | // | |
103 | void Process::setup(const ClientSetupInfo *info) | |
104 | { | |
105 | // process setup info | |
106 | assert(info); | |
107 | uint32 pversion; | |
108 | if (info->order == 0x1234) { // right side up | |
109 | pversion = info->version; | |
110 | mByteFlipped = false; | |
111 | } else if (info->order == 0x34120000) { // flip side up | |
112 | pversion = flip(info->version); | |
113 | mByteFlipped = true; | |
114 | } else // non comprende | |
115 | CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); | |
116 | ||
117 | // check wire protocol version | |
118 | if (pversion != SSPROTOVERSION) | |
119 | CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); | |
120 | } | |
121 | ||
122 | ||
123 | // | |
124 | // Clean up a Process object | |
125 | // | |
126 | Process::~Process() | |
127 | { | |
128 | SECURITYD_CLIENT_RELEASE(this, this->pid()); | |
129 | ||
130 | // tell all our authorizations that we're gone | |
131 | IFDEBUG(if (!mAuthorizations.empty()) | |
132 | secdebug("SS", "Process %p(%d) clearing %d authorizations", | |
133 | this, mPid, int(mAuthorizations.size()))); | |
134 | for (AuthorizationSet::iterator it = mAuthorizations.begin(); | |
135 | it != mAuthorizations.end(); ) { | |
136 | AuthorizationToken *auth = *it; | |
137 | while (++it != mAuthorizations.end() && *it == auth) ; // Skip duplicates | |
138 | if (auth->endProcess(*this)) | |
139 | delete auth; | |
140 | } | |
141 | ||
142 | // release our name for the process's task port | |
143 | if (mTaskPort) | |
144 | mTaskPort.destroy(); | |
145 | } | |
146 | ||
147 | void Process::kill() | |
148 | { | |
149 | StLock<Mutex> _(*this); | |
150 | ||
151 | // release local temp store | |
152 | mLocalStore = NULL; | |
153 | ||
154 | // standard kill processing | |
155 | PerProcess::kill(); | |
156 | } | |
157 | ||
158 | ||
159 | Session& Process::session() const | |
160 | { | |
161 | return parent<Session>(); | |
162 | } | |
163 | ||
164 | ||
165 | void Process::checkSession(const audit_token_t &auditToken) | |
166 | { | |
167 | AuditToken audit(auditToken); | |
168 | if (audit.sessionId() != this->session().sessionId()) | |
169 | this->changeSession(audit.sessionId()); | |
170 | } | |
171 | ||
172 | ||
173 | LocalDatabase &Process::localStore() | |
174 | { | |
175 | StLock<Mutex> _(*this); | |
176 | if (!mLocalStore) | |
177 | mLocalStore = new TempDatabase(*this); | |
178 | return *mLocalStore; | |
179 | } | |
180 | ||
181 | Key *Process::makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes, | |
182 | const AclEntryPrototype *owner) | |
183 | { | |
184 | return safer_cast<TempDatabase&>(localStore()).makeKey(key, moreAttributes, owner); | |
185 | } | |
186 | ||
187 | ||
188 | // | |
189 | // Change the session of a process. | |
190 | // This is the result of SessionCreate from a known process client. | |
191 | // | |
192 | void Process::changeSession(Session::SessionId sessionId) | |
193 | { | |
194 | // re-parent | |
195 | parent(Session::find(sessionId, true)); | |
196 | SECURITYD_CLIENT_CHANGE_SESSION(this, &this->session()); | |
197 | } | |
198 | ||
199 | ||
200 | // | |
201 | // Authorization set maintainance | |
202 | // | |
203 | void Process::addAuthorization(AuthorizationToken *auth) | |
204 | { | |
205 | assert(auth); | |
206 | StLock<Mutex> _(*this); | |
207 | mAuthorizations.insert(auth); | |
208 | auth->addProcess(*this); | |
209 | } | |
210 | ||
211 | void Process::checkAuthorization(AuthorizationToken *auth) | |
212 | { | |
213 | assert(auth); | |
214 | StLock<Mutex> _(*this); | |
215 | if (mAuthorizations.find(auth) == mAuthorizations.end()) | |
216 | MacOSError::throwMe(errAuthorizationInvalidRef); | |
217 | } | |
218 | ||
219 | bool Process::removeAuthorization(AuthorizationToken *auth) | |
220 | { | |
221 | assert(auth); | |
222 | StLock<Mutex> _(*this); | |
223 | // we do everything with a single set lookup call... | |
224 | typedef AuthorizationSet::iterator Iter; | |
225 | Iter it = mAuthorizations.lower_bound(auth); | |
226 | bool isLast; | |
227 | if (it == mAuthorizations.end() || auth != *it) { | |
228 | isLast = true; | |
229 | } else { | |
230 | Iter next = it; ++next; // following element | |
231 | isLast = (next == mAuthorizations.end()) || auth != *next; | |
232 | mAuthorizations.erase(it); // remove first match | |
233 | } | |
234 | if (isLast) { | |
235 | if (auth->endProcess(*this)) // ... tell it to remove us, | |
236 | return true; // ... and tell the caller | |
237 | } | |
238 | return false; // keep the auth; it's still in use | |
239 | } | |
240 | ||
241 | ||
242 | // | |
243 | // Debug dump support | |
244 | // | |
245 | #if defined(DEBUGDUMP) | |
246 | ||
247 | void Process::dumpNode() | |
248 | { | |
249 | PerProcess::dumpNode(); | |
250 | if (mByteFlipped) | |
251 | Debug::dump(" FLIPPED"); | |
252 | Debug::dump(" task=%d pid=%d uid/gid=%d/%d", | |
253 | mTaskPort.port(), mPid, mUid, mGid); | |
254 | CodeSigningHost::dump(); | |
255 | ClientIdentification::dump(); | |
256 | } | |
257 | ||
258 | #endif //DEBUGDUMP |