]> git.saurik.com Git - apple/security.git/blob - SecurityServer/process.cpp
Security-54.tar.gz
[apple/security.git] / SecurityServer / process.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // process - track a single client process and its belongings
21 //
22 #include "process.h"
23 #include "server.h"
24 #include "session.h"
25 #include "authority.h"
26
27
28 //
29 // Construct a Process object.
30 //
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)
34 {
35 // let's take a look at our wannabe client...
36 mPid = mTaskPort.pid();
37
38 // register with the session
39 session.addProcess(this);
40
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);
45
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)");
49 }
50
51 #if 0
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)
55 {
56 // copy more
57 mPid = prior.mPid;
58
59 // register with the session
60 session.addProcess(this);
61
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();
65
66 debug("SS", "Process %p(%d) recloned uid=%d gid=%d session=%p",
67 this, mPid, mUid, mGid, &session);
68 }
69 #endif
70
71
72 Process::~Process()
73 {
74 assert(mBusyCount == 0); // mustn't die with Connections referencing us
75
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))
84 delete auth;
85 }
86
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++)
93 delete *it;
94
95 // no need to lock here; the client process has no more active threads
96 debug("SS", "Process %p(%d) has died", this, mPid);
97
98 // release our name for the process's task port
99 if (mTaskPort)
100 mTaskPort.destroy(); // either dead or taken by reclone
101
102 // deregister from session
103 if (session.removeProcess(this))
104 delete &session;
105 }
106
107 bool Process::kill()
108 {
109 if (mBusyCount == 0) {
110 return true; // destroy me now
111 } else {
112 debug("SS", "Process %p(%d) destruction deferred for %d busy connections",
113 this, mPid, int(mBusyCount));
114 mDying = true;
115 return false; // destroy me later
116 }
117 }
118
119
120 //
121 // Connection management
122 //
123 void Process::beginConnection(Connection &)
124 {
125 StLock<Mutex> _(mLock);
126 mBusyCount++;
127 }
128
129 bool Process::endConnection(Connection &)
130 {
131 StLock<Mutex> _(mLock);
132 return --mBusyCount == 0 && mDying;
133 }
134
135
136 //
137 // Database management
138 //
139 void Process::addDatabase(Database *database)
140 {
141 StLock<Mutex> _(mLock);
142 mDatabases.insert(database);
143 }
144
145 void Process::removeDatabase(Database *database)
146 {
147 StLock<Mutex> _(mLock);
148 assert(mDatabases.find(database) != mDatabases.end());
149 mDatabases.erase(database);
150 }
151
152
153 //
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.
158 //
159 bool Process::verifyCodeSignature(const CodeSigning::Signature *signature)
160 {
161 if (mClientCode)
162 return Server::signer().verify(*mClientCode, signature);
163 else
164 return false; // identity not known; can't verify
165 }
166
167
168 //
169 // Authorization set maintainance
170 //
171 void Process::addAuthorization(AuthorizationToken *auth)
172 {
173 assert(auth);
174 StLock<Mutex> _(mLock);
175 mAuthorizations.insert(auth);
176 auth->addProcess(*this);
177 }
178
179 bool Process::removeAuthorization(AuthorizationToken *auth)
180 {
181 assert(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
192 }
193 return false; // keep the auth; it's still in use
194 }
195
196
197 //
198 // Notification client maintainance
199 //
200 void Process::requestNotifications(Port port, Listener::Domain domain, Listener::EventMask events)
201 {
202 new Listener(*this, port, domain, events);
203 }
204
205 void Process::stopNotifications(Port port)
206 {
207 if (!Listener::remove(port))
208 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); //@@@ bad name (should be "no such callback")
209 }
210
211 void Process::postNotification(Listener::Domain domain, Listener::Event event, const CssmData &data)
212 {
213 Listener::notify(domain, event, data);
214 }
215