2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // process - track a single client process and its belongings
31 #include "tempdatabase.h"
32 #include "authority.h"
37 // Construct a Process object.
39 Process::Process(Port servicePort
, TaskPort taskPort
,
40 const ClientSetupInfo
*info
, const char *identity
, const CommonCriteria::AuditToken
&audit
)
41 : mTaskPort(taskPort
), mByteFlipped(false), mPid(audit
.pid()), mUid(audit
.euid()), mGid(audit
.egid())
44 parent(Session::find(servicePort
));
46 // let's take a look at our wannabe client...
47 if (mTaskPort
.pid() != mPid
) {
48 secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d) for %s",
49 mPid
, mTaskPort
.port(), mTaskPort
.pid(),
50 (identity
&& identity
[0]) ? identity
: "(unknown)");
51 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED
); // you lied!
54 setup(info
, identity
);
56 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
57 this, mPid
, mUid
, mGid
, &session(),
59 mByteFlipped
? "FLIP " : "",
60 (identity
&& identity
[0]) ? identity
: "(unknown)");
65 // Screen a process setup request for an existing process.
66 // This usually means the client has called exec(2) and forgotten all about itself.
67 // Though it could be a nefarious attempt to fool us...
69 void Process::reset(Port servicePort
, TaskPort taskPort
,
70 const ClientSetupInfo
*info
, const char *identity
, const CommonCriteria::AuditToken
&audit
)
72 if (servicePort
!= session().servicePort() || taskPort
!= mTaskPort
) {
73 secdebug("SS", "Process %p(%d) reset mismatch (sp %d-%d, tp %d-%d) for %s",
74 this, pid(), servicePort
.port(), session().servicePort().port(), taskPort
.port(), mTaskPort
.port(),
75 (identity
&& identity
[0]) ? identity
: "(unknown)");
76 CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED
); // liar
79 setup(info
, identity
);
81 secdebug("SS", "process %p(%d) has reset; now %sfor %s",
82 this, mPid
, mByteFlipped
? "FLIP " : "",
83 (identity
&& identity
[0]) ? identity
: "(unknown)");
88 // Common set processing
90 void Process::setup(const ClientSetupInfo
*info
, const char *identity
)
95 if (info
->order
== 0x1234) { // right side up
96 pversion
= info
->version
;
97 } else if (info
->order
== 0x34120000) { // flip side up
98 pversion
= ntohl(info
->version
);
100 } else // non comprende
101 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
103 // check wire protocol version
104 if (pversion
!= SSPROTOVERSION
)
105 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
107 // process identity (if given)
109 mClientCode
= OSXCode::decode(identity
);
110 mClientIdent
= deferred
; // will calculate code identity when needed
112 secdebug("SS", "process %p(%d) identity decode threw exception", this, pid());
114 mClientIdent
= unknown
; // no chance to squeeze a code identity from this
115 secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid());
121 // Clean up a Process object
125 // tell all our authorizations that we're gone
126 IFDEBUG(if (!mAuthorizations
.empty())
127 secdebug("SS", "Process %p(%d) clearing %d authorizations",
128 this, mPid
, int(mAuthorizations
.size())));
129 for (AuthorizationSet::iterator it
= mAuthorizations
.begin();
130 it
!= mAuthorizations
.end(); ) {
131 AuthorizationToken
*auth
= *it
;
132 while (++it
!= mAuthorizations
.end() && *it
== auth
) ; // Skip duplicates
133 if (auth
->endProcess(*this))
137 // no need to lock here; the client process has no more active threads
138 secdebug("SS", "Process %p(%d) has died", this, mPid
);
140 // release our name for the process's task port
147 StLock
<Mutex
> _(*this);
149 // release local temp store
152 // standard kill processing
157 Session
& Process::session() const
159 return parent
<Session
>();
163 LocalDatabase
&Process::localStore()
165 StLock
<Mutex
> _(*this);
167 mLocalStore
= new TempDatabase(*this);
171 Key
*Process::makeTemporaryKey(const CssmKey
&key
, CSSM_KEYATTR_FLAGS moreAttributes
,
172 const AclEntryPrototype
*owner
)
174 return safer_cast
<TempDatabase
&>(localStore()).makeKey(key
, moreAttributes
, owner
);
179 // Change the session of a process.
180 // This is the result of SessionCreate from a known process client.
182 void Process::changeSession(Port servicePort
)
185 parent(Session::find(servicePort
));
187 secdebug("SS", "process %p(%d) changed session to %p", this, pid(), &session());
192 // CodeSignatures implementation of Identity.
193 // The caller must make sure we have a valid (not necessarily hash-able) clientCode().
195 string
Process::getPath() const
198 return mClientCode
->canonicalPath();
201 const CssmData
Process::getHash(CodeSigning::OSXSigner
&signer
) const
203 switch (mClientIdent
) {
206 // try to calculate our signature hash (first time use)
207 mCachedSignature
.reset(mClientCode
->sign(signer
));
208 assert(mCachedSignature
.get());
209 mClientIdent
= known
;
210 secdebug("SS", "process %p(%d) code signature computed", this, pid());
213 // couldn't get client signature (unreadable, gone, hack attack, ...)
214 mClientIdent
= unknown
;
215 secdebug("SS", "process %p(%d) no code signature - anonymous", this, pid());
216 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION
);
219 assert(mCachedSignature
.get());
222 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION
);
224 return CssmData(*mCachedSignature
);
229 // Authorization set maintainance
231 void Process::addAuthorization(AuthorizationToken
*auth
)
234 StLock
<Mutex
> _(*this);
235 mAuthorizations
.insert(auth
);
236 auth
->addProcess(*this);
239 void Process::checkAuthorization(AuthorizationToken
*auth
)
242 StLock
<Mutex
> _(*this);
243 if (mAuthorizations
.find(auth
) == mAuthorizations
.end())
244 MacOSError::throwMe(errAuthorizationInvalidRef
);
247 bool Process::removeAuthorization(AuthorizationToken
*auth
)
250 StLock
<Mutex
> _(*this);
251 // we do everything with a single set lookup call...
252 typedef AuthorizationSet::iterator Iter
;
253 Iter it
= mAuthorizations
.lower_bound(auth
);
255 if (it
== mAuthorizations
.end() || auth
!= *it
) {
258 Iter next
= it
; ++next
; // following element
259 isLast
= (next
== mAuthorizations
.end()) || auth
!= *next
;
260 mAuthorizations
.erase(it
); // remove first match
263 if (auth
->endProcess(*this)) // ... tell it to remove us,
264 return true; // ... and tell the caller
266 return false; // keep the auth; it's still in use
271 // Notification client maintainance
273 void Process::requestNotifications(Port port
, SecurityServer::NotificationDomain domain
, SecurityServer::NotificationMask events
)
275 new ProcessListener(*this, port
, domain
, events
);
278 void Process::stopNotifications(Port port
)
280 if (!Listener::remove(port
))
281 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
); //@@@ bad name (should be "no such callback")
286 // Debug dump support
288 #if defined(DEBUGDUMP)
290 void Process::dumpNode()
292 PerProcess::dumpNode();
294 Debug::dump(" FLIPPED");
295 Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
296 mTaskPort
.port(), mPid
, mUid
, mGid
);
298 Debug::dump(" client=%s", mClientCode
->canonicalPath().c_str());
299 switch (mClientIdent
) {
306 Debug::dump("[UNKNOWN]");
310 Debug::dump(" NO CLIENT ID");