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"
29 // Construct a Process object.
31 Process::Process(Port servicePort
, TaskPort taskPort
, const char *identity
, uid_t uid
, gid_t gid
)
32 : session(Session::find(servicePort
)), mBusyCount(0), mDying(false),
33 mTaskPort(taskPort
), mUid(uid
), mGid(gid
)
35 // let's take a look at our wannabe client...
36 mPid
= mTaskPort
.pid();
38 // register with the session
39 session
.addProcess(this);
41 // identify the client-on-disk
42 // @@@ do this lazily on first use?
43 // @@@ note that the paradigm will shift here when kernel-supported id happens
44 mClientCode
= CodeSigning::OSXCode::decode(identity
);
46 debug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d for %s",
47 this, mPid
, mUid
, mGid
, &session
,
48 mTaskPort
.port(), identity
? identity
: "(unknown)");
52 Process::Process(Process
&prior
)
53 : session(Session::find(prior
.mTaskPort
.bootstrap())), mBusyCount(0), mDying(false),
54 mTaskPort(prior
.mTaskPort
), mUid(prior
.mUid
), mGid(prior
.mGid
)
59 // register with the session
60 session
.addProcess(this);
62 // copy the client-code id (and clear it in the prior so it doesn't get destroyed there)
63 mClientCode
= prior
.mClientCode
;
64 prior
.mTaskPort
= Port();
66 debug("SS", "Process %p(%d) recloned uid=%d gid=%d session=%p",
67 this, mPid
, mUid
, mGid
, &session
);
74 assert(mBusyCount
== 0); // mustn't die with Connections referencing us
76 // tell all our authorizations that we're gone
77 IFDEBUG(if (!mAuthorizations
.empty())
78 debug("SS", "Process %p(%d) clearing %d authorizations",
79 this, mPid
, int(mAuthorizations
.size())));
80 for (AuthorizationSet::iterator it
= mAuthorizations
.begin();
81 it
!= mAuthorizations
.end(); it
++) {
82 AuthorizationToken
*auth
= *it
;
83 if (removeAuthorization(auth
))
87 // remove all database handles that belong to this process
88 IFDEBUG(if (!mDatabases
.empty())
89 debug("SS", "Process %p(%d) clearing %d database handles",
90 this, mPid
, int(mDatabases
.size())));
91 for (DatabaseSet::iterator it
= mDatabases
.begin();
92 it
!= mDatabases
.end(); it
++)
95 // no need to lock here; the client process has no more active threads
96 debug("SS", "Process %p(%d) has died", this, mPid
);
98 // release our name for the process's task port
100 mTaskPort
.destroy(); // either dead or taken by reclone
102 // deregister from session
103 if (session
.removeProcess(this))
109 if (mBusyCount
== 0) {
110 return true; // destroy me now
112 debug("SS", "Process %p(%d) destruction deferred for %d busy connections",
113 this, mPid
, int(mBusyCount
));
115 return false; // destroy me later
121 // Connection management
123 void Process::beginConnection(Connection
&)
125 StLock
<Mutex
> _(mLock
);
129 bool Process::endConnection(Connection
&)
131 StLock
<Mutex
> _(mLock
);
132 return --mBusyCount
== 0 && mDying
;
137 // Database management
139 void Process::addDatabase(Database
*database
)
141 StLock
<Mutex
> _(mLock
);
142 mDatabases
.insert(database
);
145 void Process::removeDatabase(Database
*database
)
147 StLock
<Mutex
> _(mLock
);
148 assert(mDatabases
.find(database
) != mDatabases
.end());
149 mDatabases
.erase(database
);
154 // Verify the code signature of the a process's on-disk source.
155 // @@@ In a truly secure solution, we would ask the OS to verify this.
156 // @@@ Only the OS knows for sure what disk file (if any) originated a process.
157 // @@@ In the meantime, we fake it.
159 bool Process::verifyCodeSignature(const CodeSigning::Signature
*signature
)
162 return Server::signer().verify(*mClientCode
, signature
);
164 return false; // identity not known; can't verify
169 // Authorization set maintainance
171 void Process::addAuthorization(AuthorizationToken
*auth
)
174 StLock
<Mutex
> _(mLock
);
175 mAuthorizations
.insert(auth
);
176 auth
->addProcess(*this);
179 bool Process::removeAuthorization(AuthorizationToken
*auth
)
182 StLock
<Mutex
> _(mLock
);
183 // we do everything with a single set lookup call...
184 typedef AuthorizationSet::iterator Iter
;
185 pair
<Iter
, Iter
> range
= mAuthorizations
.equal_range(auth
);
186 assert(range
.first
!= mAuthorizations
.end());
187 Iter next
= range
.first
; next
++; // next element after first hit
188 mAuthorizations
.erase(range
.first
); // erase first hit
189 if (next
== range
.second
) { // if no more hits...
190 if (auth
->endProcess(*this)) // ... tell it to remove us,
191 return true; // ... and tell the caller
193 return false; // keep the auth; it's still in use
198 // Notification client maintainance
200 void Process::requestNotifications(Port port
, Listener::Domain domain
, Listener::EventMask events
)
202 new Listener(*this, port
, domain
, events
);
205 void Process::stopNotifications(Port port
)
207 if (!Listener::remove(port
))
208 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
); //@@@ bad name (should be "no such callback")
211 void Process::postNotification(Listener::Domain domain
, Listener::Event event
, const CssmData
&data
)
213 Listener::notify(domain
, event
, data
);