2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // process - track a single client process and its belongings
25 #include "authority.h"
30 // Construct a Process object.
32 Process::Process(Port servicePort
, TaskPort taskPort
,
33 const ClientSetupInfo
*info
, const char *identity
, uid_t uid
, gid_t gid
)
34 : session(Session::find(servicePort
)), mBusyCount(0), mDying(false),
35 mTaskPort(taskPort
), mByteFlipped(false), mUid(uid
), mGid(gid
),
36 mClientIdent(deferred
)
38 // examine info passed
40 uint32 pversion
= info
->version
;
41 if (pversion
== SSPROTOVERSION
) {
42 // correct protocol, same byte order, cool
44 Flippers::flip(pversion
);
45 if (pversion
== SSPROTOVERSION
) {
46 // correct protocol, reversed byte order
49 // unsupported protocol version
50 CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION
);
54 // let's take a look at our wannabe client...
55 mPid
= mTaskPort
.pid();
57 // register with the session
58 session
.addProcess(this);
60 secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
61 this, mPid
, mUid
, mGid
, &session
,
63 mByteFlipped
? "FLIP " : "",
64 (identity
&& identity
[0]) ? identity
: "(unknown)");
67 mClientCode
= CodeSigning::OSXCode::decode(identity
);
69 secdebug("SS", "process %p(%d) identity decode threw exception", this, pid());
72 mClientIdent
= unknown
; // no chance to squeeze a code identity from this
73 secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid());
80 assert(mBusyCount
== 0); // mustn't die with Connections referencing us
82 // tell all our authorizations that we're gone
83 IFDEBUG(if (!mAuthorizations
.empty())
84 secdebug("SS", "Process %p(%d) clearing %d authorizations",
85 this, mPid
, int(mAuthorizations
.size())));
86 for (AuthorizationSet::iterator it
= mAuthorizations
.begin();
87 it
!= mAuthorizations
.end(); ) {
88 AuthorizationToken
*auth
= *it
;
89 while (++it
!= mAuthorizations
.end() && *it
== auth
) ; // Skip duplicates
90 if (auth
->endProcess(*this))
94 // remove all database handles that belong to this process
95 IFDEBUG(if (!mDatabases
.empty())
96 secdebug("SS", "Process %p(%d) clearing %d database handles",
97 this, mPid
, int(mDatabases
.size())));
98 for (DatabaseSet::iterator it
= mDatabases
.begin();
99 it
!= mDatabases
.end(); it
++)
102 // no need to lock here; the client process has no more active threads
103 secdebug("SS", "Process %p(%d) has died", this, mPid
);
105 // release our name for the process's task port
109 // deregister from session
110 if (session
.removeProcess(this))
114 bool Process::kill(bool keepTaskPort
)
116 StLock
<Mutex
> _(mLock
);
118 mTaskPort
= Port(); // clear port so we don't destroy it later
119 if (mBusyCount
== 0) {
120 return true; // destroy me now
122 secdebug("SS", "Process %p(%d) destruction deferred for %d busy connections",
123 this, mPid
, int(mBusyCount
));
125 return false; // destroy me later
131 // Connection management
133 void Process::beginConnection(Connection
&)
135 StLock
<Mutex
> _(mLock
);
139 bool Process::endConnection(Connection
&)
141 StLock
<Mutex
> _(mLock
);
142 return --mBusyCount
== 0 && mDying
;
147 // Database management
149 void Process::addDatabase(Database
*database
)
151 StLock
<Mutex
> _(mLock
);
152 mDatabases
.insert(database
);
155 void Process::removeDatabase(Database
*database
)
157 StLock
<Mutex
> _(mLock
);
158 assert(mDatabases
.find(database
) != mDatabases
.end());
159 mDatabases
.erase(database
);
164 // CodeSignatures implementation of Identity.
165 // The caller must make sure we have a valid (not necessarily hash-able) clientCode().
167 string
Process::getPath() const
170 return mClientCode
->canonicalPath();
173 const CssmData
Process::getHash(CodeSigning::OSXSigner
&signer
) const
175 switch (mClientIdent
) {
178 // try to calculate our signature hash (first time use)
179 mCachedSignature
.reset(mClientCode
->sign(signer
));
180 assert(mCachedSignature
.get());
181 mClientIdent
= known
;
182 secdebug("SS", "process %p(%d) code signature computed", this, pid());
185 // couldn't get client signature (unreadable, gone, hack attack, ...)
186 mClientIdent
= unknown
;
187 secdebug("SS", "process %p(%d) no code signature - anonymous", this, pid());
188 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION
);
191 assert(mCachedSignature
.get());
194 CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION
);
196 return CssmData(*mCachedSignature
);
201 // Authorization set maintainance
203 void Process::addAuthorization(AuthorizationToken
*auth
)
206 StLock
<Mutex
> _(mLock
);
207 mAuthorizations
.insert(auth
);
208 auth
->addProcess(*this);
211 void Process::checkAuthorization(AuthorizationToken
*auth
)
214 StLock
<Mutex
> _(mLock
);
215 if (mAuthorizations
.find(auth
) == mAuthorizations
.end())
216 MacOSError::throwMe(errAuthorizationInvalidRef
);
219 bool Process::removeAuthorization(AuthorizationToken
*auth
)
222 StLock
<Mutex
> _(mLock
);
223 // we do everything with a single set lookup call...
224 typedef AuthorizationSet::iterator Iter
;
225 Iter it
= mAuthorizations
.lower_bound(auth
);
227 if (it
== mAuthorizations
.end() || auth
!= *it
) {
228 Syslog::error("process is missing authorization to remove"); // temp. diagnostic
231 Iter next
= it
; ++next
; // following element
232 isLast
= (next
== mAuthorizations
.end()) || auth
!= *next
;
233 mAuthorizations
.erase(it
); // remove first match
236 if (auth
->endProcess(*this)) // ... tell it to remove us,
237 return true; // ... and tell the caller
239 return false; // keep the auth; it's still in use
244 // Notification client maintainance
246 void Process::requestNotifications(Port port
, Listener::Domain domain
, Listener::EventMask events
)
248 new Listener(*this, port
, domain
, events
);
251 void Process::stopNotifications(Port port
)
253 if (!Listener::remove(port
))
254 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
); //@@@ bad name (should be "no such callback")
257 void Process::postNotification(Listener::Domain domain
, Listener::Event event
, const CssmData
&data
)
259 Listener::notify(domain
, event
, data
);