]> git.saurik.com Git - apple/security.git/blob - SecurityServer/agentquery.cpp
Security-54.1.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 // Construct a query object
32 //
33 SecurityAgentQuery::SecurityAgentQuery(uid_t clientUID,
34 Session &clientSession) :
35 SecurityAgent::Client(clientUID, clientSession.bootstrapPort()),
36 mClientSession(clientSession)
37 {
38 }
39
40 SecurityAgentQuery::~SecurityAgentQuery()
41 {
42 // SecurityAgent::Client::~SecurityAgent already calls terminate().
43 }
44
45 void
46 SecurityAgentQuery::activate(const char *bootstrapName = NULL)
47 {
48 if (isActive())
49 return;
50
51 // Before popping up an agent: is UI session allowed?
52 if (!(mClientSession.attributes() & sessionHasGraphicAccess))
53 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION);
54
55 // this may take a while
56 Server::active().longTermActivity();
57 Server::connection().useAgent(this);
58
59 SecurityAgent::Client::activate(bootstrapName);
60 }
61
62 void
63 SecurityAgentQuery::terminate()
64 {
65 if (!isActive())
66 return;
67
68 Server::connection(true).useAgent(NULL);
69 SecurityAgent::Client::terminate();
70 }
71
72
73 //
74 // Perform the "rogue app" access query dialog
75 //
76 void QueryKeychainUse::operator () (const char *database, const char *description,
77 AclAuthorization action)
78 {
79 queryKeychainAccess(Server::connection().process.clientCode(),
80 Server::connection().process.pid(),
81 database, description, action, needPassphrase, *this);
82 }
83
84
85 //
86 // Obtain passphrases and submit them to the accept() method until it is accepted
87 // or we can't get another passphrase. Accept() should consume the passphrase
88 // if it is accepted. If no passphrase is acceptable, throw out of here.
89 //
90 void QueryPassphrase::query(const AccessCredentials *cred, CSSM_SAMPLE_TYPE sampleType)
91 {
92 CssmAutoData passphrase(CssmAllocator::standard(CssmAllocator::sensitive));
93 if (SecurityServerAcl::getBatchPassphrase(cred, sampleType, passphrase)) {
94 // batch use - try the one and only, fail if unacceptable
95 if (accept(passphrase, false) == noReason)
96 return;
97 else
98 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PASSPHRASE); //@@@ not ideal
99 } else {
100 // interactive use - run a try/retry loop
101 unsigned int retryCount = 0;
102 queryInteractive(passphrase);
103 while (Reason reason = accept(passphrase, true)) {
104 if (++retryCount > maxRetries) {
105 cancelStagedQuery(tooManyTries);
106 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PASSPHRASE); //@@@ not ideal
107 } else {
108 retryInteractive(passphrase, reason);
109 }
110 }
111 // accepted
112 finishStagedQuery();
113 }
114 }
115
116
117 //
118 // Get existing passphrase (unlock) Query
119 //
120 void QueryUnlock::operator () (const AccessCredentials *cred)
121 {
122 query(cred, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK);
123 }
124
125 Reason QueryUnlock::accept(CssmManagedData &passphrase, bool)
126 {
127 return database.decode(passphrase) ? noReason : invalidPassphrase;
128 }
129
130 void QueryUnlock::queryInteractive(CssmOwnedData &passphrase)
131 {
132 char passString[maxPassphraseLength];
133 queryUnlockDatabase(Server::connection().process.clientCode(),
134 Server::connection().process.pid(),
135 database.dbName(), passString);
136 passphrase.copy(passString, strlen(passString));
137 }
138
139 void QueryUnlock::retryInteractive(CssmOwnedData &passphrase, Reason reason)
140 {
141 char passString[maxPassphraseLength];
142 retryUnlockDatabase(reason, passString);
143 passphrase.copy(passString, strlen(passString));
144 }
145
146
147 //
148 // Get new passphrase Query
149 //
150 void QueryNewPassphrase::operator () (const AccessCredentials *cred, CssmOwnedData &passphrase)
151 {
152 query(cred, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK);
153 passphrase = mPassphrase;
154 }
155
156 Reason QueryNewPassphrase::accept(CssmManagedData &passphrase, bool canRetry)
157 {
158 //@@@ acceptance criteria are currently hardwired here
159 //@@@ This validation presumes ASCII - UTF8 might be more lenient
160
161 // if we can't retry (i.e. batch environment), accept it rather than fail terminally
162 if (!canRetry) {
163 mPassphrase = passphrase;
164 return noReason;
165 }
166
167 // if the user insists (re-enters the same passphrase), allow it
168 if (mPassphraseValid && passphrase.get() == mPassphrase)
169 return noReason;
170
171 // check simple criteria
172 mPassphrase = passphrase;
173 mPassphraseValid = true;
174 if (mPassphrase.length() == 0)
175 return passphraseIsNull;
176 const char *passString = mPassphrase;
177 if (strlen(passString) < 6)
178 return passphraseTooSimple;
179
180 // accept this
181 return noReason;
182 }
183
184 void QueryNewPassphrase::queryInteractive(CssmOwnedData &passphrase)
185 {
186 char passString[maxPassphraseLength];
187 queryNewPassphrase(Server::connection().process.clientCode(),
188 Server::connection().process.pid(),
189 dbCommon.dbName(), initialReason, passString);
190 passphrase.copy(passString, strlen(passString));
191 }
192
193 void QueryNewPassphrase::retryInteractive(CssmOwnedData &passphrase, Reason reason)
194 {
195 char passString[maxPassphraseLength];
196 retryNewPassphrase(reason, passString);
197 passphrase.copy(passString, strlen(passString));
198 }
199
200
201 //
202 // Authorize by group membership
203 //
204 QueryAuthorizeByGroup::QueryAuthorizeByGroup(uid_t clientUID, const AuthorizationToken &auth) :
205 SecurityAgentQuery(clientUID, auth.session),
206 authorization(auth), mActive(false) { }
207
208
209 void QueryAuthorizeByGroup::cancel(Reason reason)
210 {
211 if (mActive) {
212 cancelStagedQuery(reason);
213 mActive = false;
214 }
215 }
216
217 void QueryAuthorizeByGroup::done()
218 {
219 if (mActive) {
220 finishStagedQuery();
221 mActive = false;
222 }
223 }
224
225 uid_t QueryAuthorizeByGroup::uid()
226 {
227 return Server::connection().process.uid();
228 }
229
230 bool QueryAuthorizeByGroup::operator () (const char *group, const char *candidateUser,
231 char username[maxUsernameLength], char passphrase[maxPassphraseLength], Reason reason)
232 {
233 if (mActive) {
234 return retryAuthorizationAuthenticate(reason, username, passphrase);
235 } else {
236 bool result = authorizationAuthenticate(authorization.creatorCode(),
237 Server::connection().process.pid(), group, candidateUser, username, passphrase);
238 mActive = true;
239 return result;
240 }
241 }
242
243 QueryInvokeMechanism::QueryInvokeMechanism(uid_t clientUID, const AuthorizationToken &auth) :
244 SecurityAgentQuery(clientUID, auth.session) {}
245
246 bool QueryInvokeMechanism::operator () (const string &inPluginId, const string &inMechanismId, const AuthorizationValueVector *inArguments, const AuthItemSet &inHints, const AuthItemSet &inContext, AuthorizationResult *outResult, AuthorizationItemSet *&outHintsPtr, AuthorizationItemSet *&outContextPtr)
247 {
248 bool result = invokeMechanism(inPluginId, inMechanismId, inArguments, inHints, inContext, outResult, outHintsPtr, outContextPtr);
249 return result;
250 }
251
252 QueryTerminateAgent::QueryTerminateAgent(uid_t clientUID, const AuthorizationToken &auth) :
253 SecurityAgentQuery(clientUID, auth.session) {}
254
255 void QueryTerminateAgent::operator () ()
256 {
257 terminateAgent();
258 }
259