]>
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 A |
37 | #include <pwd.h> |
38 | ||
d8f41ccd A |
39 | OSStatus |
40 | SecKeychainMDSInstall() | |
41 | { | |
42 | BEGIN_SECAPI | |
43 | ||
44 | Security::MDSClient::Directory d; | |
45 | d.install(); | |
46 | ||
47 | END_SECAPI | |
48 | } | |
49 | ||
b1ab9ed8 A |
50 | CFTypeID |
51 | SecKeychainGetTypeID(void) | |
52 | { | |
53 | BEGIN_SECAPI | |
54 | ||
55 | return gTypes().KeychainImpl.typeID; | |
56 | ||
57 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
58 | } | |
59 | ||
60 | ||
61 | OSStatus | |
62 | SecKeychainGetVersion(UInt32 *returnVers) | |
63 | { | |
64 | if (!returnVers) | |
427c49bc | 65 | return errSecSuccess; |
b1ab9ed8 A |
66 | |
67 | *returnVers = 0x02028000; | |
427c49bc | 68 | return errSecSuccess; |
b1ab9ed8 A |
69 | } |
70 | ||
71 | ||
72 | OSStatus | |
73 | SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef) | |
74 | { | |
75 | BEGIN_SECAPI | |
76 | ||
77 | RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); | |
78 | ||
79 | END_SECAPI | |
80 | } | |
81 | ||
82 | ||
83 | OSStatus | |
84 | SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subserviceType, const char* dbName, | |
85 | const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain) | |
86 | { | |
87 | BEGIN_SECAPI | |
88 | ||
89 | // range check parameters | |
90 | RequiredParam (guid); | |
91 | RequiredParam (dbName); | |
92 | ||
93 | // create a DLDbIdentifier that describes what should be opened | |
94 | const CSSM_VERSION *version = NULL; | |
95 | const CssmSubserviceUid ssuid(*guid, version, subserviceId, subserviceType); | |
96 | DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation); | |
97 | ||
98 | // make a keychain from the supplied info | |
99 | RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false)->handle (); | |
100 | ||
101 | END_SECAPI | |
102 | } | |
103 | ||
104 | ||
105 | OSStatus | |
106 | SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password, | |
107 | Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef) | |
108 | { | |
109 | BEGIN_SECAPI | |
427c49bc A |
110 | |
111 | KCThrowParamErrIf_(!pathName); | |
b1ab9ed8 A |
112 | Keychain keychain = globals().storageManager.make(pathName); |
113 | ||
114 | // @@@ the call to StorageManager::make above leaves keychain the the cache. | |
115 | // If the create below fails we should probably remove it. | |
116 | if(promptUser) | |
117 | keychain->create(); | |
118 | else | |
119 | { | |
120 | KCThrowParamErrIf_(!password); | |
121 | keychain->create(passwordLength, password); | |
122 | } | |
123 | ||
124 | RequiredParam(keychainRef)=keychain->handle(); | |
125 | ||
126 | END_SECAPI | |
127 | } | |
128 | ||
129 | ||
130 | OSStatus | |
131 | SecKeychainDelete(SecKeychainRef keychainOrArray) | |
132 | { | |
133 | BEGIN_SECAPI | |
134 | ||
135 | KCThrowIf_(!keychainOrArray, errSecInvalidKeychain); | |
136 | StorageManager::KeychainList keychains; | |
137 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
138 | ||
139 | globals().storageManager.remove(keychains, true); | |
140 | ||
141 | END_SECAPI | |
142 | } | |
143 | ||
144 | ||
145 | OSStatus | |
146 | SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings) | |
147 | { | |
148 | BEGIN_SECAPI | |
149 | ||
150 | Keychain keychain = Keychain::optional(keychainRef); | |
151 | if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) | |
152 | { | |
153 | UInt32 lockInterval=newSettings->lockInterval; | |
154 | bool lockOnSleep=newSettings->lockOnSleep; | |
155 | keychain->setSettings(lockInterval, lockOnSleep); | |
156 | } | |
157 | ||
158 | END_SECAPI | |
159 | } | |
160 | ||
161 | ||
162 | OSStatus | |
163 | SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings) | |
164 | { | |
165 | BEGIN_SECAPI | |
166 | ||
167 | Keychain keychain = Keychain::optional(keychainRef); | |
168 | if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) | |
169 | { | |
170 | uint32 lockInterval; | |
171 | bool lockOnSleep; | |
172 | ||
173 | keychain->getSettings(lockInterval, lockOnSleep); | |
174 | outSettings->lockInterval=lockInterval; | |
175 | outSettings->lockOnSleep=lockOnSleep; | |
176 | } | |
177 | ||
178 | END_SECAPI | |
179 | } | |
180 | ||
181 | ||
182 | OSStatus | |
183 | SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword) | |
184 | { | |
185 | BEGIN_SECAPI | |
186 | ||
187 | Keychain keychain = Keychain::optional(keychainRef); | |
188 | ||
189 | if (usePassword) | |
190 | keychain->unlock(CssmData(const_cast<void *>(password), passwordLength)); | |
191 | else | |
192 | keychain->unlock(); | |
193 | ||
194 | END_SECAPI | |
195 | } | |
196 | ||
197 | ||
198 | OSStatus | |
199 | SecKeychainLock(SecKeychainRef keychainRef) | |
200 | { | |
201 | BEGIN_SECAPI | |
202 | ||
203 | Keychain keychain = Keychain::optional(keychainRef); | |
204 | keychain->lock(); | |
205 | ||
206 | END_SECAPI | |
207 | } | |
208 | ||
209 | ||
210 | OSStatus | |
211 | SecKeychainLockAll(void) | |
212 | { | |
213 | BEGIN_SECAPI | |
214 | ||
215 | globals().storageManager.lockAll(); | |
216 | ||
217 | END_SECAPI | |
218 | } | |
219 | ||
220 | ||
221 | OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList) | |
222 | { | |
223 | BEGIN_SECAPI | |
224 | // | |
225 | // Get the current user (using fallback method if necessary) | |
226 | // | |
227 | char* uName = getenv("USER"); | |
228 | string userName = uName ? uName : ""; | |
229 | if ( userName.length() == 0 ) | |
230 | { | |
231 | uid_t uid = geteuid(); | |
232 | if (!uid) uid = getuid(); | |
233 | struct passwd *pw = getpwuid(uid); // fallback case... | |
234 | if (pw) | |
235 | userName = pw->pw_name; | |
236 | endpwent(); | |
237 | } | |
238 | if ( userName.length() == 0 ) // did we ultimately get one? | |
239 | MacOSError::throwMe(errAuthorizationInternal); | |
822b670c A |
240 | |
241 | SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData()); | |
242 | ||
b1ab9ed8 A |
243 | if (password) |
244 | { | |
245 | // Clear the plist and move aside (rename) the existing login.keychain | |
246 | globals().storageManager.resetKeychain(resetSearchList); | |
247 | ||
248 | // Create the login keychain without UI | |
427c49bc | 249 | globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password); |
b1ab9ed8 A |
250 | |
251 | // Set it as the default | |
252 | Keychain keychain = globals().storageManager.loginKeychain(); | |
253 | globals().storageManager.defaultKeychain(keychain); | |
254 | } | |
255 | else | |
256 | { | |
257 | // Create the login keychain, prompting for password | |
258 | // (implicitly calls resetKeychain, login, and defaultKeychain) | |
259 | globals().storageManager.makeLoginAuthUI(NULL); | |
260 | } | |
261 | ||
262 | // Post a "list changed" event after a reset, so apps can refresh their list. | |
263 | // Make sure we are not holding mLock when we post this event. | |
264 | KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); | |
265 | ||
266 | END_SECAPI | |
267 | } | |
268 | ||
269 | OSStatus | |
270 | SecKeychainCopyDefault(SecKeychainRef *keychainRef) | |
271 | { | |
272 | BEGIN_SECAPI | |
273 | ||
274 | RequiredParam(keychainRef)=globals().storageManager.defaultKeychain()->handle(); | |
275 | ||
276 | END_SECAPI | |
277 | } | |
278 | ||
279 | ||
280 | OSStatus | |
281 | SecKeychainSetDefault(SecKeychainRef keychainRef) | |
282 | { | |
283 | BEGIN_SECAPI | |
284 | ||
285 | globals().storageManager.defaultKeychain(Keychain::optional(keychainRef)); | |
286 | ||
287 | END_SECAPI | |
288 | } | |
289 | ||
290 | OSStatus SecKeychainCopySearchList(CFArrayRef *searchList) | |
291 | { | |
292 | BEGIN_SECAPI | |
293 | ||
294 | RequiredParam(searchList); | |
295 | StorageManager &smr = globals().storageManager; | |
296 | StorageManager::KeychainList keychainList; | |
297 | smr.getSearchList(keychainList); | |
298 | *searchList = smr.convertFromKeychainList(keychainList); | |
299 | ||
300 | END_SECAPI | |
301 | } | |
302 | ||
303 | OSStatus SecKeychainSetSearchList(CFArrayRef searchList) | |
304 | { | |
305 | BEGIN_SECAPI | |
306 | ||
307 | RequiredParam(searchList); | |
308 | StorageManager &smr = globals().storageManager; | |
309 | StorageManager::KeychainList keychainList; | |
310 | smr.convertToKeychainList(searchList, keychainList); | |
311 | smr.setSearchList(keychainList); | |
312 | ||
313 | END_SECAPI | |
314 | } | |
315 | ||
316 | OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef) | |
317 | { | |
318 | BEGIN_SECAPI | |
319 | ||
320 | RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle(); | |
321 | ||
322 | END_SECAPI | |
323 | } | |
324 | ||
325 | OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef) | |
326 | { | |
327 | BEGIN_SECAPI | |
328 | ||
329 | globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef)); | |
330 | ||
331 | END_SECAPI | |
332 | } | |
333 | ||
334 | OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef *searchList) | |
335 | { | |
336 | BEGIN_SECAPI | |
337 | ||
338 | RequiredParam(searchList); | |
339 | StorageManager &smr = globals().storageManager; | |
340 | StorageManager::KeychainList keychainList; | |
341 | smr.getSearchList(domain, keychainList); | |
342 | *searchList = smr.convertFromKeychainList(keychainList); | |
343 | ||
344 | END_SECAPI | |
345 | } | |
346 | ||
347 | OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList) | |
348 | { | |
349 | BEGIN_SECAPI | |
350 | ||
351 | RequiredParam(searchList); | |
352 | StorageManager &smr = globals().storageManager; | |
353 | StorageManager::KeychainList keychainList; | |
354 | smr.convertToKeychainList(searchList, keychainList); | |
355 | smr.setSearchList(domain, keychainList); | |
356 | ||
357 | END_SECAPI | |
358 | } | |
359 | ||
360 | OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain) | |
361 | { | |
362 | BEGIN_SECAPI | |
363 | ||
364 | globals().storageManager.domain(domain); | |
365 | ||
366 | END_SECAPI | |
367 | } | |
368 | ||
369 | OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain) | |
370 | { | |
371 | BEGIN_SECAPI | |
372 | ||
373 | *domain = globals().storageManager.domain(); | |
374 | ||
375 | END_SECAPI | |
376 | } | |
377 | ||
378 | ||
379 | OSStatus | |
380 | SecKeychainGetStatus(SecKeychainRef keychainRef, SecKeychainStatus *keychainStatus) | |
381 | { | |
382 | BEGIN_SECAPI | |
383 | ||
384 | RequiredParam(keychainStatus) = (SecKeychainStatus)Keychain::optional(keychainRef)->status(); | |
385 | ||
386 | END_SECAPI | |
387 | } | |
388 | ||
389 | ||
390 | OSStatus | |
391 | SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathName) | |
392 | { | |
393 | BEGIN_SECAPI | |
394 | ||
395 | RequiredParam(pathName); | |
396 | RequiredParam(ioPathLength); | |
397 | ||
398 | const char *name = Keychain::optional(keychainRef)->name(); | |
427c49bc | 399 | UInt32 nameLen = (UInt32)strlen(name); |
b1ab9ed8 A |
400 | UInt32 callersLen = *ioPathLength; |
401 | *ioPathLength = nameLen; | |
402 | if (nameLen+1 > callersLen) // if the client's buffer is too small (including null-termination), throw | |
403 | return errSecBufferTooSmall; | |
404 | strncpy(pathName, name, nameLen); | |
405 | pathName[nameLen] = 0; | |
406 | *ioPathLength = nameLen; // set the length. | |
407 | ||
408 | END_SECAPI | |
409 | } | |
410 | ||
e3d460c9 A |
411 | OSStatus |
412 | SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version) | |
413 | { | |
414 | BEGIN_SECAPI | |
415 | ||
416 | RequiredParam(version); | |
417 | ||
418 | *version = Keychain::optional(keychainRef)->database()->dbBlobVersion(); | |
419 | ||
420 | END_SECAPI | |
421 | } | |
422 | ||
b1ab9ed8 A |
423 | |
424 | // @@@ Deprecated | |
425 | UInt16 | |
426 | SecKeychainListGetCount(void) | |
427 | { | |
428 | BEGIN_SECAPI | |
429 | ||
430 | return globals().storageManager.size(); | |
431 | ||
432 | END_SECAPI1(0) | |
433 | } | |
434 | ||
435 | ||
436 | // @@@ Deprecated | |
437 | OSStatus | |
438 | SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef) | |
439 | { | |
440 | BEGIN_SECAPI | |
441 | ||
442 | KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager; | |
443 | RequiredParam(keychainRef)=smgr[index]->handle(); | |
444 | ||
445 | END_SECAPI | |
446 | } | |
447 | ||
448 | ||
449 | // @@@ Deprecated | |
450 | OSStatus | |
451 | SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef) | |
452 | { | |
453 | BEGIN_SECAPI | |
454 | ||
455 | Required(keychainRef); | |
456 | Keychain keychain = Keychain::optional(*keychainRef); | |
457 | StorageManager::KeychainList keychainList; | |
458 | keychainList.push_back(keychain); | |
459 | globals().storageManager.remove(keychainList); | |
460 | *keychainRef = NULL; | |
461 | ||
462 | END_SECAPI | |
463 | } | |
464 | ||
465 | ||
466 | OSStatus | |
467 | SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info) | |
468 | { | |
469 | BEGIN_SECAPI | |
470 | ||
471 | Keychain keychain = Keychain::optional(keychainRef); | |
472 | keychain->getAttributeInfoForItemID(itemID, info); | |
473 | ||
474 | END_SECAPI | |
475 | } | |
476 | ||
477 | ||
478 | OSStatus | |
479 | SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) | |
480 | { | |
481 | BEGIN_SECAPI | |
482 | ||
483 | KeychainImpl::freeAttributeInfo(info); | |
484 | ||
485 | END_SECAPI | |
486 | } | |
487 | ||
488 | ||
489 | pascal OSStatus | |
490 | SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext) | |
491 | { | |
492 | BEGIN_SECAPI | |
493 | ||
494 | RequiredParam(callbackFunction); | |
495 | CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext); | |
496 | ||
497 | END_SECAPI | |
498 | } | |
499 | ||
500 | ||
501 | OSStatus | |
502 | SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) | |
503 | { | |
504 | BEGIN_SECAPI | |
505 | ||
506 | RequiredParam(callbackFunction); | |
507 | CCallbackMgr::RemoveCallback(callbackFunction); | |
508 | ||
509 | END_SECAPI | |
510 | } | |
511 | ||
512 | OSStatus | |
513 | 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) | |
514 | { | |
515 | BEGIN_SECAPI | |
516 | ||
517 | KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); | |
518 | // @@@ Get real itemClass | |
519 | Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false); | |
520 | ||
521 | if (serverName && serverNameLength) | |
522 | { | |
523 | CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength); | |
524 | item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server); | |
525 | // use server name as default label | |
526 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server); | |
527 | } | |
528 | ||
529 | if (accountName && accountNameLength) | |
530 | { | |
531 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
532 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
533 | } | |
534 | ||
535 | if (securityDomain && securityDomainLength) | |
536 | item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr), | |
537 | CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength)); | |
538 | ||
539 | item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port)); | |
540 | item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol); | |
541 | item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType); | |
542 | ||
543 | if (path && pathLength) | |
544 | item->setAttribute(Schema::attributeInfo(kSecPathItemAttr), | |
545 | CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength)); | |
546 | ||
547 | Keychain keychain = nil; | |
548 | try | |
549 | { | |
550 | keychain = Keychain::optional(keychainRef); | |
551 | if ( !keychain->exists() ) | |
552 | { | |
553 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
554 | } | |
555 | } | |
556 | catch(...) | |
557 | { | |
558 | keychain = globals().storageManager.defaultKeychainUI(item); | |
559 | } | |
560 | ||
561 | keychain->add(item); | |
562 | ||
563 | if (itemRef) | |
564 | *itemRef = item->handle(); | |
565 | ||
566 | END_SECAPI | |
567 | } | |
568 | ||
569 | ||
570 | OSStatus | |
571 | 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) | |
572 | ||
573 | { | |
574 | BEGIN_SECAPI | |
575 | ||
576 | StorageManager::KeychainList keychains; | |
577 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
578 | KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL); | |
579 | ||
580 | if (serverName && serverNameLength) | |
581 | { | |
582 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr), | |
583 | CssmData(const_cast<char *>(serverName), serverNameLength)); | |
584 | } | |
585 | ||
586 | if (securityDomain && securityDomainLength) | |
587 | { | |
588 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr), | |
589 | CssmData (const_cast<char*>(securityDomain), securityDomainLength)); | |
590 | } | |
591 | ||
592 | if (accountName && accountNameLength) | |
593 | { | |
594 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), | |
595 | CssmData (const_cast<char*>(accountName), accountNameLength)); | |
596 | } | |
597 | ||
598 | if (port) | |
599 | { | |
600 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr), | |
601 | UInt32(port)); | |
602 | } | |
603 | ||
604 | if (protocol) | |
605 | { | |
606 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr), | |
607 | protocol); | |
608 | } | |
609 | ||
610 | if (authenticationType) | |
611 | { | |
612 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr), | |
613 | authenticationType); | |
614 | } | |
615 | ||
616 | if (path && pathLength) | |
617 | { | |
618 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path); | |
619 | } | |
620 | ||
621 | Item item; | |
622 | if (!cursor->next(item)) | |
623 | return errSecItemNotFound; | |
624 | ||
625 | // Get its data (only if necessary) | |
626 | if (passwordData || passwordLength) | |
627 | { | |
628 | CssmDataContainer outData; | |
629 | item->getData(outData); | |
427c49bc | 630 | *passwordLength=(UInt32)outData.length(); |
b1ab9ed8 A |
631 | outData.Length=0; |
632 | *passwordData=outData.data(); | |
633 | outData.Data=NULL; | |
634 | } | |
635 | ||
636 | if (itemRef) | |
637 | *itemRef=item->handle(); | |
638 | ||
639 | END_SECAPI | |
640 | } | |
641 | ||
642 | ||
643 | OSStatus | |
644 | SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) | |
645 | { | |
646 | BEGIN_SECAPI | |
647 | ||
648 | KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); | |
649 | // @@@ Get real itemClass | |
650 | ||
651 | Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false); | |
652 | ||
653 | if (serviceName && serviceNameLength) | |
654 | { | |
655 | CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength); | |
656 | item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); | |
657 | // use service name as default label (UNLESS the service is iTools and we have an account name [3787371]) | |
658 | const char *iTools = "iTools"; | |
659 | if (accountNameLength && serviceNameLength==strlen(iTools) && !memcmp(serviceName, iTools, serviceNameLength)) | |
660 | { | |
661 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
662 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), account); | |
663 | } | |
664 | else | |
665 | { | |
666 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); | |
667 | } | |
668 | } | |
669 | ||
670 | if (accountName && accountNameLength) | |
671 | { | |
672 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
673 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
674 | } | |
675 | ||
676 | Keychain keychain = nil; | |
677 | try | |
678 | { | |
679 | keychain = Keychain::optional(keychainRef); | |
680 | if ( !keychain->exists() ) | |
681 | { | |
682 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
683 | } | |
684 | } | |
685 | catch(...) | |
686 | { | |
687 | keychain = globals().storageManager.defaultKeychainUI(item); | |
688 | } | |
689 | ||
690 | keychain->add(item); | |
691 | if (itemRef) | |
692 | *itemRef = item->handle(); | |
693 | ||
694 | END_SECAPI | |
695 | } | |
696 | ||
697 | ||
698 | OSStatus | |
699 | SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) | |
700 | ||
701 | { | |
702 | BEGIN_SECAPI | |
703 | ||
704 | StorageManager::KeychainList keychains; | |
705 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
706 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
707 | ||
708 | if (serviceName && serviceNameLength) | |
709 | { | |
710 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), | |
711 | CssmData(const_cast<char *>(serviceName), serviceNameLength)); | |
712 | } | |
713 | ||
714 | if (accountName && accountNameLength) | |
715 | { | |
716 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), | |
717 | CssmData(const_cast<char *>(accountName), accountNameLength)); | |
718 | } | |
719 | ||
720 | Item item; | |
721 | if (!cursor->next(item)) | |
722 | return errSecItemNotFound; | |
723 | ||
724 | // Get its data (only if necessary) | |
725 | if (passwordData || passwordLength) | |
726 | { | |
727 | CssmDataContainer outData; | |
728 | item->getData(outData); | |
427c49bc | 729 | *passwordLength=(UInt32)outData.length(); |
b1ab9ed8 A |
730 | outData.Length=0; |
731 | *passwordData=outData.data(); | |
732 | outData.Data=NULL; | |
733 | } | |
734 | ||
735 | if (itemRef) | |
736 | *itemRef=item->handle(); | |
737 | ||
738 | END_SECAPI | |
739 | } | |
740 | ||
741 | ||
742 | OSStatus | |
743 | SecKeychainSetUserInteractionAllowed(Boolean state) | |
744 | { | |
745 | BEGIN_SECAPI | |
746 | ||
747 | globals().setUserInteractionAllowed(state); | |
748 | ||
749 | END_SECAPI | |
750 | } | |
751 | ||
752 | ||
753 | OSStatus | |
754 | SecKeychainGetUserInteractionAllowed(Boolean *state) | |
755 | { | |
756 | BEGIN_SECAPI | |
757 | ||
758 | Required(state)=globals().getUserInteractionAllowed(); | |
759 | ||
760 | END_SECAPI | |
761 | } | |
762 | ||
763 | ||
764 | OSStatus | |
765 | SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle) | |
766 | { | |
767 | BEGIN_SECAPI | |
768 | ||
769 | RequiredParam(dldbHandle); | |
770 | ||
771 | Keychain keychain = Keychain::optional(keychainRef); | |
772 | *dldbHandle = keychain->database()->handle(); | |
773 | ||
774 | END_SECAPI | |
775 | } | |
776 | ||
777 | ||
778 | OSStatus | |
779 | SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) | |
780 | { | |
781 | BEGIN_SECAPI | |
782 | ||
783 | RequiredParam(cspHandle); | |
784 | ||
785 | Keychain keychain = Keychain::optional(keychainRef); | |
786 | *cspHandle = keychain->csp()->handle(); | |
787 | ||
788 | END_SECAPI | |
789 | } | |
790 | ||
791 | ||
792 | OSStatus | |
793 | SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef) | |
794 | { | |
795 | BEGIN_SECAPI | |
796 | ||
427c49bc | 797 | MacOSError::throwMe(errSecUnimplemented);//%%%for now |
b1ab9ed8 A |
798 | |
799 | END_SECAPI | |
800 | } | |
801 | ||
802 | ||
803 | OSStatus | |
804 | SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef) | |
805 | { | |
806 | BEGIN_SECAPI | |
807 | ||
427c49bc | 808 | MacOSError::throwMe(errSecUnimplemented);//%%%for now |
b1ab9ed8 A |
809 | |
810 | END_SECAPI | |
811 | } | |
812 | ||
813 | ||
814 | #pragma mark ---- Private API ---- | |
815 | ||
816 | ||
817 | OSStatus | |
818 | SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword) | |
819 | { | |
820 | BEGIN_SECAPI | |
821 | ||
822 | Keychain keychain = Keychain::optional(keychainRef); | |
823 | keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword); | |
824 | ||
825 | END_SECAPI | |
826 | } | |
827 | ||
828 | ||
829 | OSStatus | |
830 | SecKeychainCopyLogin(SecKeychainRef *keychainRef) | |
831 | { | |
832 | BEGIN_SECAPI | |
833 | ||
834 | RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle(); | |
835 | ||
836 | END_SECAPI | |
837 | } | |
838 | ||
839 | ||
840 | OSStatus | |
841 | SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password) | |
842 | { | |
843 | BEGIN_SECAPI | |
844 | ||
845 | try | |
846 | { | |
427c49bc A |
847 | if (password) { |
848 | globals().storageManager.login(nameLength, name, passwordLength, password); | |
849 | } else { | |
850 | globals().storageManager.stashLogin(); | |
851 | } | |
b1ab9ed8 A |
852 | } |
853 | catch (CommonError &e) | |
854 | { | |
855 | if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) | |
856 | { | |
857 | return errSecAuthFailed; | |
858 | } | |
859 | else | |
860 | { | |
861 | return e.osStatus(); | |
862 | } | |
863 | } | |
864 | ||
865 | END_SECAPI | |
866 | } | |
867 | ||
427c49bc A |
868 | OSStatus SecKeychainStash() |
869 | { | |
870 | BEGIN_SECAPI | |
871 | ||
872 | try | |
873 | { | |
874 | globals().storageManager.stashKeychain(); | |
875 | } | |
876 | catch (CommonError &e) | |
877 | { | |
878 | if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) | |
879 | { | |
880 | return errSecAuthFailed; | |
881 | } | |
882 | else | |
883 | { | |
884 | return e.osStatus(); | |
885 | } | |
886 | } | |
887 | ||
888 | END_SECAPI | |
889 | } | |
b1ab9ed8 A |
890 | |
891 | OSStatus | |
892 | SecKeychainLogout() | |
893 | { | |
894 | BEGIN_SECAPI | |
895 | ||
896 | globals().storageManager.logout(); | |
897 | ||
898 | END_SECAPI | |
899 | } | |
900 | ||
901 | /* (non-exported C utility routine) 'Makes' a keychain based on a full path | |
902 | */ | |
903 | static Keychain make(const char *name) | |
904 | { | |
905 | return globals().storageManager.make(name); | |
906 | } | |
907 | ||
908 | /* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs. | |
909 | Note this version doesn't take an accessRef or password. | |
910 | The "KC" create API takes a keychainRef... | |
911 | */ | |
912 | OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef) | |
913 | { | |
914 | BEGIN_SECAPI | |
915 | RequiredParam(fullPathName); | |
916 | RequiredParam(keychainRef)=make(fullPathName)->handle(); | |
917 | END_SECAPI | |
918 | } | |
919 | ||
920 | ||
921 | /* Determines if the keychainRef is a valid keychain. | |
922 | */ | |
923 | OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid) | |
924 | { | |
925 | BEGIN_SECAPI | |
926 | *isValid = false; | |
927 | if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL) | |
928 | *isValid = true; | |
929 | END_SECAPI | |
930 | } | |
931 | ||
932 | /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs. | |
933 | */ | |
934 | OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef) | |
935 | { | |
936 | BEGIN_SECAPI | |
937 | StorageManager::KeychainList singleton; | |
938 | singleton.push_back(KeychainImpl::required(keychainRef)); | |
939 | globals().storageManager.remove(singleton); | |
940 | END_SECAPI | |
941 | } | |
942 | ||
943 | /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs. | |
944 | */ | |
945 | OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword) | |
946 | { | |
947 | BEGIN_SECAPI | |
948 | RequiredParam(inPassword); | |
949 | KeychainImpl::required(keychainRef)->create(passwordLength, inPassword); | |
950 | END_SECAPI | |
951 | } | |
952 | ||
953 | /* Modify a keychain so that it can be synchronized. | |
954 | */ | |
955 | OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData) | |
956 | { | |
957 | BEGIN_SECAPI | |
958 | ||
959 | // do error checking for required parameters | |
960 | RequiredParam(dbBlobArray); | |
961 | RequiredParam(extraData); | |
962 | ||
963 | const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)), | |
964 | CFDataGetLength(extraData)); | |
965 | ||
966 | CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray); | |
967 | size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle)); | |
968 | void *dataPtr = (void*)malloc(space); | |
969 | if ( !dataPtr ) | |
427c49bc | 970 | return errSecAllocate; |
b1ab9ed8 A |
971 | // |
972 | // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with. | |
973 | // | |
974 | uint8* sizePtr = (uint8*)dataPtr; | |
975 | *sizePtr = dbBlobArrayCount; | |
976 | SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); | |
977 | CFIndex index; | |
978 | SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard()); | |
979 | for (index=0; index < dbBlobArrayCount; index++) | |
980 | { | |
981 | CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index); | |
982 | const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData)); | |
983 | // | |
984 | // Since it's to a DbHandle that's not on our disk (it came from user's iDisk), | |
985 | // it's OK to use the mIdentifier and access credentials of the keychain we're recoding. | |
986 | // | |
987 | Keychain kc = KeychainImpl::required(keychainRef); | |
988 | *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */ | |
989 | ||
990 | currDbHandle++; | |
991 | } | |
992 | // do the work | |
993 | Keychain keychain = Keychain::optional(keychainRef); | |
994 | const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space); | |
995 | Boolean recodeFailed = false; | |
996 | ||
427c49bc | 997 | int errCode=errSecSuccess; |
b1ab9ed8 A |
998 | |
999 | try | |
1000 | { | |
1001 | keychain->recode(data, extraCssmData); | |
1002 | } | |
1003 | catch (MacOSError e) | |
1004 | { | |
1005 | errCode = e.osStatus(); | |
1006 | recodeFailed = true; | |
1007 | } | |
1008 | catch (UnixError ue) | |
1009 | { | |
1010 | errCode = ue.unixError(); | |
1011 | } | |
1012 | ||
1013 | currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); | |
1014 | for (index=0; index < dbBlobArrayCount; index++) | |
1015 | { | |
1016 | ss.releaseDb(*currDbHandle); | |
1017 | currDbHandle++; | |
1018 | } | |
1019 | if ( dataPtr ) | |
1020 | free(dataPtr); | |
1021 | ||
1022 | if ( recodeFailed ) | |
1023 | { | |
1024 | return errCode; | |
1025 | } | |
1026 | ||
1027 | END_SECAPI | |
1028 | } | |
1029 | ||
1030 | OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) | |
1031 | { | |
1032 | BEGIN_SECAPI | |
1033 | ||
1034 | // do error checking for required parameters | |
1035 | RequiredParam(keychainSignature); | |
1036 | ||
1037 | // make a keychain object "wrapper" for this keychain ref | |
1038 | Keychain keychain = Keychain::optional(keychainRef); | |
1039 | CssmAutoData data(keychain->database()->allocator()); | |
1040 | keychain->copyBlob(data.get()); | |
1041 | ||
1042 | // get the cssmDBBlob | |
1043 | const SecurityServer::DbBlob *cssmDBBlob = | |
1044 | data.get().interpretedAs<const SecurityServer::DbBlob>(); | |
1045 | ||
1046 | // convert from CDSA standards to CF standards | |
1047 | *keychainSignature = CFDataCreate(kCFAllocatorDefault, | |
1048 | cssmDBBlob->randomSignature.bytes, | |
1049 | sizeof(SecurityServer::DbBlob::Signature)); | |
1050 | ||
1051 | END_SECAPI | |
1052 | } | |
1053 | ||
1054 | OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob) | |
1055 | { | |
1056 | BEGIN_SECAPI | |
1057 | ||
1058 | // do error checking for required parameters | |
1059 | RequiredParam(dbBlob); | |
1060 | ||
1061 | // make a keychain object "wrapper" for this keychain ref | |
1062 | Keychain keychain = Keychain::optional(keychainRef); | |
1063 | CssmAutoData data(keychain->database()->allocator()); | |
1064 | keychain->copyBlob(data.get()); | |
1065 | ||
1066 | // convert from CDSA standards to CF standards | |
1067 | *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length()); | |
1068 | ||
1069 | END_SECAPI | |
1070 | } | |
1071 | ||
1072 | // make a new keychain with pre-existing secrets | |
1073 | OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef) | |
1074 | { | |
1075 | BEGIN_SECAPI | |
1076 | ||
1077 | KCThrowParamErrIf_(!fullPathName); | |
1078 | KCThrowParamErrIf_(!dbBlob); | |
1079 | ||
1080 | Keychain keychain = globals().storageManager.make(fullPathName); | |
1081 | ||
1082 | CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob)); | |
1083 | ||
1084 | // @@@ the call to StorageManager::make above leaves keychain the the cache. | |
1085 | // If the create below fails we should probably remove it. | |
1086 | keychain->createWithBlob(blob); | |
1087 | ||
1088 | RequiredParam(kcRef)=keychain->handle(); | |
1089 | ||
1090 | // | |
1091 | ||
1092 | END_SECAPI | |
1093 | } | |
1094 | ||
1095 | // add a non-file based DB to the keychain list | |
1096 | OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1097 | const CSSM_GUID *guid, uint32 subServiceType) | |
1098 | { | |
1099 | BEGIN_SECAPI | |
1100 | ||
1101 | RequiredParam(dbName); | |
1102 | StorageManager &smr = globals().storageManager; | |
1103 | smr.addToDomainList(domain, dbName, *guid, subServiceType); | |
1104 | ||
1105 | END_SECAPI | |
1106 | } | |
1107 | ||
1108 | // determine if a non-file based DB is in the keychain list | |
1109 | OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1110 | const CSSM_GUID *guid, uint32 subServiceType) | |
1111 | { | |
1112 | BEGIN_SECAPI | |
1113 | RequiredParam(dbName); | |
1114 | StorageManager &smr = globals().storageManager; | |
1115 | smr.isInDomainList(domain, dbName, *guid, subServiceType); | |
1116 | END_SECAPI | |
1117 | } | |
1118 | ||
1119 | // remove a non-file based DB from the keychain list | |
1120 | OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1121 | const CSSM_GUID *guid, uint32 subServiceType) | |
1122 | { | |
1123 | BEGIN_SECAPI | |
1124 | RequiredParam(dbName); | |
1125 | StorageManager &smr = globals().storageManager; | |
1126 | smr.removeFromDomainList(domain, dbName, *guid, subServiceType); | |
1127 | END_SECAPI | |
1128 | } | |
1129 | ||
1130 | ||
1131 | // set server mode -- must be called before any other Sec* etc. call | |
1132 | void SecKeychainSetServerMode() | |
1133 | { | |
1134 | gServerMode = true; | |
1135 | } | |
1136 | ||
1137 | ||
1138 | ||
1139 | OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback) | |
1140 | { | |
1141 | BEGIN_SECAPI | |
1142 | RequiredParam(kcRef); | |
1143 | Keychain keychain = Keychain::optional(kcRef); | |
1144 | keychain->setBatchMode(mode, rollback); | |
1145 | END_SECAPI | |
1146 | } | |
1147 | ||
1148 | ||
1149 | ||
1150 | OSStatus SecKeychainCleanupHandles() | |
1151 | { | |
1152 | BEGIN_SECAPI | |
1153 | END_SECAPI // which causes the handle cache cleanup routine to run | |
1154 | } | |
1155 | ||
427c49bc A |
1156 | OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries) |
1157 | { | |
1158 | BEGIN_SECAPI | |
1159 | SecurityServer::ClientSession().verifyKeyStorePassphrase(retries); | |
1160 | END_SECAPI | |
1161 | } | |
1162 | ||
1163 | OSStatus SecKeychainChangeKeyStorePassphrase() | |
1164 | { | |
1165 | BEGIN_SECAPI | |
1166 | SecurityServer::ClientSession().changeKeyStorePassphrase(); | |
1167 | END_SECAPI | |
d8f41ccd A |
1168 | } |
1169 | ||
1170 | static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password) | |
1171 | { | |
1172 | BEGIN_SECAPI | |
1173 | ||
1174 | // make a keychain object "wrapper" for this keychain ref | |
1175 | Keychain keychain = Keychain::optional(userKeychainRef); | |
1176 | ||
1177 | CssmClient::Db db = keychain->database(); | |
1178 | ||
1179 | // create the keychain, using appropriate credentials | |
1180 | Allocator &alloc = db->allocator(); | |
1181 | AutoCredentials cred(alloc); // will leak, but we're quitting soon :-) | |
1182 | ||
1183 | char passphrase[1024]; | |
1184 | CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8); | |
1185 | ||
1186 | // use this passphrase | |
1187 | cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, | |
1188 | new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD), | |
1189 | new(alloc) ListElement(StringData(passphrase))); | |
1190 | db->accessCredentials(&cred); | |
1191 | ||
1192 | CSSM_DL_DB_HANDLE dlDb = db->handle(); | |
1193 | CssmData dlDbData = CssmData::wrap(dlDb); | |
1194 | CssmKey refKey; | |
1195 | KeySpec spec(CSSM_KEYUSE_ANY, | |
1196 | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE); | |
1197 | ||
1198 | DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64); | |
1199 | derive(&dlDbData, spec, refKey); | |
1200 | ||
1201 | // now extract the raw keybits | |
1202 | CssmKey rawKey; | |
1203 | WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE); | |
1204 | wrap(refKey, rawKey); | |
1205 | ||
1206 | *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length()); | |
1207 | ||
1208 | END_SECAPI | |
1209 | } | |
1210 | ||
1211 | ||
1212 | OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) { | |
1213 | SecTrustedApplicationRef itemPath; | |
1214 | SecAccessRef ourAccessRef = NULL; | |
1215 | ||
1216 | OSStatus result = errSecParam; | |
1217 | ||
1218 | CFDataRef masterKey = NULL; | |
1219 | result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password); | |
1220 | if (errSecSuccess != result) { | |
1221 | return result; | |
1222 | } | |
1223 | ||
1224 | result = SecKeychainStash(); | |
1225 | if (errSecSuccess != result) { | |
1226 | if (NULL != masterKey) CFRelease(masterKey); | |
1227 | return result; | |
1228 | } | |
1229 | ||
1230 | CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
1231 | if ( noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath ) | |
1232 | CFArrayAppendValue(trustedApplications, itemPath); | |
1233 | ||
1234 | if ( trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) { | |
1235 | if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) { | |
1236 | if (NULL == systemKeychainRef) { | |
1237 | SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &systemKeychainRef); | |
1238 | } | |
1239 | ||
1240 | const void *queryKeys[] = { kSecClass, | |
1241 | kSecAttrService, | |
1242 | kSecAttrAccount, | |
1243 | kSecUseKeychain, | |
1244 | }; | |
1245 | const void *queryValues[] = { kSecClassGenericPassword, | |
1246 | CFSTR("com.apple.loginwindow.auto-login"), | |
1247 | username, | |
1248 | systemKeychainRef, | |
1249 | }; | |
1250 | ||
1251 | const void *updateKeys[] = { kSecAttrAccess, | |
1252 | kSecValueData, | |
1253 | }; | |
1254 | const void *updateValues[] = { ourAccessRef, | |
1255 | masterKey, | |
1256 | }; | |
1257 | ||
1258 | CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1259 | CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1260 | ||
1261 | result = SecItemUpdate(query, update); | |
1262 | ||
1263 | if (errSecSuccess != result) { | |
1264 | const void *addKeys[] = { kSecClass, | |
1265 | kSecAttrService, | |
1266 | kSecAttrAccount, | |
1267 | kSecUseKeychain, | |
1268 | kSecAttrAccess, | |
1269 | kSecValueData, | |
1270 | }; | |
1271 | const void *addValues[] = { kSecClassGenericPassword, | |
1272 | CFSTR("com.apple.loginwindow.auto-login"), | |
1273 | username, | |
1274 | systemKeychainRef, | |
1275 | ourAccessRef, | |
1276 | masterKey, | |
1277 | }; | |
1278 | ||
1279 | CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1280 | result = SecItemAdd(add, NULL); | |
1281 | if (NULL != add) CFRelease(add); | |
1282 | } | |
1283 | ||
1284 | if (NULL != query) CFRelease(query); | |
1285 | if (NULL != update) CFRelease(update); | |
1286 | } | |
1287 | } | |
1288 | ||
1289 | if (NULL != masterKey) CFRelease(masterKey); | |
1290 | if (NULL != trustedApplications) CFRelease(trustedApplications); | |
1291 | if (NULL != ourAccessRef) CFRelease(ourAccessRef); | |
1292 | if (NULL != systemKeychainRef) CFRelease(systemKeychainRef); | |
1293 | ||
1294 | return result; | |
1295 | } |