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