]> git.saurik.com Git - apple/security.git/blob - SecurityServer/process.cpp
Security-29.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(TaskPort taskPort, const char *identity, uid_t uid, gid_t gid)
32 : session(Session::find(taskPort.bootstrap())), 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 Process::Process(Process &prior)
52 : session(Session::find(prior.mTaskPort.bootstrap())), mBusyCount(0), mDying(false),
53 mTaskPort(prior.mTaskPort), mUid(prior.mUid), mGid(prior.mGid)
54 {
55 // copy more
56 mPid = prior.mPid;
57
58 // register with the session
59 session.addProcess(this);
60
61 // copy the client-code id (and clear it in the prior so it doesn't get destroyed there)
62 mClientCode = prior.mClientCode;
63 prior.mClientCode = NULL;
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
70
71 Process::~Process()
72 {
73 assert(mBusyCount == 0); // mustn't die with Connections referencing us
74
75 // tell all our authorizations that we're gone
76 IFDEBUG(if (!mAuthorizations.empty())
77 debug("SS", "Process %p(%d) clearing %d authorizations",
78 this, mPid, int(mAuthorizations.size())));
79 for (AuthorizationSet::iterator it = mAuthorizations.begin();
80 it != mAuthorizations.end(); it++) {
81 AuthorizationToken *auth = *it;
82 if (removeAuthorization(auth))
83 delete auth;
84 }
85
86 // remove all database handles that belong to this process
87 IFDEBUG(if (!mDatabases.empty())
88 debug("SS", "Process %p(%d) clearing %d database handles",
89 this, mPid, int(mDatabases.size())));
90 for (DatabaseSet::iterator it = mDatabases.begin();
91 it != mDatabases.end(); it++)
92 delete *it;
93
94 // no need to lock here; the client process has no more active threads
95 debug("SS", "Process %p(%d) has died", this, mPid);
96
97 if (mTaskPort)
98 mTaskPort.destroy(); // either dead or taken by reclone
99 delete mClientCode;
100
101 // deregister from session
102 if (session.removeProcess(this))
103 delete &session;
104 }
105
106 bool Process::kill()
107 {
108 if (mBusyCount == 0) {
109 return true; // destroy me now
110 } else {
111 debug("SS", "Process %p(%d) destruction deferred for %d busy connections",
112 this, mPid, int(mBusyCount));
113 mDying = true;
114 return false; // destroy me later
115 }
116 }
117
118
119 //
120 // Given a task port, determine which session it belongs to.
121 // @@@ Very preliminary, pending true session implementation.
122 //
123 Session &Process::sessionForPort(TaskPort taskPort)
124 {
125 return Session::find(taskPort.bootstrap());
126 }
127
128
129 //
130 // Connection management
131 //
132 void Process::beginConnection(Connection &)
133 {
134 StLock<Mutex> _(mLock);
135 mBusyCount++;
136 }
137
138 bool Process::endConnection(Connection &)
139 {
140 StLock<Mutex> _(mLock);
141 return --mBusyCount == 0 && mDying;
142 }
143
144
145 //
146 // Database management
147 //
148 void Process::addDatabase(Database *database)
149 {
150 StLock<Mutex> _(mLock);
151 mDatabases.insert(database);
152 }
153
154 void Process::removeDatabase(Database *database)
155 {
156 StLock<Mutex> _(mLock);
157 assert(mDatabases.find(database) != mDatabases.end());
158 mDatabases.erase(database);
159 }
160
161
162 //
163 // Verify the code signature of the a process's on-disk source.
164 // @@@ In a truly secure solution, we would ask the OS to verify this.
165 // @@@ Only the OS knows for sure what disk file (if any) originated a process.
166 // @@@ In the meantime, we fake it.
167 //
168 bool Process::verifyCodeSignature(const CodeSigning::Signature *signature)
169 {
170 if (mClientCode)
171 return Server::signer().verify(*mClientCode, signature);
172 else
173 return false; // identity not known; can't verify
174 }
175
176
177 //
178 // Authorization set maintainance
179 //
180 void Process::addAuthorization(AuthorizationToken *auth)
181 {
182 assert(auth);
183 StLock<Mutex> _(mLock);
184 mAuthorizations.insert(auth);
185 auth->addProcess(*this);
186 }
187
188 bool Process::removeAuthorization(AuthorizationToken *auth)
189 {
190 assert(auth);
191 StLock<Mutex> _(mLock);
192 // we do everything with a single set lookup call...
193 typedef AuthorizationSet::iterator Iter;
194 pair<Iter, Iter> range = mAuthorizations.equal_range(auth);
195 assert(range.first != mAuthorizations.end());
196 Iter next = range.first; next++; // next element after first hit
197 mAuthorizations.erase(range.first); // erase first hit
198 if (next == range.second) { // if no more hits...
199 if (auth->endProcess(*this)) // ... tell it to remove us,
200 return true; // ... and tell the caller
201 }
202 return false; // keep the auth; it's still in use
203 }