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