]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | #include <Security/SecKeychain.h> | |
25 | #include <Security/SecKeychainPriv.h> | |
26 | #include <security_keychain/KCCursor.h> | |
27 | #include <security_cdsa_utilities/cssmdata.h> | |
d8f41ccd | 28 | #include <security_cdsa_client/wrapkey.h> |
b1ab9ed8 A |
29 | #include <security_keychain/KCExceptions.h> |
30 | #include <securityd_client/ssblob.h> | |
d8f41ccd A |
31 | #include <Security/SecAccess.h> |
32 | #include <Security/SecTrustedApplicationPriv.h> | |
b1ab9ed8 A |
33 | #include "SecBridge.h" |
34 | #include "CCallbackMgr.h" | |
35 | #include <security_cdsa_utilities/Schema.h> | |
d8f41ccd | 36 | #include <security_cdsa_client/mdsclient.h> |
b1ab9ed8 | 37 | #include <pwd.h> |
866f8763 | 38 | #include <os/activity.h> |
fa7225c8 A |
39 | #include <Security/AuthorizationTagsPriv.h> |
40 | #include <Security/Authorization.h> | |
41 | #include "TokenLogin.h" | |
d64be36e A |
42 | #include "LegacyAPICounts.h" |
43 | ||
44 | extern "C" { | |
45 | #include "ctkloginhelper.h" | |
46 | } | |
b1ab9ed8 | 47 | |
d8f41ccd A |
48 | OSStatus |
49 | SecKeychainMDSInstall() | |
50 | { | |
866f8763 | 51 | BEGIN_SECAPI |
d64be36e A |
52 | |
53 | os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
54 | os_activity_scope(activity); |
55 | os_release(activity); | |
d8f41ccd A |
56 | |
57 | Security::MDSClient::Directory d; | |
58 | d.install(); | |
59 | ||
60 | END_SECAPI | |
61 | } | |
62 | ||
b1ab9ed8 A |
63 | CFTypeID |
64 | SecKeychainGetTypeID(void) | |
65 | { | |
66 | BEGIN_SECAPI | |
67 | ||
68 | return gTypes().KeychainImpl.typeID; | |
69 | ||
70 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
71 | } | |
72 | ||
73 | ||
74 | OSStatus | |
75 | SecKeychainGetVersion(UInt32 *returnVers) | |
76 | { | |
d64be36e | 77 | COUNTLEGACYAPI |
b1ab9ed8 | 78 | if (!returnVers) |
427c49bc | 79 | return errSecSuccess; |
b1ab9ed8 A |
80 | |
81 | *returnVers = 0x02028000; | |
427c49bc | 82 | return errSecSuccess; |
b1ab9ed8 A |
83 | } |
84 | ||
85 | ||
86 | OSStatus | |
87 | SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef) | |
88 | { | |
89 | BEGIN_SECAPI | |
b1ab9ed8 | 90 | |
d64be36e | 91 | os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
866f8763 A |
92 | os_activity_scope(activity); |
93 | os_release(activity); | |
b1ab9ed8 | 94 | |
d64be36e | 95 | RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); |
b1ab9ed8 A |
96 | |
97 | END_SECAPI | |
98 | } | |
99 | ||
b1ab9ed8 A |
100 | OSStatus |
101 | SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password, | |
102 | Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef) | |
103 | { | |
104 | BEGIN_SECAPI | |
d64be36e A |
105 | |
106 | os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
107 | os_activity_scope(activity); |
108 | os_release(activity); | |
427c49bc A |
109 | |
110 | KCThrowParamErrIf_(!pathName); | |
fa7225c8 | 111 | Keychain keychain = globals().storageManager.make(pathName, true, true); |
b1ab9ed8 A |
112 | |
113 | // @@@ the call to StorageManager::make above leaves keychain the the cache. | |
114 | // If the create below fails we should probably remove it. | |
115 | if(promptUser) | |
116 | keychain->create(); | |
117 | else | |
118 | { | |
119 | KCThrowParamErrIf_(!password); | |
120 | keychain->create(passwordLength, password); | |
121 | } | |
122 | ||
123 | RequiredParam(keychainRef)=keychain->handle(); | |
124 | ||
125 | END_SECAPI | |
126 | } | |
127 | ||
128 | ||
129 | OSStatus | |
130 | SecKeychainDelete(SecKeychainRef keychainOrArray) | |
131 | { | |
132 | BEGIN_SECAPI | |
d64be36e A |
133 | |
134 | os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
135 | os_activity_scope(activity); |
136 | os_release(activity); | |
b1ab9ed8 A |
137 | |
138 | KCThrowIf_(!keychainOrArray, errSecInvalidKeychain); | |
139 | StorageManager::KeychainList keychains; | |
140 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
141 | ||
142 | globals().storageManager.remove(keychains, true); | |
143 | ||
144 | END_SECAPI | |
145 | } | |
146 | ||
147 | ||
148 | OSStatus | |
149 | SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings) | |
150 | { | |
151 | BEGIN_SECAPI | |
d64be36e A |
152 | |
153 | os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
154 | os_activity_scope(activity); |
155 | os_release(activity); | |
b1ab9ed8 A |
156 | |
157 | Keychain keychain = Keychain::optional(keychainRef); | |
158 | if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) | |
159 | { | |
160 | UInt32 lockInterval=newSettings->lockInterval; | |
161 | bool lockOnSleep=newSettings->lockOnSleep; | |
162 | keychain->setSettings(lockInterval, lockOnSleep); | |
163 | } | |
164 | ||
165 | END_SECAPI | |
166 | } | |
167 | ||
168 | ||
169 | OSStatus | |
170 | SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings) | |
171 | { | |
172 | BEGIN_SECAPI | |
d64be36e A |
173 | |
174 | os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
175 | os_activity_scope(activity); |
176 | os_release(activity); | |
b1ab9ed8 A |
177 | |
178 | Keychain keychain = Keychain::optional(keychainRef); | |
179 | if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) | |
180 | { | |
181 | uint32 lockInterval; | |
182 | bool lockOnSleep; | |
183 | ||
184 | keychain->getSettings(lockInterval, lockOnSleep); | |
185 | outSettings->lockInterval=lockInterval; | |
186 | outSettings->lockOnSleep=lockOnSleep; | |
187 | } | |
188 | ||
189 | END_SECAPI | |
190 | } | |
191 | ||
192 | ||
193 | OSStatus | |
194 | SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword) | |
195 | { | |
196 | BEGIN_SECAPI | |
d64be36e A |
197 | |
198 | os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
199 | os_activity_scope(activity); |
200 | os_release(activity); | |
b1ab9ed8 A |
201 | |
202 | Keychain keychain = Keychain::optional(keychainRef); | |
203 | ||
204 | if (usePassword) | |
205 | keychain->unlock(CssmData(const_cast<void *>(password), passwordLength)); | |
206 | else | |
207 | keychain->unlock(); | |
208 | ||
209 | END_SECAPI | |
210 | } | |
211 | ||
212 | ||
213 | OSStatus | |
214 | SecKeychainLock(SecKeychainRef keychainRef) | |
215 | { | |
216 | BEGIN_SECAPI | |
d64be36e A |
217 | |
218 | os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
219 | os_activity_scope(activity); |
220 | os_release(activity); | |
b1ab9ed8 A |
221 | |
222 | Keychain keychain = Keychain::optional(keychainRef); | |
223 | keychain->lock(); | |
224 | ||
225 | END_SECAPI | |
226 | } | |
227 | ||
228 | ||
229 | OSStatus | |
230 | SecKeychainLockAll(void) | |
231 | { | |
232 | BEGIN_SECAPI | |
d64be36e A |
233 | |
234 | os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
235 | os_activity_scope(activity); |
236 | os_release(activity); | |
b1ab9ed8 A |
237 | |
238 | globals().storageManager.lockAll(); | |
239 | ||
240 | END_SECAPI | |
241 | } | |
242 | ||
243 | ||
244 | OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList) | |
245 | { | |
246 | BEGIN_SECAPI | |
d64be36e A |
247 | |
248 | os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
249 | os_activity_scope(activity); |
250 | os_release(activity); | |
b1ab9ed8 A |
251 | // |
252 | // Get the current user (using fallback method if necessary) | |
253 | // | |
254 | char* uName = getenv("USER"); | |
255 | string userName = uName ? uName : ""; | |
256 | if ( userName.length() == 0 ) | |
257 | { | |
258 | uid_t uid = geteuid(); | |
259 | if (!uid) uid = getuid(); | |
260 | struct passwd *pw = getpwuid(uid); // fallback case... | |
261 | if (pw) | |
262 | userName = pw->pw_name; | |
263 | endpwent(); | |
264 | } | |
265 | if ( userName.length() == 0 ) // did we ultimately get one? | |
ecaf5866 | 266 | { |
b1ab9ed8 | 267 | MacOSError::throwMe(errAuthorizationInternal); |
ecaf5866 | 268 | } |
822b670c A |
269 | |
270 | SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData()); | |
ecaf5866 | 271 | secwarning("SecKeychainResetLogin: reset AKS passphrase"); |
b1ab9ed8 A |
272 | if (password) |
273 | { | |
274 | // Clear the plist and move aside (rename) the existing login.keychain | |
275 | globals().storageManager.resetKeychain(resetSearchList); | |
276 | ||
277 | // Create the login keychain without UI | |
fa7225c8 | 278 | globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password, true); |
b1ab9ed8 A |
279 | |
280 | // Set it as the default | |
281 | Keychain keychain = globals().storageManager.loginKeychain(); | |
282 | globals().storageManager.defaultKeychain(keychain); | |
283 | } | |
284 | else | |
285 | { | |
286 | // Create the login keychain, prompting for password | |
287 | // (implicitly calls resetKeychain, login, and defaultKeychain) | |
fa7225c8 | 288 | globals().storageManager.makeLoginAuthUI(NULL, true); |
b1ab9ed8 | 289 | } |
ecaf5866 | 290 | secwarning("SecKeychainResetLogin: reset osx keychain"); |
b1ab9ed8 A |
291 | |
292 | // Post a "list changed" event after a reset, so apps can refresh their list. | |
293 | // Make sure we are not holding mLock when we post this event. | |
294 | KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); | |
295 | ||
ecaf5866 | 296 | |
b1ab9ed8 A |
297 | END_SECAPI |
298 | } | |
299 | ||
300 | OSStatus | |
301 | SecKeychainCopyDefault(SecKeychainRef *keychainRef) | |
302 | { | |
303 | BEGIN_SECAPI | |
304 | ||
305 | RequiredParam(keychainRef)=globals().storageManager.defaultKeychain()->handle(); | |
306 | ||
307 | END_SECAPI | |
308 | } | |
309 | ||
310 | ||
311 | OSStatus | |
312 | SecKeychainSetDefault(SecKeychainRef keychainRef) | |
313 | { | |
314 | BEGIN_SECAPI | |
d64be36e A |
315 | |
316 | os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
317 | os_activity_scope(activity); |
318 | os_release(activity); | |
b1ab9ed8 A |
319 | |
320 | globals().storageManager.defaultKeychain(Keychain::optional(keychainRef)); | |
321 | ||
322 | END_SECAPI | |
323 | } | |
324 | ||
325 | OSStatus SecKeychainCopySearchList(CFArrayRef *searchList) | |
326 | { | |
327 | BEGIN_SECAPI | |
d64be36e A |
328 | |
329 | os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
330 | os_activity_scope(activity); |
331 | os_release(activity); | |
b1ab9ed8 A |
332 | |
333 | RequiredParam(searchList); | |
334 | StorageManager &smr = globals().storageManager; | |
335 | StorageManager::KeychainList keychainList; | |
336 | smr.getSearchList(keychainList); | |
337 | *searchList = smr.convertFromKeychainList(keychainList); | |
338 | ||
339 | END_SECAPI | |
340 | } | |
341 | ||
342 | OSStatus SecKeychainSetSearchList(CFArrayRef searchList) | |
343 | { | |
344 | BEGIN_SECAPI | |
d64be36e A |
345 | |
346 | os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
347 | os_activity_scope(activity); |
348 | os_release(activity); | |
b1ab9ed8 A |
349 | |
350 | RequiredParam(searchList); | |
351 | StorageManager &smr = globals().storageManager; | |
352 | StorageManager::KeychainList keychainList; | |
353 | smr.convertToKeychainList(searchList, keychainList); | |
354 | smr.setSearchList(keychainList); | |
355 | ||
356 | END_SECAPI | |
357 | } | |
358 | ||
359 | OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef) | |
360 | { | |
361 | BEGIN_SECAPI | |
d64be36e A |
362 | |
363 | os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
364 | os_activity_scope(activity); |
365 | os_release(activity); | |
b1ab9ed8 A |
366 | |
367 | RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle(); | |
368 | ||
369 | END_SECAPI | |
370 | } | |
371 | ||
372 | OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef) | |
373 | { | |
374 | BEGIN_SECAPI | |
d64be36e A |
375 | |
376 | os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
377 | os_activity_scope(activity); |
378 | os_release(activity); | |
b1ab9ed8 A |
379 | |
380 | globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef)); | |
381 | ||
382 | END_SECAPI | |
383 | } | |
384 | ||
385 | OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef *searchList) | |
386 | { | |
387 | BEGIN_SECAPI | |
388 | ||
389 | RequiredParam(searchList); | |
390 | StorageManager &smr = globals().storageManager; | |
391 | StorageManager::KeychainList keychainList; | |
392 | smr.getSearchList(domain, keychainList); | |
393 | *searchList = smr.convertFromKeychainList(keychainList); | |
394 | ||
395 | END_SECAPI | |
396 | } | |
397 | ||
398 | OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList) | |
399 | { | |
400 | BEGIN_SECAPI | |
d64be36e A |
401 | |
402 | os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
403 | os_activity_scope(activity); |
404 | os_release(activity); | |
b1ab9ed8 A |
405 | |
406 | RequiredParam(searchList); | |
407 | StorageManager &smr = globals().storageManager; | |
408 | StorageManager::KeychainList keychainList; | |
409 | smr.convertToKeychainList(searchList, keychainList); | |
410 | smr.setSearchList(domain, keychainList); | |
411 | ||
412 | END_SECAPI | |
413 | } | |
414 | ||
415 | OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain) | |
416 | { | |
417 | BEGIN_SECAPI | |
d64be36e A |
418 | |
419 | os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
420 | os_activity_scope(activity); |
421 | os_release(activity); | |
b1ab9ed8 A |
422 | |
423 | globals().storageManager.domain(domain); | |
424 | ||
425 | END_SECAPI | |
426 | } | |
427 | ||
428 | OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain) | |
429 | { | |
430 | BEGIN_SECAPI | |
d64be36e A |
431 | |
432 | os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
433 | os_activity_scope(activity); |
434 | os_release(activity); | |
b1ab9ed8 A |
435 | |
436 | *domain = globals().storageManager.domain(); | |
437 | ||
438 | END_SECAPI | |
439 | } | |
440 | ||
441 | ||
442 | OSStatus | |
443 | SecKeychainGetStatus(SecKeychainRef keychainRef, SecKeychainStatus *keychainStatus) | |
444 | { | |
445 | BEGIN_SECAPI | |
446 | ||
447 | RequiredParam(keychainStatus) = (SecKeychainStatus)Keychain::optional(keychainRef)->status(); | |
448 | ||
449 | END_SECAPI | |
450 | } | |
451 | ||
452 | ||
453 | OSStatus | |
454 | SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathName) | |
455 | { | |
456 | BEGIN_SECAPI | |
457 | ||
458 | RequiredParam(pathName); | |
459 | RequiredParam(ioPathLength); | |
460 | ||
461 | const char *name = Keychain::optional(keychainRef)->name(); | |
427c49bc | 462 | UInt32 nameLen = (UInt32)strlen(name); |
b1ab9ed8 A |
463 | UInt32 callersLen = *ioPathLength; |
464 | *ioPathLength = nameLen; | |
465 | if (nameLen+1 > callersLen) // if the client's buffer is too small (including null-termination), throw | |
466 | return errSecBufferTooSmall; | |
467 | strncpy(pathName, name, nameLen); | |
468 | pathName[nameLen] = 0; | |
469 | *ioPathLength = nameLen; // set the length. | |
470 | ||
471 | END_SECAPI | |
472 | } | |
473 | ||
e3d460c9 A |
474 | OSStatus |
475 | SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version) | |
476 | { | |
477 | BEGIN_SECAPI | |
478 | ||
d64be36e | 479 | RequiredParam(version); |
e3d460c9 A |
480 | |
481 | *version = Keychain::optional(keychainRef)->database()->dbBlobVersion(); | |
482 | ||
483 | END_SECAPI | |
484 | } | |
485 | ||
fa7225c8 A |
486 | OSStatus |
487 | SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename) | |
488 | { | |
489 | BEGIN_SECAPI | |
d64be36e A |
490 | |
491 | os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
492 | os_activity_scope(activity); |
493 | os_release(activity); | |
fa7225c8 A |
494 | |
495 | RequiredParam(masterKeyFilename); | |
496 | Keychain kc = Keychain::optional(keychain); | |
497 | ||
498 | SecurityServer::SystemKeychainKey keychainKey(masterKeyFilename); | |
499 | if(keychainKey.valid()) { | |
500 | // We've managed to read the key; now, create credentials using it | |
501 | string path = kc->name(); | |
502 | ||
503 | CssmClient::Key keychainMasterKey(kc->csp(), keychainKey.key(), true); | |
504 | CssmClient::AclFactory::MasterKeyUnlockCredentials creds(keychainMasterKey, Allocator::standard(Allocator::sensitive)); | |
505 | ||
506 | // Attempt the migrate, using our master key as the ACL override | |
507 | bool result = kc->keychainMigration(path, kc->database()->dbBlobVersion(), path, version, creds.getAccessCredentials()); | |
508 | if(!result) { | |
509 | return errSecBadReq; | |
510 | } | |
511 | return (kc->database()->dbBlobVersion() == version ? errSecSuccess : errSecBadReq); | |
512 | } else { | |
513 | return errSecBadReq; | |
514 | } | |
515 | ||
516 | END_SECAPI | |
517 | } | |
518 | ||
b1ab9ed8 A |
519 | |
520 | // @@@ Deprecated | |
521 | UInt16 | |
522 | SecKeychainListGetCount(void) | |
523 | { | |
524 | BEGIN_SECAPI | |
525 | ||
526 | return globals().storageManager.size(); | |
527 | ||
528 | END_SECAPI1(0) | |
529 | } | |
530 | ||
531 | ||
532 | // @@@ Deprecated | |
533 | OSStatus | |
534 | SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef) | |
535 | { | |
536 | BEGIN_SECAPI | |
537 | ||
538 | KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager; | |
539 | RequiredParam(keychainRef)=smgr[index]->handle(); | |
540 | ||
541 | END_SECAPI | |
542 | } | |
543 | ||
544 | ||
545 | // @@@ Deprecated | |
546 | OSStatus | |
547 | SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef) | |
548 | { | |
549 | BEGIN_SECAPI | |
550 | ||
551 | Required(keychainRef); | |
552 | Keychain keychain = Keychain::optional(*keychainRef); | |
553 | StorageManager::KeychainList keychainList; | |
554 | keychainList.push_back(keychain); | |
555 | globals().storageManager.remove(keychainList); | |
556 | *keychainRef = NULL; | |
557 | ||
558 | END_SECAPI | |
559 | } | |
560 | ||
561 | ||
562 | OSStatus | |
563 | SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info) | |
564 | { | |
565 | BEGIN_SECAPI | |
566 | ||
567 | Keychain keychain = Keychain::optional(keychainRef); | |
568 | keychain->getAttributeInfoForItemID(itemID, info); | |
569 | ||
570 | END_SECAPI | |
571 | } | |
572 | ||
573 | ||
574 | OSStatus | |
575 | SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) | |
576 | { | |
577 | BEGIN_SECAPI | |
578 | ||
579 | KeychainImpl::freeAttributeInfo(info); | |
580 | ||
581 | END_SECAPI | |
582 | } | |
583 | ||
584 | ||
585 | pascal OSStatus | |
586 | SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext) | |
587 | { | |
588 | BEGIN_SECAPI | |
d64be36e A |
589 | |
590 | os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
591 | os_activity_scope(activity); |
592 | os_release(activity); | |
b1ab9ed8 A |
593 | |
594 | RequiredParam(callbackFunction); | |
595 | CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext); | |
596 | ||
597 | END_SECAPI | |
598 | } | |
599 | ||
600 | ||
601 | OSStatus | |
602 | SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) | |
603 | { | |
604 | BEGIN_SECAPI | |
d64be36e A |
605 | |
606 | os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
607 | os_activity_scope(activity); |
608 | os_release(activity); | |
b1ab9ed8 A |
609 | |
610 | RequiredParam(callbackFunction); | |
611 | CCallbackMgr::RemoveCallback(callbackFunction); | |
612 | ||
613 | END_SECAPI | |
614 | } | |
615 | ||
616 | OSStatus | |
617 | SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) | |
618 | { | |
619 | BEGIN_SECAPI | |
d64be36e A |
620 | |
621 | os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
622 | os_activity_scope(activity); |
623 | os_release(activity); | |
b1ab9ed8 A |
624 | |
625 | KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); | |
626 | // @@@ Get real itemClass | |
627 | Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false); | |
628 | ||
629 | if (serverName && serverNameLength) | |
630 | { | |
631 | CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength); | |
632 | item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server); | |
633 | // use server name as default label | |
634 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server); | |
635 | } | |
636 | ||
637 | if (accountName && accountNameLength) | |
638 | { | |
639 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
640 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
641 | } | |
642 | ||
643 | if (securityDomain && securityDomainLength) | |
644 | item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr), | |
645 | CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength)); | |
646 | ||
647 | item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port)); | |
648 | item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol); | |
649 | item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType); | |
650 | ||
651 | if (path && pathLength) | |
652 | item->setAttribute(Schema::attributeInfo(kSecPathItemAttr), | |
653 | CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength)); | |
654 | ||
655 | Keychain keychain = nil; | |
656 | try | |
657 | { | |
658 | keychain = Keychain::optional(keychainRef); | |
659 | if ( !keychain->exists() ) | |
660 | { | |
661 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
662 | } | |
663 | } | |
664 | catch(...) | |
665 | { | |
666 | keychain = globals().storageManager.defaultKeychainUI(item); | |
667 | } | |
668 | ||
669 | keychain->add(item); | |
670 | ||
671 | if (itemRef) | |
672 | *itemRef = item->handle(); | |
673 | ||
674 | END_SECAPI | |
675 | } | |
676 | ||
677 | ||
678 | OSStatus | |
679 | SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) | |
680 | ||
681 | { | |
682 | BEGIN_SECAPI | |
d64be36e A |
683 | |
684 | os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
685 | os_activity_scope(activity); |
686 | os_release(activity); | |
b1ab9ed8 A |
687 | |
688 | StorageManager::KeychainList keychains; | |
689 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
690 | KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL); | |
691 | ||
692 | if (serverName && serverNameLength) | |
693 | { | |
694 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr), | |
695 | CssmData(const_cast<char *>(serverName), serverNameLength)); | |
696 | } | |
697 | ||
698 | if (securityDomain && securityDomainLength) | |
699 | { | |
700 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr), | |
701 | CssmData (const_cast<char*>(securityDomain), securityDomainLength)); | |
702 | } | |
703 | ||
704 | if (accountName && accountNameLength) | |
705 | { | |
706 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), | |
707 | CssmData (const_cast<char*>(accountName), accountNameLength)); | |
708 | } | |
709 | ||
710 | if (port) | |
711 | { | |
712 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr), | |
713 | UInt32(port)); | |
714 | } | |
715 | ||
716 | if (protocol) | |
717 | { | |
718 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr), | |
719 | protocol); | |
720 | } | |
721 | ||
722 | if (authenticationType) | |
723 | { | |
724 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr), | |
725 | authenticationType); | |
726 | } | |
727 | ||
728 | if (path && pathLength) | |
729 | { | |
730 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path); | |
731 | } | |
732 | ||
733 | Item item; | |
734 | if (!cursor->next(item)) | |
735 | return errSecItemNotFound; | |
736 | ||
737 | // Get its data (only if necessary) | |
738 | if (passwordData || passwordLength) | |
739 | { | |
740 | CssmDataContainer outData; | |
741 | item->getData(outData); | |
fa7225c8 A |
742 | if (passwordLength) { |
743 | *passwordLength=(UInt32)outData.length(); | |
744 | } | |
b1ab9ed8 | 745 | outData.Length=0; |
fa7225c8 A |
746 | if (passwordData) { |
747 | *passwordData=outData.data(); | |
748 | } | |
b1ab9ed8 A |
749 | outData.Data=NULL; |
750 | } | |
751 | ||
752 | if (itemRef) | |
753 | *itemRef=item->handle(); | |
754 | ||
755 | END_SECAPI | |
756 | } | |
757 | ||
758 | ||
759 | OSStatus | |
760 | SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) | |
761 | { | |
762 | BEGIN_SECAPI | |
d64be36e A |
763 | |
764 | os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
765 | os_activity_scope(activity); |
766 | os_release(activity); | |
b1ab9ed8 A |
767 | |
768 | KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); | |
769 | // @@@ Get real itemClass | |
770 | ||
771 | Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false); | |
772 | ||
773 | if (serviceName && serviceNameLength) | |
774 | { | |
775 | CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength); | |
776 | item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); | |
866f8763 | 777 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); |
b1ab9ed8 A |
778 | } |
779 | ||
780 | if (accountName && accountNameLength) | |
781 | { | |
782 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
783 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
784 | } | |
785 | ||
786 | Keychain keychain = nil; | |
787 | try | |
788 | { | |
789 | keychain = Keychain::optional(keychainRef); | |
790 | if ( !keychain->exists() ) | |
791 | { | |
792 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
793 | } | |
794 | } | |
795 | catch(...) | |
796 | { | |
797 | keychain = globals().storageManager.defaultKeychainUI(item); | |
798 | } | |
799 | ||
800 | keychain->add(item); | |
801 | if (itemRef) | |
802 | *itemRef = item->handle(); | |
803 | ||
804 | END_SECAPI | |
805 | } | |
806 | ||
807 | ||
808 | OSStatus | |
809 | SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) | |
810 | ||
811 | { | |
812 | BEGIN_SECAPI | |
d64be36e A |
813 | |
814 | os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
815 | os_activity_scope(activity); |
816 | os_release(activity); | |
b1ab9ed8 A |
817 | |
818 | StorageManager::KeychainList keychains; | |
819 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
820 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
821 | ||
822 | if (serviceName && serviceNameLength) | |
823 | { | |
824 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), | |
825 | CssmData(const_cast<char *>(serviceName), serviceNameLength)); | |
826 | } | |
827 | ||
828 | if (accountName && accountNameLength) | |
829 | { | |
830 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), | |
831 | CssmData(const_cast<char *>(accountName), accountNameLength)); | |
832 | } | |
833 | ||
834 | Item item; | |
835 | if (!cursor->next(item)) | |
836 | return errSecItemNotFound; | |
837 | ||
838 | // Get its data (only if necessary) | |
839 | if (passwordData || passwordLength) | |
840 | { | |
841 | CssmDataContainer outData; | |
842 | item->getData(outData); | |
fa7225c8 A |
843 | if (passwordLength) { |
844 | *passwordLength=(UInt32)outData.length(); | |
845 | } | |
b1ab9ed8 | 846 | outData.Length=0; |
fa7225c8 A |
847 | if (passwordData) { |
848 | *passwordData=outData.data(); | |
849 | } | |
b1ab9ed8 A |
850 | outData.Data=NULL; |
851 | } | |
852 | ||
853 | if (itemRef) | |
854 | *itemRef=item->handle(); | |
855 | ||
856 | END_SECAPI | |
857 | } | |
858 | ||
859 | ||
860 | OSStatus | |
861 | SecKeychainSetUserInteractionAllowed(Boolean state) | |
862 | { | |
863 | BEGIN_SECAPI | |
864 | ||
865 | globals().setUserInteractionAllowed(state); | |
866 | ||
867 | END_SECAPI | |
868 | } | |
869 | ||
870 | ||
871 | OSStatus | |
872 | SecKeychainGetUserInteractionAllowed(Boolean *state) | |
873 | { | |
874 | BEGIN_SECAPI | |
875 | ||
876 | Required(state)=globals().getUserInteractionAllowed(); | |
877 | ||
878 | END_SECAPI | |
879 | } | |
880 | ||
881 | ||
882 | OSStatus | |
883 | SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle) | |
884 | { | |
885 | BEGIN_SECAPI | |
d64be36e A |
886 | |
887 | os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
888 | os_activity_scope(activity); |
889 | os_release(activity); | |
b1ab9ed8 A |
890 | |
891 | RequiredParam(dldbHandle); | |
892 | ||
893 | Keychain keychain = Keychain::optional(keychainRef); | |
894 | *dldbHandle = keychain->database()->handle(); | |
895 | ||
896 | END_SECAPI | |
897 | } | |
898 | ||
79b9da22 A |
899 | static ModuleNexus<Mutex> gSecReturnedKeychainCSPsMutex; |
900 | static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeychainCSPs; | |
b1ab9ed8 A |
901 | |
902 | OSStatus | |
903 | SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) | |
904 | { | |
905 | BEGIN_SECAPI | |
906 | ||
907 | RequiredParam(cspHandle); | |
908 | ||
909 | Keychain keychain = Keychain::optional(keychainRef); | |
866f8763 A |
910 | |
911 | // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). | |
912 | // Keep a global pointer to it to force the CSP to stay live forever. | |
913 | CssmClient::CSP returnedKeychainCSP = keychain->csp(); | |
914 | { | |
79b9da22 A |
915 | StLock<Mutex> _(gSecReturnedKeychainCSPsMutex()); |
916 | gSecReturnedKeychainCSPs().insert(returnedKeychainCSP); | |
866f8763 A |
917 | } |
918 | *cspHandle = returnedKeychainCSP->handle(); | |
b1ab9ed8 A |
919 | |
920 | END_SECAPI | |
921 | } | |
922 | ||
923 | ||
924 | OSStatus | |
925 | SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef) | |
926 | { | |
927 | BEGIN_SECAPI | |
928 | ||
427c49bc | 929 | MacOSError::throwMe(errSecUnimplemented);//%%%for now |
b1ab9ed8 A |
930 | |
931 | END_SECAPI | |
932 | } | |
933 | ||
934 | ||
935 | OSStatus | |
936 | SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef) | |
937 | { | |
938 | BEGIN_SECAPI | |
939 | ||
427c49bc | 940 | MacOSError::throwMe(errSecUnimplemented);//%%%for now |
b1ab9ed8 A |
941 | |
942 | END_SECAPI | |
943 | } | |
944 | ||
945 | ||
946 | #pragma mark ---- Private API ---- | |
947 | ||
948 | ||
949 | OSStatus | |
950 | SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword) | |
951 | { | |
952 | BEGIN_SECAPI | |
d64be36e A |
953 | |
954 | os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
955 | os_activity_scope(activity); |
956 | os_release(activity); | |
b1ab9ed8 A |
957 | |
958 | Keychain keychain = Keychain::optional(keychainRef); | |
959 | keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword); | |
960 | ||
961 | END_SECAPI | |
962 | } | |
963 | ||
964 | ||
965 | OSStatus | |
966 | SecKeychainCopyLogin(SecKeychainRef *keychainRef) | |
967 | { | |
968 | BEGIN_SECAPI | |
d64be36e A |
969 | |
970 | os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
971 | os_activity_scope(activity); |
972 | os_release(activity); | |
b1ab9ed8 A |
973 | |
974 | RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle(); | |
975 | ||
976 | END_SECAPI | |
977 | } | |
978 | ||
979 | ||
980 | OSStatus | |
981 | SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password) | |
982 | { | |
983 | BEGIN_SECAPI | |
d64be36e A |
984 | |
985 | os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
986 | os_activity_scope(activity); |
987 | os_release(activity); | |
b1ab9ed8 A |
988 | |
989 | try | |
990 | { | |
427c49bc | 991 | if (password) { |
fa7225c8 | 992 | globals().storageManager.login(nameLength, name, passwordLength, password, false); |
427c49bc A |
993 | } else { |
994 | globals().storageManager.stashLogin(); | |
995 | } | |
b1ab9ed8 A |
996 | } |
997 | catch (CommonError &e) | |
998 | { | |
b04fe171 | 999 | secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not"); |
b1ab9ed8 A |
1000 | if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) |
1001 | { | |
1002 | return errSecAuthFailed; | |
1003 | } | |
1004 | else | |
1005 | { | |
1006 | return e.osStatus(); | |
1007 | } | |
1008 | } | |
b04fe171 A |
1009 | |
1010 | catch (...) { | |
1011 | __secapiresult=errSecInternalComponent; | |
1012 | } | |
1013 | secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not"); | |
1014 | ||
b1ab9ed8 A |
1015 | END_SECAPI |
1016 | } | |
1017 | ||
427c49bc A |
1018 | OSStatus SecKeychainStash() |
1019 | { | |
1020 | BEGIN_SECAPI | |
d64be36e A |
1021 | |
1022 | os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1023 | os_activity_scope(activity); |
1024 | os_release(activity); | |
427c49bc A |
1025 | |
1026 | try | |
1027 | { | |
1028 | globals().storageManager.stashKeychain(); | |
1029 | } | |
1030 | catch (CommonError &e) | |
1031 | { | |
1032 | if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) | |
1033 | { | |
1034 | return errSecAuthFailed; | |
1035 | } | |
1036 | else | |
1037 | { | |
1038 | return e.osStatus(); | |
1039 | } | |
1040 | } | |
1041 | ||
1042 | END_SECAPI | |
1043 | } | |
b1ab9ed8 A |
1044 | |
1045 | OSStatus | |
1046 | SecKeychainLogout() | |
1047 | { | |
1048 | BEGIN_SECAPI | |
d64be36e A |
1049 | |
1050 | os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1051 | os_activity_scope(activity); |
1052 | os_release(activity); | |
b1ab9ed8 A |
1053 | |
1054 | globals().storageManager.logout(); | |
1055 | ||
1056 | END_SECAPI | |
1057 | } | |
1058 | ||
1059 | /* (non-exported C utility routine) 'Makes' a keychain based on a full path | |
1060 | */ | |
1061 | static Keychain make(const char *name) | |
1062 | { | |
1063 | return globals().storageManager.make(name); | |
1064 | } | |
1065 | ||
1066 | /* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs. | |
1067 | Note this version doesn't take an accessRef or password. | |
1068 | The "KC" create API takes a keychainRef... | |
1069 | */ | |
1070 | OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef) | |
1071 | { | |
1072 | BEGIN_SECAPI | |
d64be36e A |
1073 | |
1074 | RequiredParam(fullPathName); | |
b1ab9ed8 A |
1075 | RequiredParam(keychainRef)=make(fullPathName)->handle(); |
1076 | END_SECAPI | |
1077 | } | |
1078 | ||
1079 | ||
1080 | /* Determines if the keychainRef is a valid keychain. | |
1081 | */ | |
1082 | OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid) | |
1083 | { | |
1084 | BEGIN_SECAPI | |
d64be36e A |
1085 | |
1086 | *isValid = false; | |
b1ab9ed8 A |
1087 | if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL) |
1088 | *isValid = true; | |
1089 | END_SECAPI | |
1090 | } | |
1091 | ||
1092 | /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs. | |
1093 | */ | |
1094 | OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef) | |
1095 | { | |
1096 | BEGIN_SECAPI | |
d64be36e A |
1097 | |
1098 | os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1099 | os_activity_scope(activity); |
1100 | os_release(activity); | |
b1ab9ed8 A |
1101 | StorageManager::KeychainList singleton; |
1102 | singleton.push_back(KeychainImpl::required(keychainRef)); | |
1103 | globals().storageManager.remove(singleton); | |
1104 | END_SECAPI | |
1105 | } | |
1106 | ||
1107 | /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs. | |
1108 | */ | |
1109 | OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword) | |
1110 | { | |
1111 | BEGIN_SECAPI | |
d64be36e A |
1112 | |
1113 | os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1114 | os_activity_scope(activity); |
1115 | os_release(activity); | |
b1ab9ed8 A |
1116 | RequiredParam(inPassword); |
1117 | KeychainImpl::required(keychainRef)->create(passwordLength, inPassword); | |
1118 | END_SECAPI | |
1119 | } | |
1120 | ||
1121 | /* Modify a keychain so that it can be synchronized. | |
1122 | */ | |
1123 | OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData) | |
1124 | { | |
1125 | BEGIN_SECAPI | |
d64be36e A |
1126 | |
1127 | os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1128 | os_activity_scope(activity); |
1129 | os_release(activity); | |
b1ab9ed8 A |
1130 | |
1131 | // do error checking for required parameters | |
1132 | RequiredParam(dbBlobArray); | |
1133 | RequiredParam(extraData); | |
1134 | ||
1135 | const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)), | |
1136 | CFDataGetLength(extraData)); | |
1137 | ||
1138 | CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray); | |
1139 | size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle)); | |
1140 | void *dataPtr = (void*)malloc(space); | |
1141 | if ( !dataPtr ) | |
427c49bc | 1142 | return errSecAllocate; |
b1ab9ed8 A |
1143 | // |
1144 | // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with. | |
1145 | // | |
1146 | uint8* sizePtr = (uint8*)dataPtr; | |
1147 | *sizePtr = dbBlobArrayCount; | |
1148 | SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); | |
1149 | CFIndex index; | |
1150 | SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard()); | |
1151 | for (index=0; index < dbBlobArrayCount; index++) | |
1152 | { | |
1153 | CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index); | |
1154 | const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData)); | |
1155 | // | |
1156 | // Since it's to a DbHandle that's not on our disk (it came from user's iDisk), | |
1157 | // it's OK to use the mIdentifier and access credentials of the keychain we're recoding. | |
1158 | // | |
1159 | Keychain kc = KeychainImpl::required(keychainRef); | |
1160 | *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */ | |
1161 | ||
1162 | currDbHandle++; | |
1163 | } | |
1164 | // do the work | |
1165 | Keychain keychain = Keychain::optional(keychainRef); | |
1166 | const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space); | |
1167 | Boolean recodeFailed = false; | |
1168 | ||
427c49bc | 1169 | int errCode=errSecSuccess; |
b1ab9ed8 A |
1170 | |
1171 | try | |
1172 | { | |
1173 | keychain->recode(data, extraCssmData); | |
1174 | } | |
1175 | catch (MacOSError e) | |
1176 | { | |
1177 | errCode = e.osStatus(); | |
1178 | recodeFailed = true; | |
1179 | } | |
1180 | catch (UnixError ue) | |
1181 | { | |
1182 | errCode = ue.unixError(); | |
1183 | } | |
1184 | ||
1185 | currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); | |
1186 | for (index=0; index < dbBlobArrayCount; index++) | |
1187 | { | |
1188 | ss.releaseDb(*currDbHandle); | |
1189 | currDbHandle++; | |
1190 | } | |
1191 | if ( dataPtr ) | |
1192 | free(dataPtr); | |
1193 | ||
1194 | if ( recodeFailed ) | |
1195 | { | |
1196 | return errCode; | |
1197 | } | |
1198 | ||
1199 | END_SECAPI | |
1200 | } | |
1201 | ||
1202 | OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) | |
1203 | { | |
1204 | BEGIN_SECAPI | |
d64be36e A |
1205 | |
1206 | os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1207 | os_activity_scope(activity); |
1208 | os_release(activity); | |
b1ab9ed8 A |
1209 | |
1210 | // do error checking for required parameters | |
1211 | RequiredParam(keychainSignature); | |
1212 | ||
1213 | // make a keychain object "wrapper" for this keychain ref | |
1214 | Keychain keychain = Keychain::optional(keychainRef); | |
1215 | CssmAutoData data(keychain->database()->allocator()); | |
1216 | keychain->copyBlob(data.get()); | |
1217 | ||
1218 | // get the cssmDBBlob | |
1219 | const SecurityServer::DbBlob *cssmDBBlob = | |
1220 | data.get().interpretedAs<const SecurityServer::DbBlob>(); | |
1221 | ||
1222 | // convert from CDSA standards to CF standards | |
1223 | *keychainSignature = CFDataCreate(kCFAllocatorDefault, | |
1224 | cssmDBBlob->randomSignature.bytes, | |
1225 | sizeof(SecurityServer::DbBlob::Signature)); | |
1226 | ||
1227 | END_SECAPI | |
1228 | } | |
1229 | ||
1230 | OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob) | |
1231 | { | |
1232 | BEGIN_SECAPI | |
d64be36e A |
1233 | |
1234 | os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1235 | os_activity_scope(activity); |
1236 | os_release(activity); | |
b1ab9ed8 A |
1237 | |
1238 | // do error checking for required parameters | |
1239 | RequiredParam(dbBlob); | |
1240 | ||
1241 | // make a keychain object "wrapper" for this keychain ref | |
1242 | Keychain keychain = Keychain::optional(keychainRef); | |
1243 | CssmAutoData data(keychain->database()->allocator()); | |
1244 | keychain->copyBlob(data.get()); | |
1245 | ||
1246 | // convert from CDSA standards to CF standards | |
1247 | *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length()); | |
1248 | ||
1249 | END_SECAPI | |
1250 | } | |
1251 | ||
1252 | // make a new keychain with pre-existing secrets | |
1253 | OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef) | |
1254 | { | |
1255 | BEGIN_SECAPI | |
d64be36e A |
1256 | |
1257 | os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1258 | os_activity_scope(activity); |
1259 | os_release(activity); | |
b1ab9ed8 A |
1260 | |
1261 | KCThrowParamErrIf_(!fullPathName); | |
1262 | KCThrowParamErrIf_(!dbBlob); | |
1263 | ||
1264 | Keychain keychain = globals().storageManager.make(fullPathName); | |
1265 | ||
1266 | CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob)); | |
1267 | ||
1268 | // @@@ the call to StorageManager::make above leaves keychain the the cache. | |
1269 | // If the create below fails we should probably remove it. | |
1270 | keychain->createWithBlob(blob); | |
1271 | ||
1272 | RequiredParam(kcRef)=keychain->handle(); | |
1273 | ||
1274 | // | |
1275 | ||
1276 | END_SECAPI | |
1277 | } | |
1278 | ||
1279 | // add a non-file based DB to the keychain list | |
1280 | OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1281 | const CSSM_GUID *guid, uint32 subServiceType) | |
1282 | { | |
1283 | BEGIN_SECAPI | |
d64be36e A |
1284 | |
1285 | os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1286 | os_activity_scope(activity); |
1287 | os_release(activity); | |
b1ab9ed8 A |
1288 | |
1289 | RequiredParam(dbName); | |
1290 | StorageManager &smr = globals().storageManager; | |
1291 | smr.addToDomainList(domain, dbName, *guid, subServiceType); | |
1292 | ||
1293 | END_SECAPI | |
1294 | } | |
1295 | ||
1296 | // determine if a non-file based DB is in the keychain list | |
1297 | OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1298 | const CSSM_GUID *guid, uint32 subServiceType) | |
1299 | { | |
1300 | BEGIN_SECAPI | |
d64be36e A |
1301 | |
1302 | RequiredParam(dbName); | |
b1ab9ed8 A |
1303 | StorageManager &smr = globals().storageManager; |
1304 | smr.isInDomainList(domain, dbName, *guid, subServiceType); | |
1305 | END_SECAPI | |
1306 | } | |
1307 | ||
1308 | // remove a non-file based DB from the keychain list | |
1309 | OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1310 | const CSSM_GUID *guid, uint32 subServiceType) | |
1311 | { | |
1312 | BEGIN_SECAPI | |
d64be36e A |
1313 | |
1314 | os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1315 | os_activity_scope(activity); |
1316 | os_release(activity); | |
b1ab9ed8 A |
1317 | RequiredParam(dbName); |
1318 | StorageManager &smr = globals().storageManager; | |
1319 | smr.removeFromDomainList(domain, dbName, *guid, subServiceType); | |
1320 | END_SECAPI | |
1321 | } | |
1322 | ||
1323 | ||
1324 | // set server mode -- must be called before any other Sec* etc. call | |
1325 | void SecKeychainSetServerMode() | |
1326 | { | |
1327 | gServerMode = true; | |
1328 | } | |
1329 | ||
1330 | ||
1331 | ||
1332 | OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback) | |
1333 | { | |
1334 | BEGIN_SECAPI | |
d64be36e A |
1335 | |
1336 | os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1337 | os_activity_scope(activity); |
1338 | os_release(activity); | |
b1ab9ed8 A |
1339 | RequiredParam(kcRef); |
1340 | Keychain keychain = Keychain::optional(kcRef); | |
1341 | keychain->setBatchMode(mode, rollback); | |
1342 | END_SECAPI | |
1343 | } | |
1344 | ||
1345 | ||
1346 | ||
1347 | OSStatus SecKeychainCleanupHandles() | |
1348 | { | |
1349 | BEGIN_SECAPI | |
d64be36e A |
1350 | |
1351 | END_SECAPI // which causes the handle cache cleanup routine to run | |
b1ab9ed8 A |
1352 | } |
1353 | ||
427c49bc A |
1354 | OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries) |
1355 | { | |
1356 | BEGIN_SECAPI | |
d64be36e A |
1357 | |
1358 | os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1359 | os_activity_scope(activity); |
1360 | os_release(activity); | |
427c49bc A |
1361 | SecurityServer::ClientSession().verifyKeyStorePassphrase(retries); |
1362 | END_SECAPI | |
1363 | } | |
1364 | ||
1365 | OSStatus SecKeychainChangeKeyStorePassphrase() | |
1366 | { | |
1367 | BEGIN_SECAPI | |
d64be36e A |
1368 | |
1369 | os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1370 | os_activity_scope(activity); |
1371 | os_release(activity); | |
427c49bc A |
1372 | SecurityServer::ClientSession().changeKeyStorePassphrase(); |
1373 | END_SECAPI | |
d8f41ccd A |
1374 | } |
1375 | ||
1376 | static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password) | |
1377 | { | |
1378 | BEGIN_SECAPI | |
d64be36e A |
1379 | |
1380 | os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
866f8763 A |
1381 | os_activity_scope(activity); |
1382 | os_release(activity); | |
d8f41ccd A |
1383 | |
1384 | // make a keychain object "wrapper" for this keychain ref | |
1385 | Keychain keychain = Keychain::optional(userKeychainRef); | |
1386 | ||
1387 | CssmClient::Db db = keychain->database(); | |
1388 | ||
1389 | // create the keychain, using appropriate credentials | |
1390 | Allocator &alloc = db->allocator(); | |
1391 | AutoCredentials cred(alloc); // will leak, but we're quitting soon :-) | |
1392 | ||
1393 | char passphrase[1024]; | |
1394 | CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8); | |
1395 | ||
1396 | // use this passphrase | |
1397 | cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, | |
1398 | new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD), | |
1399 | new(alloc) ListElement(StringData(passphrase))); | |
fa7225c8 A |
1400 | db->authenticate(CSSM_DB_ACCESS_READ, &cred); |
1401 | ||
1402 | CSSM_DL_DB_HANDLE dlDb = db->handle(); | |
d8f41ccd A |
1403 | CssmData dlDbData = CssmData::wrap(dlDb); |
1404 | CssmKey refKey; | |
1405 | KeySpec spec(CSSM_KEYUSE_ANY, | |
1406 | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE); | |
1407 | ||
1408 | DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64); | |
1409 | derive(&dlDbData, spec, refKey); | |
1410 | ||
1411 | // now extract the raw keybits | |
1412 | CssmKey rawKey; | |
1413 | WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE); | |
1414 | wrap(refKey, rawKey); | |
1415 | ||
1416 | *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length()); | |
1417 | ||
1418 | END_SECAPI | |
1419 | } | |
1420 | ||
fa7225c8 A |
1421 | static const char *kAutologinPWFilePath = "/etc/kcpassword"; |
1422 | static const uint32_t kObfuscatedPasswordSizeMultiple = 12; | |
1423 | static const uint32_t buffer_size = 512; | |
1424 | static const uint8_t kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f}; | |
1425 | ||
1426 | static void obfuscate(void *buffer, size_t bufferLength) | |
1427 | { | |
1428 | uint8_t *pBuf = (uint8_t *) buffer; | |
1429 | const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey ); | |
1430 | ||
1431 | while (bufferLength--) { | |
1432 | *pBuf = *pBuf ^ *pKey; | |
1433 | ++pKey; | |
1434 | ++pBuf; | |
1435 | if (pKey == eKey) | |
1436 | pKey = kObfuscationKey; | |
1437 | } | |
1438 | } | |
1439 | ||
1440 | static bool _SASetAutologinPW(CFStringRef inAutologinPW) | |
1441 | { | |
1442 | bool result = false; | |
1443 | struct stat sb; | |
1444 | ||
1445 | // Delete the kcpassword file if it exists already | |
1446 | if (stat(kAutologinPWFilePath, &sb) == 0) | |
1447 | unlink( kAutologinPWFilePath ); | |
1448 | ||
1449 | // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off. | |
1450 | if (inAutologinPW != NULL) { | |
1451 | char buffer[buffer_size]; | |
1452 | const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8); | |
1453 | if (pwAsUTF8String == NULL) { | |
1454 | if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer; | |
1455 | } | |
1456 | ||
1457 | if (pwAsUTF8String != NULL) { | |
1458 | size_t pwLength = strlen(pwAsUTF8String) + 1; | |
1459 | size_t obfuscatedPWLength; | |
1460 | char *obfuscatedPWBuffer; | |
1461 | ||
1462 | // The size of the obfuscated password should be the smallest multiple of | |
1463 | // kObfuscatedPasswordSizeMultiple greater than or equal to pwLength. | |
1464 | obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple; | |
1465 | obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength); | |
1466 | ||
1467 | // Copy the password (including null terminator) to beginning of obfuscatedPWBuffer | |
1468 | bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength); | |
1469 | ||
1470 | // Pad remainder of obfuscatedPWBuffer with random bytes | |
1471 | { | |
1472 | char *p; | |
1473 | char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength; | |
1474 | ||
1475 | for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p) | |
1476 | *p = random() & 0x000000FF; | |
1477 | } | |
1478 | ||
1479 | obfuscate(obfuscatedPWBuffer, obfuscatedPWLength); | |
1480 | ||
1481 | int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR); | |
1482 | if (pwFile >= 0) { | |
1483 | size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength); | |
1484 | if (wrote == obfuscatedPWLength) | |
1485 | result = true; | |
1486 | close(pwFile); | |
1487 | } | |
1488 | ||
1489 | chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR); | |
1490 | free(obfuscatedPWBuffer); | |
1491 | } | |
1492 | } | |
1493 | ||
1494 | return result; | |
1495 | } | |
d8f41ccd A |
1496 | |
1497 | OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) { | |
d64be36e | 1498 | COUNTLEGACYAPI |
d8f41ccd A |
1499 | SecTrustedApplicationRef itemPath; |
1500 | SecAccessRef ourAccessRef = NULL; | |
1501 | ||
1502 | OSStatus result = errSecParam; | |
1503 | ||
fa7225c8 A |
1504 | if (userKeychainRef == NULL) { |
1505 | // We don't have a specific user keychain, fall back | |
1506 | if (_SASetAutologinPW(password)) | |
1507 | result = errSecSuccess; | |
1508 | ||
1509 | return result; | |
1510 | } | |
1511 | ||
d8f41ccd A |
1512 | CFDataRef masterKey = NULL; |
1513 | result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password); | |
1514 | if (errSecSuccess != result) { | |
1515 | return result; | |
1516 | } | |
1517 | ||
1518 | result = SecKeychainStash(); | |
1519 | if (errSecSuccess != result) { | |
fa7225c8 | 1520 | if (masterKey != NULL) CFRelease(masterKey); |
d8f41ccd A |
1521 | return result; |
1522 | } | |
1523 | ||
1524 | CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
fa7225c8 | 1525 | if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath) |
d8f41ccd A |
1526 | CFArrayAppendValue(trustedApplications, itemPath); |
1527 | ||
fa7225c8 | 1528 | if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) { |
d8f41ccd | 1529 | if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) { |
fa7225c8 | 1530 | SecKeychainRef internalSystemKeychainRef = NULL; |
d8f41ccd | 1531 | if (NULL == systemKeychainRef) { |
fa7225c8 A |
1532 | SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef); |
1533 | } else { | |
1534 | internalSystemKeychainRef = systemKeychainRef; | |
d8f41ccd A |
1535 | } |
1536 | ||
1537 | const void *queryKeys[] = { kSecClass, | |
1538 | kSecAttrService, | |
1539 | kSecAttrAccount, | |
1540 | kSecUseKeychain, | |
1541 | }; | |
1542 | const void *queryValues[] = { kSecClassGenericPassword, | |
1543 | CFSTR("com.apple.loginwindow.auto-login"), | |
1544 | username, | |
fa7225c8 | 1545 | internalSystemKeychainRef, |
d8f41ccd A |
1546 | }; |
1547 | ||
1548 | const void *updateKeys[] = { kSecAttrAccess, | |
1549 | kSecValueData, | |
1550 | }; | |
1551 | const void *updateValues[] = { ourAccessRef, | |
1552 | masterKey, | |
1553 | }; | |
1554 | ||
1555 | CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1556 | CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1557 | ||
1558 | result = SecItemUpdate(query, update); | |
1559 | ||
1560 | if (errSecSuccess != result) { | |
1561 | const void *addKeys[] = { kSecClass, | |
1562 | kSecAttrService, | |
1563 | kSecAttrAccount, | |
1564 | kSecUseKeychain, | |
1565 | kSecAttrAccess, | |
1566 | kSecValueData, | |
1567 | }; | |
1568 | const void *addValues[] = { kSecClassGenericPassword, | |
1569 | CFSTR("com.apple.loginwindow.auto-login"), | |
1570 | username, | |
fa7225c8 | 1571 | internalSystemKeychainRef, |
d8f41ccd A |
1572 | ourAccessRef, |
1573 | masterKey, | |
1574 | }; | |
1575 | ||
1576 | CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1577 | result = SecItemAdd(add, NULL); | |
1578 | if (NULL != add) CFRelease(add); | |
1579 | } | |
1580 | ||
1581 | if (NULL != query) CFRelease(query); | |
1582 | if (NULL != update) CFRelease(update); | |
fa7225c8 A |
1583 | |
1584 | // If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one | |
1585 | if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef); | |
d8f41ccd A |
1586 | } |
1587 | } | |
1588 | ||
1589 | if (NULL != masterKey) CFRelease(masterKey); | |
1590 | if (NULL != trustedApplications) CFRelease(trustedApplications); | |
1591 | if (NULL != ourAccessRef) CFRelease(ourAccessRef); | |
d8f41ccd A |
1592 | |
1593 | return result; | |
1594 | } | |
fa7225c8 A |
1595 | |
1596 | OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts) | |
1597 | { | |
1598 | BEGIN_SECAPI | |
d64be36e | 1599 | |
866f8763 A |
1600 | os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1601 | os_activity_scope(activity); | |
1602 | os_release(activity); | |
fa7225c8 A |
1603 | |
1604 | if(attempts) { | |
1605 | SecurityServer::ClientSession().getUserPromptAttempts(*attempts); | |
1606 | } | |
1607 | ||
1608 | END_SECAPI | |
1609 | } | |
1610 | ||
1611 | OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash, | |
1612 | SecKeychainRef userKeychain, CFStringRef password) | |
1613 | { | |
d64be36e | 1614 | COUNTLEGACYAPI |
fa7225c8 A |
1615 | CFRef<CFStringRef> pwd; |
1616 | OSStatus result; | |
1617 | ||
1618 | if (password == NULL || CFStringGetLength(password) == 0) { | |
1619 | AuthorizationRef authorizationRef; | |
1620 | result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef); | |
1621 | if (result != errAuthorizationSuccess) { | |
b04fe171 | 1622 | secnotice("SecKeychain", "failed to create authorization"); |
fa7225c8 A |
1623 | return result; |
1624 | } | |
1625 | ||
1626 | AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0}; | |
1627 | AuthorizationRights myRights = {1, &myItems}; | |
fa7225c8 A |
1628 | |
1629 | char pathName[PATH_MAX]; | |
1630 | UInt32 pathLength = PATH_MAX; | |
1631 | result = SecKeychainGetPath(userKeychain, &pathLength, pathName); | |
1632 | if (result != errSecSuccess) { | |
b04fe171 | 1633 | secnotice("SecKeychain", "failed to create authorization"); |
fa7225c8 A |
1634 | return result; |
1635 | } | |
1636 | ||
1637 | Boolean checkPwd = TRUE; | |
b04fe171 | 1638 | Boolean ignoreSession = TRUE; |
fa7225c8 A |
1639 | AuthorizationItem envItems[] = { |
1640 | {AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0}, | |
b04fe171 A |
1641 | {AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd}, |
1642 | {AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession} | |
fa7225c8 A |
1643 | }; |
1644 | ||
b04fe171 | 1645 | AuthorizationEnvironment environment = {3, envItems}; |
fa7225c8 | 1646 | AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; |
b54c578e A |
1647 | result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, NULL); |
1648 | secnotice("SecKeychain", "Authorization result: %d", (int)result); | |
fa7225c8 A |
1649 | |
1650 | if (result == errAuthorizationSuccess) { | |
1651 | AuthorizationItemSet *items; | |
1652 | result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items); | |
b54c578e | 1653 | secnotice("SecKeychain", "Items copy result: %d", (int)result); |
fa7225c8 | 1654 | if (result == errAuthorizationSuccess) { |
b54c578e | 1655 | secnotice("SecKeychain", "Items count: %d", items->count); |
fa7225c8 A |
1656 | if (items->count > 0) { |
1657 | pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8); | |
b54c578e A |
1658 | if (pwd) { |
1659 | secnotice("SecKeychain", "Got kcpass"); | |
1660 | } | |
fa7225c8 A |
1661 | } |
1662 | AuthorizationFreeItemSet(items); | |
1663 | } | |
1664 | } | |
1665 | AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); | |
1666 | if (result != errAuthorizationSuccess) { | |
b04fe171 | 1667 | secnotice("SecKeychain", "did not get authorization to pair the card"); |
fa7225c8 A |
1668 | return result; |
1669 | } | |
1670 | } else { | |
1671 | pwd.take(password); | |
1672 | } | |
1673 | ||
1674 | if (!pwd) { | |
b04fe171 | 1675 | secnotice("SecKeychain", "did not get kcpass"); |
fa7225c8 A |
1676 | return errSecInternalComponent; |
1677 | } | |
1678 | ||
1679 | CFRef<CFDataRef> masterKey; | |
1680 | result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd); | |
1681 | if (result != errSecSuccess) { | |
1682 | secnotice("SecKeychain", "Failed to get master key: %d", (int) result); | |
1683 | return result; | |
1684 | } | |
1685 | ||
1686 | CFRef<CFDataRef> scBlob; | |
1687 | result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take()); | |
1688 | if (result != errSecSuccess) { | |
1689 | secnotice("SecKeychain", "Failed to get stash: %d", (int) result); | |
1690 | return result; | |
1691 | } | |
1692 | ||
1693 | result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob); | |
1694 | if (result != errSecSuccess) { | |
1695 | secnotice("SecKeychain", "Failed to create login data: %d", (int) result); | |
1696 | return result; | |
1697 | } | |
1698 | ||
1699 | secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result); | |
d64be36e A |
1700 | |
1701 | // create SC KEK | |
1702 | // this might fail if KC password is different from user's password | |
1703 | uid_t uid = geteuid(); | |
1704 | if (!uid) { | |
1705 | uid = getuid(); | |
1706 | } | |
1707 | struct passwd *passwd = getpwuid(uid); | |
1708 | if (passwd) { | |
1709 | CFRef<CFStringRef> username = CFStringCreateWithCString(kCFAllocatorDefault, passwd->pw_name, kCFStringEncodingUTF8); | |
1710 | OSStatus kekRes = TKAddSecureToken(username, pwd, tokenID, wrapPubKeyHash); | |
1711 | if (kekRes != noErr) { | |
1712 | secnotice("SecKeychain", "Failed to register SC token: %d", (int) kekRes); // do not fail because KC functionality be still OK | |
1713 | } | |
1714 | } else { | |
1715 | secnotice("SecKeychain", "Unable to get name for uid %d", uid); | |
1716 | } | |
fa7225c8 A |
1717 | return result; |
1718 | } | |
1719 | ||
1720 | OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash) | |
1721 | { | |
d64be36e | 1722 | COUNTLEGACYAPI |
fa7225c8 A |
1723 | OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash); |
1724 | if (result != errSecSuccess) { | |
1725 | secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result); | |
1726 | } | |
1727 | return result; | |
1728 | } |