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 // Construct a query object
33 SecurityAgentQuery::SecurityAgentQuery(uid_t clientUID
,
34 Session
&clientSession
) :
35 SecurityAgent::Client(clientUID
, clientSession
.bootstrapPort()),
36 mClientSession(clientSession
)
40 SecurityAgentQuery::~SecurityAgentQuery()
42 // SecurityAgent::Client::~SecurityAgent already calls terminate().
46 SecurityAgentQuery::activate(const char *bootstrapName
= NULL
)
51 // Before popping up an agent: is UI session allowed?
52 if (!(mClientSession
.attributes() & sessionHasGraphicAccess
))
53 CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION
);
55 // this may take a while
56 Server::active().longTermActivity();
57 Server::connection().useAgent(this);
59 SecurityAgent::Client::activate(bootstrapName
);
63 SecurityAgentQuery::terminate()
68 Server::connection(true).useAgent(NULL
);
69 SecurityAgent::Client::terminate();
74 // Perform the "rogue app" access query dialog
76 void QueryKeychainUse::operator () (const char *database
, const char *description
,
77 AclAuthorization action
)
79 queryKeychainAccess(Server::connection().process
.clientCode(),
80 Server::connection().process
.pid(),
81 database
, description
, action
, needPassphrase
, *this);
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.
90 void QueryPassphrase::query(const AccessCredentials
*cred
, CSSM_SAMPLE_TYPE sampleType
)
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
)
98 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PASSPHRASE
); //@@@ not ideal
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
108 retryInteractive(passphrase
, reason
);
118 // Get existing passphrase (unlock) Query
120 void QueryUnlock::operator () (const AccessCredentials
*cred
)
122 query(cred
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
);
125 Reason
QueryUnlock::accept(CssmManagedData
&passphrase
, bool)
127 return database
.decode(passphrase
) ? noReason
: invalidPassphrase
;
130 void QueryUnlock::queryInteractive(CssmOwnedData
&passphrase
)
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
));
139 void QueryUnlock::retryInteractive(CssmOwnedData
&passphrase
, Reason reason
)
141 char passString
[maxPassphraseLength
];
142 retryUnlockDatabase(reason
, passString
);
143 passphrase
.copy(passString
, strlen(passString
));
148 // Get new passphrase Query
150 void QueryNewPassphrase::operator () (const AccessCredentials
*cred
, CssmOwnedData
&passphrase
)
152 query(cred
, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
);
153 passphrase
= mPassphrase
;
156 Reason
QueryNewPassphrase::accept(CssmManagedData
&passphrase
, bool canRetry
)
158 //@@@ acceptance criteria are currently hardwired here
159 //@@@ This validation presumes ASCII - UTF8 might be more lenient
161 // if we can't retry (i.e. batch environment), accept it rather than fail terminally
163 mPassphrase
= passphrase
;
167 // if the user insists (re-enters the same passphrase), allow it
168 if (mPassphraseValid
&& passphrase
.get() == mPassphrase
)
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
;
184 void QueryNewPassphrase::queryInteractive(CssmOwnedData
&passphrase
)
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
));
193 void QueryNewPassphrase::retryInteractive(CssmOwnedData
&passphrase
, Reason reason
)
195 char passString
[maxPassphraseLength
];
196 retryNewPassphrase(reason
, passString
);
197 passphrase
.copy(passString
, strlen(passString
));
202 // Authorize by group membership
204 QueryAuthorizeByGroup::QueryAuthorizeByGroup(uid_t clientUID
, const AuthorizationToken
&auth
) :
205 SecurityAgentQuery(clientUID
, auth
.session
),
206 authorization(auth
), mActive(false) { }
209 void QueryAuthorizeByGroup::cancel(Reason reason
)
212 cancelStagedQuery(reason
);
217 void QueryAuthorizeByGroup::done()
225 uid_t
QueryAuthorizeByGroup::uid()
227 return Server::connection().process
.uid();
230 bool QueryAuthorizeByGroup::operator () (const char *group
, const char *candidateUser
,
231 char username
[maxUsernameLength
], char passphrase
[maxPassphraseLength
], Reason reason
)
234 return retryAuthorizationAuthenticate(reason
, username
, passphrase
);
236 bool result
= authorizationAuthenticate(authorization
.creatorCode(),
237 Server::connection().process
.pid(), group
, candidateUser
, username
, passphrase
);
243 QueryInvokeMechanism::QueryInvokeMechanism(uid_t clientUID
, const AuthorizationToken
&auth
) :
244 SecurityAgentQuery(clientUID
, auth
.session
) {}
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
)
248 bool result
= invokeMechanism(inPluginId
, inMechanismId
, inArguments
, inHints
, inContext
, outResult
, outHintsPtr
, outContextPtr
);
252 QueryTerminateAgent::QueryTerminateAgent(uid_t clientUID
, const AuthorizationToken
&auth
) :
253 SecurityAgentQuery(clientUID
, auth
.session
) {}
255 void QueryTerminateAgent::operator () ()