]> git.saurik.com Git - apple/security.git/blob - SecurityServer/agentquery.cpp
Security-29.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 "server.h"
24
25 using namespace SecurityAgent;
26
27
28 //
29 // Construct a query object
30 //
31 SecurityAgentQuery::SecurityAgentQuery()
32 {
33 // this may take a while
34 Server::active().longTermActivity();
35 Server::connection().useAgent(this);
36 }
37
38 SecurityAgentQuery::~SecurityAgentQuery()
39 {
40 Server::connection(true).useAgent(NULL);
41 }
42
43
44 //
45 // Perform the "rogue app" access query dialog
46 //
47 void QueryKeychainUse::operator () (const char *database, const char *description,
48 AclAuthorization action)
49 {
50 queryKeychainAccess(Server::connection().process.clientCode(),
51 Server::connection().process.pid(),
52 database, description, action, *this);
53 }
54
55
56 //
57 // Obtain passphrases and submit them to the accept() method until it is accepted
58 // or we can't get another passphrase. Accept() should consume the passphrase
59 // if it is accepted. If no passphrase is acceptable, throw out of here.
60 //
61 void QueryPassphrase::query(const AccessCredentials *cred, CSSM_SAMPLE_TYPE sampleType)
62 {
63 CssmAutoData passphrase(CssmAllocator::standard(CssmAllocator::sensitive));
64 if (SecurityServerAcl::getBatchPassphrase(cred, sampleType, passphrase)) {
65 // batch use - try the one and only, fail if unacceptable
66 if (accept(passphrase, false) == noReason)
67 return;
68 else
69 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PASSPHRASE); //@@@ not ideal
70 } else {
71 // interactive use - run a try/retry loop
72 unsigned int retryCount = 0;
73 queryInteractive(passphrase);
74 while (Reason reason = accept(passphrase, true)) {
75 if (++retryCount > maxRetries) {
76 cancelStagedQuery(tooManyTries);
77 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PASSPHRASE); //@@@ not ideal
78 } else {
79 retryInteractive(passphrase, reason);
80 }
81 }
82 // accepted
83 finishStagedQuery();
84 }
85 }
86
87
88 //
89 // Get existing passphrase (unlock) Query
90 //
91 void QueryUnlock::operator () (const AccessCredentials *cred)
92 {
93 query(cred, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK);
94 }
95
96 Reason QueryUnlock::accept(CssmManagedData &passphrase, bool)
97 {
98 return database.decode(passphrase) ? noReason : invalidPassphrase;
99 }
100
101 void QueryUnlock::queryInteractive(CssmOwnedData &passphrase)
102 {
103 char passString[maxPassphraseLength];
104 queryUnlockDatabase(Server::connection().process.clientCode(),
105 Server::connection().process.pid(),
106 database.dbName(), passString);
107 passphrase.copy(passString, strlen(passString));
108 }
109
110 void QueryUnlock::retryInteractive(CssmOwnedData &passphrase, Reason reason)
111 {
112 char passString[maxPassphraseLength];
113 retryUnlockDatabase(reason, passString);
114 passphrase.copy(passString, strlen(passString));
115 }
116
117
118 //
119 // Get new passphrase Query
120 //
121 void QueryNewPassphrase::operator () (const AccessCredentials *cred, CssmOwnedData &passphrase)
122 {
123 query(cred, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK);
124 passphrase = mPassphrase;
125 }
126
127 Reason QueryNewPassphrase::accept(CssmManagedData &passphrase, bool canRetry)
128 {
129 //@@@ acceptance criteria are currently hardwired here
130 //@@@ This validation presumes ASCII - UTF8 might be more lenient
131
132 // if we can't retry (i.e. batch environment), accept it rather than fail terminally
133 if (!canRetry) {
134 mPassphrase = passphrase;
135 return noReason;
136 }
137
138 // if the user insists (re-enters the same passphrase), allow it
139 if (mPassphraseValid && passphrase.get() == mPassphrase)
140 return noReason;
141
142 // check simple criteria
143 mPassphrase = passphrase;
144 mPassphraseValid = true;
145 if (mPassphrase.length() == 0)
146 return passphraseIsNull;
147 const char *passString = mPassphrase;
148 if (strlen(passString) < 6)
149 return passphraseTooSimple;
150
151 // accept this
152 return noReason;
153 }
154
155 void QueryNewPassphrase::queryInteractive(CssmOwnedData &passphrase)
156 {
157 char passString[maxPassphraseLength];
158 queryNewPassphrase(Server::connection().process.clientCode(),
159 Server::connection().process.pid(),
160 dbCommon.dbName(), initialReason, passString);
161 passphrase.copy(passString, strlen(passString));
162 }
163
164 void QueryNewPassphrase::retryInteractive(CssmOwnedData &passphrase, Reason reason)
165 {
166 char passString[maxPassphraseLength];
167 retryNewPassphrase(reason, passString);
168 passphrase.copy(passString, strlen(passString));
169 }
170
171
172 //
173 // Authorize by group membership
174 //
175 void QueryAuthorizeByGroup::cancel(Reason reason)
176 {
177 if (mActive) {
178 cancelStagedQuery(reason);
179 mActive = false;
180 }
181 }
182
183 void QueryAuthorizeByGroup::done()
184 {
185 if (mActive) {
186 finishStagedQuery();
187 mActive = false;
188 }
189 }
190
191 uid_t QueryAuthorizeByGroup::uid()
192 {
193 return Server::connection().process.uid();
194 }
195
196 bool QueryAuthorizeByGroup::operator () (const char *group, const char *candidateUser,
197 char username[maxUsernameLength], char passphrase[maxPassphraseLength], Reason reason)
198 {
199 if (mActive) {
200 return retryAuthorizationAuthenticate(reason, username, passphrase);
201 } else {
202 bool result = authorizationAuthenticate(Server::connection().process.clientCode(),
203 Server::connection().process.pid(), group, candidateUser, username, passphrase);
204 mActive = true;
205 return result;
206 }
207 }