]> git.saurik.com Git - apple/security.git/blob - SecurityServer/authority.cpp
Security-54.tar.gz
[apple/security.git] / SecurityServer / authority.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 // authority - authorization manager
21 //
22 #include "authority.h"
23 #include "server.h"
24 #include "connection.h"
25 #include "session.h"
26 #include "process.h"
27
28 #include "AuthorizationWalkers.h"
29
30 using Authorization::Right;
31
32 //
33 // The global dictionary of extant AuthorizationTokens
34 //
35 AuthorizationToken::AuthMap AuthorizationToken::authMap; // set of extant authorizations
36 Mutex AuthorizationToken::authMapLock; // lock for mAuthorizations (only)
37
38
39 //
40 // Construct an Authority
41 //
42 Authority::Authority(const char *configFile)
43 : Authorization::Engine(configFile)
44 {
45 }
46
47 Authority::~Authority()
48 {
49 }
50
51
52 //
53 // Create an authorization token.
54 //
55 AuthorizationToken::AuthorizationToken(Session &ssn, const CredentialSet &base)
56 : session(ssn), mBaseCreds(base), mTransferCount(INT_MAX),
57 mCreatorUid(Server::connection().process.uid()),
58 mCreatorCode(Server::connection().process.clientCode()), mInfoSet(NULL)
59 {
60 // generate our (random) handle
61 Server::active().random(mHandle);
62
63 // register handle in the global map
64 StLock<Mutex> _(authMapLock);
65 authMap[mHandle] = this;
66
67 // register with parent session
68 session.addAuthorization(this);
69
70 // all ready
71 IFDEBUG(debug("SSauth", "Authorization %p created using %d credentials; owner=%s",
72 this, int(mBaseCreds.size()),
73 mCreatorCode ? mCreatorCode->encode().c_str() : "unknown"));
74 }
75
76 AuthorizationToken::~AuthorizationToken()
77 {
78 // we better be clean
79 assert(mUsingProcesses.empty());
80
81 // deregister from parent session
82 if (session.removeAuthorization(this))
83 delete &session;
84
85 // remove stored context
86 if (mInfoSet)
87 {
88 debug("SSauth", "Authorization %p destroying context @%p", this, mInfoSet);
89 CssmAllocator::standard().free(mInfoSet); // @@@ switch to sensitive allocator
90 }
91
92 debug("SSauth", "Authorization %p destroyed", this);
93 }
94
95
96 //
97 // Locate an authorization given its blob.
98 //
99 AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob)
100 {
101 StLock<Mutex> _(authMapLock);
102 AuthMap::iterator it = authMap.find(blob);
103 if (it == authMap.end())
104 Authorization::Error::throwMe(errAuthorizationInvalidRef);
105 return *it->second;
106 }
107
108
109 //
110 // Handle atomic deletion of AuthorizationToken objects
111 //
112 AuthorizationToken::Deleter::Deleter(const AuthorizationBlob &blob)
113 : lock(authMapLock)
114 {
115 AuthMap::iterator it = authMap.find(blob);
116 if (it == authMap.end())
117 Authorization::Error::throwMe(errAuthorizationInvalidRef);
118 mAuth = it->second;
119 }
120
121 void AuthorizationToken::Deleter::remove()
122 {
123 if (mAuth) {
124 authMap.erase(mAuth->handle());
125 delete mAuth;
126 mAuth = NULL;
127 }
128 }
129
130
131 //
132 // Given a set of credentials, add it to our private credentials and return the result
133 //
134 // must hold Session::mCredsLock
135 CredentialSet AuthorizationToken::effectiveCreds() const
136 {
137 IFDEBUG(debug("SSauth", "Authorization %p grabbing session %p creds %p", this, &session, &session.authCredentials()));
138 CredentialSet result = session.authCredentials();
139 for (CredentialSet::const_iterator it = mBaseCreds.begin(); it != mBaseCreds.end(); it++)
140 if (!(*it)->isShared())
141 result.insert(*it);
142 return result;
143 }
144
145
146 //
147 // Add more credential dependencies to an authorization
148 //
149 // must hold Session::mCredsLock
150 void AuthorizationToken::mergeCredentials(const CredentialSet &add)
151 {
152 debug("SSauth", "Authorization %p merge creds %p", this, &add);
153 for (CredentialSet::const_iterator it = add.begin(); it != add.end(); it++) {
154 mBaseCreds.erase(*it);
155 mBaseCreds.insert(*it);
156 }
157 debug("SSauth", "Authorization %p merged %d new credentials for %d total",
158 this, int(add.size()), int(mBaseCreds.size()));
159 }
160
161
162 //
163 // Register a new process that uses this authorization token.
164 // This is an idempotent operation.
165 //
166 void AuthorizationToken::addProcess(Process &proc)
167 {
168 StLock<Mutex> _(mLock);
169 mUsingProcesses.insert(&proc);
170 debug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid());
171 }
172
173
174 //
175 // Completely unregister client process.
176 // It does not matter how often it was registered with addProcess before.
177 // This returns true if no more processes use this token. Presumably you
178 // would then want to clean up, though that's up to you.
179 //
180 bool AuthorizationToken::endProcess(Process &proc)
181 {
182 StLock<Mutex> _(mLock);
183 assert(mUsingProcesses.find(&proc) != mUsingProcesses.end());
184 mUsingProcesses.erase(&proc);
185 IFDEBUG(debug("SSauth", "Authorization %p removed process %p(%d)%s",
186 this, &proc, proc.pid(), mUsingProcesses.empty() ? " FINAL" : ""));
187 return mUsingProcesses.empty();
188 }
189
190
191 //
192 // Check whether internalization/externalization is allowed
193 //
194 bool AuthorizationToken::mayExternalize(Process &) const
195 {
196 return mTransferCount > 0;
197 }
198
199 bool AuthorizationToken::mayInternalize(Process &, bool countIt)
200 {
201 StLock<Mutex> _(mLock);
202 if (mTransferCount > 0) {
203 if (countIt) {
204 mTransferCount--;
205 debug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount);
206 }
207 return true;
208 }
209 return false;
210 }
211
212 AuthorizationItemSet &
213 AuthorizationToken::infoSet()
214 {
215 StLock<Mutex> _(mLock); // consider a separate lock
216 MutableRightSet tempInfoSet(mInfoSet); // turn no info into empty set
217
218 AuthorizationItemSet *returnSet = Copier<AuthorizationItemSet>(tempInfoSet, CssmAllocator::standard()).keep();
219 debug("SSauth", "Authorization %p returning context %p", this, returnSet);
220 return *returnSet;
221 }
222
223 void
224 AuthorizationToken::setInfoSet(AuthorizationItemSet &newInfoSet)
225 {
226 StLock<Mutex> _(mLock); // consider a separate lock
227 if (mInfoSet)
228 CssmAllocator::standard().free(mInfoSet); // @@@ move to sensitive allocator
229 debug("SSauth", "Authorization %p context %p -> %p", this, mInfoSet, &newInfoSet);
230 mInfoSet = &newInfoSet;
231 }
232
233 // This is destructive (non-merging)
234 void
235 AuthorizationToken::setCredentialInfo(const Credential &inCred)
236 {
237 StLock<Mutex> _(mLock);
238
239 MutableRightSet dstInfoSet;
240 char uid_string[16]; // fit a uid_t(u_int32_t)
241
242 if (snprintf(uid_string, sizeof(uid_string), "%u", inCred->uid()) >=
243 sizeof(uid_string))
244 uid_string[0] = '\0';
245 Right uidHint("uid", uid_string ? strlen(uid_string) + 1 : 0, uid_string );
246 dstInfoSet.push_back(uidHint);
247
248 const char *user = inCred->username().c_str();
249 Right userHint("username", user ? strlen(user) + 1 : 0, user );
250 dstInfoSet.push_back(userHint);
251
252 AuthorizationItemSet *newInfoSet = Copier<AuthorizationItemSet>(dstInfoSet, CssmAllocator::standard()).keep();
253 CssmAllocator::standard().free(mInfoSet); // @@@ move to sensitive allocator
254 mInfoSet = newInfoSet;
255 }
256