]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecPassword.cpp
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecPassword.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
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 "SecPassword.h"
25 #include "Password.h"
26
27 #include "SecBridge.h"
28
29 #include "KCExceptions.h"
30 #include <Security/Authorization.h>
31 #include <Security/AuthorizationTagsPriv.h>
32
33 #include <os/activity.h>
34
35 #include "LegacyAPICounts.h"
36
37 OSStatus
38 SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef)
39 {
40 BEGIN_SECAPI
41 os_activity_t activity = os_activity_create("SecGenericPasswordCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
42 os_activity_scope(activity);
43 os_release(activity);
44 KCThrowParamErrIf_( (itemRef == NULL) );
45 KCThrowParamErrIf_( (searchAttrList == NULL) ^ (itemAttrList == NULL) ); // Both or neither
46
47 Password passwordItem(kSecGenericPasswordItemClass, searchAttrList, itemAttrList);
48 if (itemRef)
49 *itemRef = passwordItem->handle();
50
51 END_SECAPI
52 }
53
54 OSStatus
55 SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef)
56 {
57 BEGIN_SECAPI
58 os_activity_t activity = os_activity_create("SecPasswordSetInitialAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
59 os_activity_scope(activity);
60 os_release(activity);
61 PasswordImpl::required(itemRef)->setAccess(Access::required(accessRef));
62 END_SECAPI
63 }
64
65 OSStatus
66 SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data)
67 {
68 BEGIN_SECAPI
69 os_activity_t activity = os_activity_create("SecPasswordAction", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
70 os_activity_scope(activity);
71 os_release(activity);
72
73 Password passwordRef = PasswordImpl::required(itemRef);
74
75 void *passwordData = NULL;
76 UInt32 passwordLength = 0;
77 bool gotPassword = false;
78
79 // no flags has no meaning, and there is no apparent default
80 assert( flags );
81
82 // fail can only be combined with get or new
83 assert( (flags & kSecPasswordFail) ? ((flags & kSecPasswordGet) || (flags & kSecPasswordNew)) : true );
84
85 // XXX/cs replace this with our CFString->UTF8 conversion
86 const char *messageData = NULL;
87 auto_array<char> messageBuffer;
88
89 if (message && (CFStringGetTypeID() == CFGetTypeID(message)))
90 {
91 messageData = CFStringGetCStringPtr(static_cast<CFStringRef>(message), kCFStringEncodingUTF8);
92
93 if (messageData == NULL)
94 {
95 CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(static_cast<CFStringRef>(message)), kCFStringEncodingUTF8) + 1;
96
97 messageBuffer.allocate(maxLen);
98 if (CFStringGetCString(static_cast<CFStringRef>(message), messageBuffer.get(), maxLen, kCFStringEncodingUTF8))
99 messageData = messageBuffer.get();
100 }
101 }
102
103 if (passwordRef->useKeychain() && !(flags & kSecPasswordNew) && !(flags & kSecPasswordFail))
104 {
105 // Pull out data and if it's successful return it
106 if (flags & kSecPasswordGet)
107 {
108
109 // XXX/cs if there are unsaved changes this doesn't work
110 // so doing a Get followed by a Get|Set will do the wrong thing
111
112 // check mItem whether it's got data
113 if (passwordRef->getData(length, data))
114 return errSecSuccess;
115 }
116
117 // User might cancel here, immediately return that too (it will be thrown)
118 }
119
120 // If we're still here we're not using the keychain or it wasn't there yet
121
122 // Do the authorization call to get the password, unless only kSecPasswordSet is specified)
123 if ((flags & kSecPasswordNew) || (flags & kSecPasswordGet))
124 {
125 AuthorizationRef authRef;
126 OSStatus status = AuthorizationCreate(NULL,NULL,0,&authRef);
127 if (status != errSecSuccess)
128 {
129 MacOSError::throwMe(status);
130 }
131
132 AuthorizationItem right = { NULL, 0, NULL, 0 };
133 AuthorizationItemSet rightSet = { 1, &right };
134 uint32_t reason, tries;
135 bool keychain = 0, addToKeychain = 0;
136
137 if (passwordRef->useKeychain())
138 {
139 keychain = 1;
140 addToKeychain = passwordRef->rememberInKeychain();
141 }
142 else
143 {
144 keychain = 0;
145 addToKeychain = 0;
146 }
147
148 // Get|Fail conceivable would have it enabled, but since the effect is that it will get overwritten
149 // we'll make the user explicitly do it
150 if (flags & kSecPasswordGet)
151 addToKeychain = 0; // turn it off for old items that weren't successfully retrieved from the keychain
152
153 if (flags & kSecPasswordFail) // set up retry to reflect failure
154 {
155 tries = 1;
156 if (flags & kSecPasswordNew)
157 reason = 34; // passphraseUnacceptable = 34 passphrase unacceptable for some other reason
158 else
159 reason = 21; // invalidPassphrase = 21 passphrase was wrong
160 }
161 else
162 {
163 reason = 0;
164 tries = 0;
165 }
166
167 if (flags & kSecPasswordNew) // pick new passphrase
168 right.name = "com.apple.builtin.generic-new-passphrase";
169 else
170 right.name = "com.apple.builtin.generic-unlock";
171
172 bool showPassword = false;
173
174 AuthorizationItem envRights[6] = { { AGENT_HINT_RETRY_REASON, sizeof(reason), &reason, 0 },
175 { AGENT_HINT_TRIES, sizeof(tries), &tries, 0 },
176 { AGENT_HINT_CUSTOM_PROMPT, messageData ? strlen(messageData) : 0, const_cast<char*>(messageData), 0 },
177 { AGENT_HINT_ALLOW_SHOW_PASSWORD, showPassword ? strlen("YES") : strlen("NO"), const_cast<char *>(showPassword ? "YES" : "NO"), 0 },
178 { AGENT_HINT_SHOW_ADD_TO_KEYCHAIN, keychain ? strlen("YES") : strlen("NO"), const_cast<char *>(keychain ? "YES" : "NO"), 0 },
179 { AGENT_ADD_TO_KEYCHAIN, addToKeychain ? strlen("YES") : strlen("NO"), const_cast<char *>(addToKeychain ? "YES" : "NO"), 0 } };
180
181 AuthorizationItemSet envSet = { sizeof(envRights) / sizeof(*envRights), envRights };
182
183 secinfo("SecPassword", "dialog(%s)%s%s%s.", right.name, tries?" retry":"", keychain?" show-add-keychain":"", addToKeychain?" save-to-keychain":"");
184
185 status = AuthorizationCopyRights(authRef, &rightSet, &envSet, kAuthorizationFlagDefaults|kAuthorizationFlagInteractionAllowed|kAuthorizationFlagExtendRights, NULL);
186
187 if (status)
188 {
189 AuthorizationFree(authRef, 0);
190 return status;
191 }
192
193 // if success pull the data
194 AuthorizationItemSet *returnedInfo;
195 status = AuthorizationCopyInfo(authRef, NULL, &returnedInfo);
196
197 if (status)
198 {
199 AuthorizationFree(authRef, 0);
200
201 return status;
202 }
203
204 if (returnedInfo && (returnedInfo->count > 0))
205 {
206 for (uint32_t index = 0; index < returnedInfo->count; index++)
207 {
208 AuthorizationItem &item = returnedInfo->items[index];
209
210 if (!strcmp(AGENT_PASSWORD, item.name))
211 {
212 gotPassword = true;
213 passwordLength = (UInt32)item.valueLength;
214
215 if (passwordLength)
216 {
217 Allocator &allocator = Allocator::standard();
218 passwordData = allocator.malloc(passwordLength);
219 if (passwordData)
220 memcpy(passwordData, item.value, passwordLength);
221 }
222
223 if (length)
224 *length = passwordLength;
225 if (data)
226 *data = passwordData;
227
228 secinfo("SecPassword", "Got password (%u,%p).", (unsigned int)passwordLength, passwordData);
229 }
230 else if (!strcmp(AGENT_ADD_TO_KEYCHAIN, item.name))
231 {
232 bool remember = (item.value && item.valueLength == strlen("YES") && !memcmp("YES", static_cast<char *>(item.value), item.valueLength));
233 passwordRef->setRememberInKeychain(remember);
234 if (remember)
235 secinfo("SecPassword", "User wants to add the password to the Keychain.");
236 }
237 }
238 }
239
240 if(returnedInfo) {
241 AuthorizationFreeItemSet(returnedInfo);
242 }
243 AuthorizationFree(authRef, 0);
244
245 }
246
247 // If we're still here the user gave us their password, store it if keychain is in use
248 if (passwordRef->useKeychain())
249 {
250 if (passwordRef->rememberInKeychain()) {
251 if (gotPassword)
252 passwordRef->setData(passwordLength, passwordData);
253 if (flags & kSecPasswordSet)
254 {
255 passwordRef->save();
256 gotPassword = true;
257 }
258 }
259 }
260
261 if (!gotPassword)
262 {
263 return errAuthorizationDenied;
264 }
265
266 END_SECAPI
267 }