2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 // process - track a single client process and its belongings
33 #include "tempdatabase.h"
34 #include "authority.h"
39 // Construct a Process object.
41 Process::Process(Port servicePort
, TaskPort taskPort
,
42 const ClientSetupInfo
*info
, const char *identity
, uid_t uid
, gid_t gid
)
43 : mTaskPort(taskPort
), mByteFlipped(false), mUid(uid
), mGid(gid
),
44 mClientIdent(deferred
)
46 // examine info passed
48 uint32 pversion
= info
->version
;
49 if (pversion
== SSPROTOVERSION
) {
50 // correct protocol, same byte order, cool
52 Flippers::flip(pversion
);
53 if (pversion
== SSPROTOVERSION
) {
54 // correct protocol, reversed byte order
57 // unsupported protocol version
58 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
63 parent(Session::find(servicePort
));
65 // let's take a look at our wannabe client...
66 mPid
= mTaskPort
.pid();
68 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
69 this, mPid
, mUid
, mGid
, &session(),
71 mByteFlipped
? "FLIP " : "",
72 (identity
&& identity
[0]) ? identity
: "(unknown)");
75 mClientCode
= CodeSigning::OSXCode::decode(identity
);
77 secdebug("SS", "process %p(%d) identity decode threw exception", this, pid());
80 mClientIdent
= unknown
; // no chance to squeeze a code identity from this
81 secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid());
88 // tell all our authorizations that we're gone
89 IFDEBUG(if (!mAuthorizations
.empty())
90 secdebug("SS", "Process %p(%d) clearing %d authorizations",
91 this, mPid
, int(mAuthorizations
.size())));
92 for (AuthorizationSet::iterator it
= mAuthorizations
.begin();
93 it
!= mAuthorizations
.end(); ) {
94 AuthorizationToken
*auth
= *it
;
95 while (++it
!= mAuthorizations
.end() && *it
== auth
) ; // Skip duplicates
96 if (auth
->endProcess(*this))
100 // no need to lock here; the client process has no more active threads
101 secdebug("SS", "Process %p(%d) has died", this, mPid
);
103 // release our name for the process's task port
110 StLock
<Mutex
> _(*this);
112 // release local temp store
115 // standard kill processing
120 Session
& Process::session() const
122 return parent
<Session
>();
126 Database
&Process::localStore()
128 StLock
<Mutex
> _(*this);
130 mLocalStore
= new TempDatabase(*this);
136 // Change the session of a process.
137 // This is the result of SessionCreate from a known process client.
139 void Process::changeSession(Port servicePort
)
142 parent(Session::find(servicePort
));
144 secdebug("SS", "process %p(%d) changed session to %p", this, pid(), &session());
149 // CodeSignatures implementation of Identity.
150 // The caller must make sure we have a valid (not necessarily hash-able) clientCode().
152 string
Process::getPath() const
155 return mClientCode
->canonicalPath();
158 const CssmData
Process::getHash(CodeSigning::OSXSigner
&signer
) const
160 switch (mClientIdent
) {
163 // try to calculate our signature hash (first time use)
164 mCachedSignature
.reset(mClientCode
->sign(signer
));
165 assert(mCachedSignature
.get());
166 mClientIdent
= known
;
167 secdebug("SS", "process %p(%d) code signature computed", this, pid());
170 // couldn't get client signature (unreadable, gone, hack attack, ...)
171 mClientIdent
= unknown
;
172 secdebug("SS", "process %p(%d) no code signature - anonymous", this, pid());
173 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION
);
176 assert(mCachedSignature
.get());
179 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION
);
181 return CssmData(*mCachedSignature
);
186 // Authorization set maintainance
188 void Process::addAuthorization(AuthorizationToken
*auth
)
191 StLock
<Mutex
> _(*this);
192 mAuthorizations
.insert(auth
);
193 auth
->addProcess(*this);
196 void Process::checkAuthorization(AuthorizationToken
*auth
)
199 StLock
<Mutex
> _(*this);
200 if (mAuthorizations
.find(auth
) == mAuthorizations
.end())
201 MacOSError::throwMe(errAuthorizationInvalidRef
);
204 bool Process::removeAuthorization(AuthorizationToken
*auth
)
207 StLock
<Mutex
> _(*this);
208 // we do everything with a single set lookup call...
209 typedef AuthorizationSet::iterator Iter
;
210 Iter it
= mAuthorizations
.lower_bound(auth
);
212 if (it
== mAuthorizations
.end() || auth
!= *it
) {
213 Syslog::error("process is missing authorization to remove"); // temp. diagnostic
216 Iter next
= it
; ++next
; // following element
217 isLast
= (next
== mAuthorizations
.end()) || auth
!= *next
;
218 mAuthorizations
.erase(it
); // remove first match
221 if (auth
->endProcess(*this)) // ... tell it to remove us,
222 return true; // ... and tell the caller
224 return false; // keep the auth; it's still in use
229 // Notification client maintainance
231 void Process::requestNotifications(Port port
, SecurityServer::NotificationDomain domain
, SecurityServer::NotificationMask events
)
233 new ProcessListener(*this, port
, domain
, events
);
236 void Process::stopNotifications(Port port
)
238 if (!Listener::remove(port
))
239 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
); //@@@ bad name (should be "no such callback")
244 // Debug dump support
246 #if defined(DEBUGDUMP)
248 void Process::dumpNode()
250 PerProcess::dumpNode();
252 Debug::dump(" FLIPPED");
253 Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
254 mTaskPort
.port(), mPid
, mUid
, mGid
);
256 Debug::dump(" client=%s", mClientCode
->canonicalPath().c_str());
257 switch (mClientIdent
) {
264 Debug::dump("[UNKNOWN]");
268 Debug::dump(" NO CLIENT ID");