]> git.saurik.com Git - apple/security.git/blob - SecurityServer/agentquery.cpp
Security-179.tar.gz
[apple/security.git] / SecurityServer / agentquery.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 // passphrases - canonical code to obtain passphrases
21 //
22 #include "agentquery.h"
23 #include "authority.h"
24 #include "server.h"
25 #include "session.h"
26
27 using namespace SecurityAgent;
28
29
30 //
31 // The default Mach service name for SecurityAgent
32 //
33 const char SecurityAgentQuery::defaultName[] = "com.apple.SecurityAgent";
34
35
36 //
37 // Construct a query object
38 //
39 SecurityAgentQuery::SecurityAgentQuery() :
40 SecurityAgent::Client(Server::active().connection().process.uid(),
41 Server::active().connection().process.session.bootstrapPort(),
42 defaultName),
43 mClientSession(Server::active().connection().process.session)
44 {
45 }
46
47 SecurityAgentQuery::SecurityAgentQuery(uid_t clientUID,
48 Session &clientSession,
49 const char *agentName) :
50 SecurityAgent::Client(clientUID, clientSession.bootstrapPort(), agentName),
51 mClientSession(clientSession)
52 {
53 }
54
55 SecurityAgentQuery::~SecurityAgentQuery()
56 {
57 terminate();
58 }
59
60 void
61 SecurityAgentQuery::activate()
62 {
63 if (isActive())
64 return;
65
66 // Before popping up an agent: is UI session allowed?
67 if (!(mClientSession.attributes() & sessionHasGraphicAccess))
68 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
69
70 // this may take a while
71 Server::active().longTermActivity();
72 Server::connection().useAgent(this);
73
74 try {
75 SecurityAgent::Client::activate();
76 } catch (...) {
77 Server::connection().useAgent(NULL); // guess not
78 throw;
79 }
80 }
81
82 void
83 SecurityAgentQuery::terminate()
84 {
85 if (!isActive())
86 return;
87
88 Server::connection(true).useAgent(NULL);
89
90 SecurityAgent::Client::terminate();
91 }
92
93
94 //
95 // Perform the "rogue app" access query dialog
96 //
97 void QueryKeychainUse::queryUser (const Database *db, const char *database, const char *description,
98 AclAuthorization action)
99 {
100 Reason reason;
101 int retryCount = 0;
102 queryKeychainAccess(Server::connection().process.clientCode(),
103 Server::connection().process.pid(),
104 database, description, action, needPassphrase, *this);
105
106 CssmData data (passphrase, strlen (passphrase));
107
108
109 if (needPassphrase) {
110 while (reason = (const_cast<Database*>(db)->decode(data) ? noReason : invalidPassphrase)) {
111 if (++retryCount > kMaximumAuthorizationTries) {
112 cancelStagedQuery(tooManyTries);
113 return;
114 }
115 else {
116 retryQueryKeychainAccess (reason, *this);
117 data = CssmData (passphrase, strlen (passphrase));
118 }
119 }
120
121 finishStagedQuery (); // since we are only staged if we needed a passphrase
122 }
123
124 }
125
126 QueryKeychainUse::~QueryKeychainUse()
127 {
128 // clear passphrase component (sensitive)
129 memset(passphrase, 0, sizeof(passphrase));
130 }
131
132
133 //
134 // Perform code signature ACL access adjustment dialogs
135 //
136 void QueryCodeCheck::operator () (const char *aclPath)
137 {
138 queryCodeIdentity(Server::connection().process.clientCode(),
139 Server::connection().process.pid(), aclPath, *this);
140 }
141
142
143 //
144 // Obtain passphrases and submit them to the accept() method until it is accepted
145 // or we can't get another passphrase. Accept() should consume the passphrase
146 // if it is accepted. If no passphrase is acceptable, throw out of here.
147 //
148 Reason QueryUnlock::query()
149 {
150 CssmAutoData passphrase(CssmAllocator::standard(CssmAllocator::sensitive));
151 int retryCount = 0;
152 queryInteractive(passphrase);
153 while (Reason reason = accept(passphrase)) {
154 if (++retryCount > maxTries) {
155 cancelStagedQuery(tooManyTries);
156 return reason;
157 } else {
158 retryInteractive(passphrase, reason);
159 }
160 }
161 // accepted
162 finishStagedQuery();
163 return noReason;
164 }
165
166
167 //
168 // Get existing passphrase (unlock) Query
169 //
170 Reason QueryUnlock::operator () ()
171 {
172 return query();
173 }
174
175 Reason QueryUnlock::accept(CssmManagedData &passphrase)
176 {
177 return database.decode(passphrase) ? noReason : invalidPassphrase;
178 }
179
180 void QueryUnlock::queryInteractive(CssmOwnedData &passphrase)
181 {
182 char passString[maxPassphraseLength];
183 queryUnlockDatabase(Server::connection().process.clientCode(),
184 Server::connection().process.pid(),
185 database.dbName(), passString);
186 passphrase.copy(passString, strlen(passString));
187 }
188
189 void QueryUnlock::retryInteractive(CssmOwnedData &passphrase, Reason reason)
190 {
191 char passString[maxPassphraseLength];
192 retryUnlockDatabase(reason, passString);
193 passphrase.copy(passString, strlen(passString));
194 }
195
196
197 //
198 // Obtain passphrases and submit them to the accept() method until it is accepted
199 // or we can't get another passphrase. Accept() should consume the passphrase
200 // if it is accepted. If no passphrase is acceptable, throw out of here.
201 //
202 Reason QueryNewPassphrase::query()
203 {
204 CssmAutoData passphrase(CssmAllocator::standard(CssmAllocator::sensitive));
205 CssmAutoData oldPassphrase(CssmAllocator::standard(CssmAllocator::sensitive));
206 int retryCount = 0;
207 queryInteractive(passphrase, oldPassphrase);
208 while (Reason reason = accept(passphrase,
209 (initialReason == changePassphrase) ? &oldPassphrase.get() : NULL)) {
210 if (++retryCount > maxTries) {
211 cancelStagedQuery(tooManyTries);
212 return reason;
213 } else {
214 retryInteractive(passphrase, oldPassphrase, reason);
215 }
216 }
217 // accepted
218 finishStagedQuery();
219 return noReason;
220 }
221
222
223 //
224 // Get new passphrase Query
225 //
226 Reason QueryNewPassphrase::operator () (CssmOwnedData &passphrase)
227 {
228 if (Reason result = query())
229 return result; // failed
230 passphrase = mPassphrase;
231 return noReason; // success
232 }
233
234 Reason QueryNewPassphrase::accept(CssmManagedData &passphrase, CssmData *oldPassphrase)
235 {
236 //@@@ acceptance criteria are currently hardwired here
237 //@@@ This validation presumes ASCII - UTF8 might be more lenient
238
239 // if we have an old passphrase, check it
240 if (oldPassphrase && !database.validatePassphrase(*oldPassphrase))
241 return oldPassphraseWrong;
242
243 // sanity check the new passphrase (but allow user override)
244 if (!(mPassphraseValid && passphrase.get() == mPassphrase)) {
245 mPassphrase = passphrase;
246 mPassphraseValid = true;
247 if (mPassphrase.length() == 0)
248 return passphraseIsNull;
249 if (mPassphrase.length() < 6)
250 return passphraseTooSimple;
251 }
252
253 // accept this
254 return noReason;
255 }
256
257 void QueryNewPassphrase::queryInteractive(CssmOwnedData &passphrase, CssmOwnedData &oldPassphrase)
258 {
259 char passString[maxPassphraseLength], oldPassString[maxPassphraseLength];
260 queryNewPassphrase(Server::connection().process.clientCode(),
261 Server::connection().process.pid(),
262 database.dbName(), initialReason, passString, oldPassString);
263 passphrase.copy(passString, strlen(passString));
264 oldPassphrase.copy(oldPassString, strlen(oldPassString));
265 }
266
267 void QueryNewPassphrase::retryInteractive(CssmOwnedData &passphrase, CssmOwnedData &oldPassphrase, Reason reason)
268 {
269 char passString[maxPassphraseLength], oldPassString[maxPassphraseLength];
270 retryNewPassphrase(reason, passString, oldPassString);
271 passphrase.copy(passString, strlen(passString));
272 oldPassphrase.copy(oldPassString, strlen(oldPassString));
273 }
274
275
276 //
277 // Authorize by group membership
278 //
279 QueryAuthorizeByGroup::QueryAuthorizeByGroup(uid_t clientUID, const AuthorizationToken &auth) :
280 SecurityAgentQuery(Server::active().connection().process.uid(), auth.session),
281 authorization(auth), mActive(false) { }
282
283
284 void QueryAuthorizeByGroup::cancel(Reason reason)
285 {
286 if (mActive) {
287 cancelStagedQuery(reason);
288 mActive = false;
289 }
290 }
291
292 void QueryAuthorizeByGroup::done()
293 {
294 if (mActive) {
295 finishStagedQuery();
296 mActive = false;
297 }
298 }
299
300 uid_t QueryAuthorizeByGroup::uid()
301 {
302 return Server::connection().process.uid();
303 }
304
305 bool QueryAuthorizeByGroup::operator () (const char *group, const char *candidateUser,
306 char username[maxUsernameLength], char passphrase[maxPassphraseLength], Reason reason)
307 {
308 if (mActive) {
309 return retryAuthorizationAuthenticate(reason, username, passphrase);
310 } else {
311 bool result = authorizationAuthenticate(authorization.creatorCode(),
312 Server::connection().process.pid(), group, candidateUser, username, passphrase);
313 mActive = true;
314 return result;
315 }
316 }
317
318 QueryInvokeMechanism::QueryInvokeMechanism(uid_t clientUID, const AuthorizationToken &auth, const char *agentName) :
319 SecurityAgentQuery(clientUID, auth.session, agentName) {}
320
321 bool QueryInvokeMechanism::operator () (const string &inPluginId, const string &inMechanismId, const AuthValueVector &inArguments, AuthItemSet &inHints, AuthItemSet &inContext, AuthorizationResult *outResult)
322 {
323 bool result = invokeMechanism(inPluginId, inMechanismId, inArguments, inHints, inContext, outResult);
324 return result;
325 }
326
327 void QueryInvokeMechanism::terminateAgent()
328 {
329 SecurityAgentQuery::terminateAgent();
330 }