2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // passphrases - canonical code to obtain passphrases
22 #include "agentquery.h"
23 #include "authority.h"
27 using namespace SecurityAgent
;
31 // The default Mach service name for SecurityAgent
33 const char SecurityAgentQuery::defaultName
[] = "com.apple.SecurityAgent";
37 // Construct a query object
39 SecurityAgentQuery::SecurityAgentQuery() :
40 SecurityAgent::Client(Server::active().connection().process
.uid(),
41 Server::active().connection().process
.session
.bootstrapPort(),
43 mClientSession(Server::active().connection().process
.session
)
47 SecurityAgentQuery::SecurityAgentQuery(uid_t clientUID
,
48 Session
&clientSession
,
49 const char *agentName
) :
50 SecurityAgent::Client(clientUID
, clientSession
.bootstrapPort(), agentName
),
51 mClientSession(clientSession
)
55 SecurityAgentQuery::~SecurityAgentQuery()
61 SecurityAgentQuery::activate()
66 // Before popping up an agent: is UI session allowed?
67 if (!(mClientSession
.attributes() & sessionHasGraphicAccess
))
68 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION
);
70 // this may take a while
71 Server::active().longTermActivity();
72 Server::connection().useAgent(this);
75 SecurityAgent::Client::activate();
77 Server::connection().useAgent(NULL
); // guess not
83 SecurityAgentQuery::terminate()
88 Server::connection(true).useAgent(NULL
);
90 SecurityAgent::Client::terminate();
95 // Perform the "rogue app" access query dialog
97 void QueryKeychainUse::queryUser (const Database
*db
, const char *database
, const char *description
,
98 AclAuthorization action
)
102 queryKeychainAccess(Server::connection().process
.clientCode(),
103 Server::connection().process
.pid(),
104 database
, description
, action
, needPassphrase
, *this);
106 CssmData
data (passphrase
, strlen (passphrase
));
109 if (needPassphrase
) {
110 while (reason
= (const_cast<Database
*>(db
)->decode(data
) ? noReason
: invalidPassphrase
)) {
111 if (++retryCount
> kMaximumAuthorizationTries
) {
112 cancelStagedQuery(tooManyTries
);
116 retryQueryKeychainAccess (reason
, *this);
117 data
= CssmData (passphrase
, strlen (passphrase
));
121 finishStagedQuery (); // since we are only staged if we needed a passphrase
126 QueryKeychainUse::~QueryKeychainUse()
128 // clear passphrase component (sensitive)
129 memset(passphrase
, 0, sizeof(passphrase
));
134 // Perform code signature ACL access adjustment dialogs
136 void QueryCodeCheck::operator () (const char *aclPath
)
138 queryCodeIdentity(Server::connection().process
.clientCode(),
139 Server::connection().process
.pid(), aclPath
, *this);
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.
148 Reason
QueryUnlock::query()
150 CssmAutoData
passphrase(CssmAllocator::standard(CssmAllocator::sensitive
));
152 queryInteractive(passphrase
);
153 while (Reason reason
= accept(passphrase
)) {
154 if (++retryCount
> maxTries
) {
155 cancelStagedQuery(tooManyTries
);
158 retryInteractive(passphrase
, reason
);
168 // Get existing passphrase (unlock) Query
170 Reason
QueryUnlock::operator () ()
175 Reason
QueryUnlock::accept(CssmManagedData
&passphrase
)
177 return database
.decode(passphrase
) ? noReason
: invalidPassphrase
;
180 void QueryUnlock::queryInteractive(CssmOwnedData
&passphrase
)
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
));
189 void QueryUnlock::retryInteractive(CssmOwnedData
&passphrase
, Reason reason
)
191 char passString
[maxPassphraseLength
];
192 retryUnlockDatabase(reason
, passString
);
193 passphrase
.copy(passString
, strlen(passString
));
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.
202 Reason
QueryNewPassphrase::query()
204 CssmAutoData
passphrase(CssmAllocator::standard(CssmAllocator::sensitive
));
205 CssmAutoData
oldPassphrase(CssmAllocator::standard(CssmAllocator::sensitive
));
207 queryInteractive(passphrase
, oldPassphrase
);
208 while (Reason reason
= accept(passphrase
,
209 (initialReason
== changePassphrase
) ? &oldPassphrase
.get() : NULL
)) {
210 if (++retryCount
> maxTries
) {
211 cancelStagedQuery(tooManyTries
);
214 retryInteractive(passphrase
, oldPassphrase
, reason
);
224 // Get new passphrase Query
226 Reason
QueryNewPassphrase::operator () (CssmOwnedData
&passphrase
)
228 if (Reason result
= query())
229 return result
; // failed
230 passphrase
= mPassphrase
;
231 return noReason
; // success
234 Reason
QueryNewPassphrase::accept(CssmManagedData
&passphrase
, CssmData
*oldPassphrase
)
236 //@@@ acceptance criteria are currently hardwired here
237 //@@@ This validation presumes ASCII - UTF8 might be more lenient
239 // if we have an old passphrase, check it
240 if (oldPassphrase
&& !database
.validatePassphrase(*oldPassphrase
))
241 return oldPassphraseWrong
;
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
;
257 void QueryNewPassphrase::queryInteractive(CssmOwnedData
&passphrase
, CssmOwnedData
&oldPassphrase
)
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
));
267 void QueryNewPassphrase::retryInteractive(CssmOwnedData
&passphrase
, CssmOwnedData
&oldPassphrase
, Reason reason
)
269 char passString
[maxPassphraseLength
], oldPassString
[maxPassphraseLength
];
270 retryNewPassphrase(reason
, passString
, oldPassString
);
271 passphrase
.copy(passString
, strlen(passString
));
272 oldPassphrase
.copy(oldPassString
, strlen(oldPassString
));
277 // Authorize by group membership
279 QueryAuthorizeByGroup::QueryAuthorizeByGroup(uid_t clientUID
, const AuthorizationToken
&auth
) :
280 SecurityAgentQuery(Server::active().connection().process
.uid(), auth
.session
),
281 authorization(auth
), mActive(false) { }
284 void QueryAuthorizeByGroup::cancel(Reason reason
)
287 cancelStagedQuery(reason
);
292 void QueryAuthorizeByGroup::done()
300 uid_t
QueryAuthorizeByGroup::uid()
302 return Server::connection().process
.uid();
305 bool QueryAuthorizeByGroup::operator () (const char *group
, const char *candidateUser
,
306 char username
[maxUsernameLength
], char passphrase
[maxPassphraseLength
], Reason reason
)
309 return retryAuthorizationAuthenticate(reason
, username
, passphrase
);
311 bool result
= authorizationAuthenticate(authorization
.creatorCode(),
312 Server::connection().process
.pid(), group
, candidateUser
, username
, passphrase
);
318 QueryInvokeMechanism::QueryInvokeMechanism(uid_t clientUID
, const AuthorizationToken
&auth
, const char *agentName
) :
319 SecurityAgentQuery(clientUID
, auth
.session
, agentName
) {}
321 bool QueryInvokeMechanism::operator () (const string
&inPluginId
, const string
&inMechanismId
, const AuthValueVector
&inArguments
, AuthItemSet
&inHints
, AuthItemSet
&inContext
, AuthorizationResult
*outResult
)
323 bool result
= invokeMechanism(inPluginId
, inMechanismId
, inArguments
, inHints
, inContext
, outResult
);
327 void QueryInvokeMechanism::terminateAgent()
329 SecurityAgentQuery::terminateAgent();