Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(343)

Side by Side Diff: chrome/browser/password_manager/password_manager_util_win.cc

Issue 34393007: [Win] Add option to reauthenticate the OS user before revealing passwords. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@password
Patch Set: determine if password is blank using SAM API Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // windows.h must be first otherwise Win8 SDK breaks.
6 #include <windows.h>
7 #include <ntsecapi.h>
8 #include <wincred.h>
9 #include <subauth.h>
10
11 // SECURITY_WIN32 must be defined in order to get
12 // EXTENDED_NAME_FORMAT enumeration.
13 #define SECURITY_WIN32 1
14 #include <security.h>
15 #undef SECURITY_WIN32
16
17 #include "base/strings/utf_string_conversions.h"
18 #include "grit/chromium_strings.h"
19 #include "grit/generated_resources.h"
20 #include "ui/base/l10n/l10n_util.h"
21
22 namespace password_manager_util {
23
24 // http://msdn.microsoft.com/en-us/library/cc245617.aspx.
25 #define SAM_USERALLINFORMATION 21
26
27 // http://msdn.microsoft.com/en-us/library/cc245522.aspx.
28 #define DOMAIN_READ 0x00020084
29 #define DOMAIN_LOOKUP 0x00000200
30
31 const unsigned kMaxPasswordRetries = 3;
32 const unsigned kCredUiDefaultFlags =
33 CREDUI_FLAGS_GENERIC_CREDENTIALS |
34 CREDUI_FLAGS_EXCLUDE_CERTIFICATES |
35 CREDUI_FLAGS_KEEP_USERNAME |
36 CREDUI_FLAGS_ALWAYS_SHOW_UI |
37 CREDUI_FLAGS_DO_NOT_PERSIST;
38
39 // http://msdn.microsoft.com/en-us/library/cc245753.aspx.
40 typedef NTSTATUS (WINAPI *SamConnectPtr)(PUNICODE_STRING ServerName,
41 PSAM_HANDLE ServerHandle,
42 DWORD DesiredAccess,
43 PVOID);
44
45 // http://msdn.microsoft.com/en-us/library/cc245748.aspx.
46 typedef NTSTATUS (WINAPI *SamOpenDomainPtr)(SAM_HANDLE ServerHandle,
47 DWORD dwAccess,
48 PSID DomainId,
49 PSAM_HANDLE DomainHandle);
50
51 // http://msdn.microsoft.com/en-us/library/cc245712.aspx.
52 typedef NTSTATUS (WINAPI *SamLookupNamesInDomainPtr)(SAM_HANDLE DomainHandle,
53 ULONG Count,
54 PUNICODE_STRING Names,
55 PULONG* RelativeIds,
56 PULONG* Use);
57
58 // http://msdn.microsoft.com/en-us/library/cc245752.aspx.
59 typedef NTSTATUS (WINAPI *SamOpenUserPtr)(SAM_HANDLE DomainHandle,
60 DWORD dwAccess,
61 DWORD UserId,
62 PSAM_HANDLE UserHandle);
63
64 // http://msdn.microsoft.com/en-us/library/cc245786.aspx.
65 typedef NTSTATUS (WINAPI *SamQueryInformationUserPtr)(
66 SAM_HANDLE UserHandle,
67 DWORD UserInformationClass,
68 PVOID Buffer);
69
70 // http://msdn.microsoft.com/en-us/library/cc245722.aspx.
71 typedef NTSTATUS (WINAPI *SamCloseHandlePtr)(PSAM_HANDLE SamHandle);
72 typedef NTSTATUS (WINAPI *SamFreeMemoryPtr)(PVOID Buffer);
73
74 static bool checkBlankPassword(WCHAR* pUsername) {
75 SAM_HANDLE handleSam = INVALID_HANDLE_VALUE;
76 HMODULE samlibDll = LoadLibrary(L"samlib.dll");
cpu_(ooo_6.6-7.5) 2013/10/25 17:04:43 you are loading the library in the UI thread?
77 SAM_HANDLE handleDomain = NULL;
78 SAM_HANDLE handleUser = NULL;
79 UNICODE_STRING username = {wcslen(pUsername) * sizeof(WCHAR),
80 wcslen(pUsername) * sizeof(WCHAR),
81 pUsername};
82 bool hasBlankPassword = false;
83
84 if (samlibDll) {
85 SamConnectPtr sam_connect_func =
86 reinterpret_cast<SamConnectPtr>(
87 GetProcAddress(samlibDll,"SamConnect"));
88 SamOpenDomainPtr sam_open_domain_func =
89 reinterpret_cast<SamOpenDomainPtr>(
90 GetProcAddress(samlibDll,"SamOpenDomain"));
91 SamLookupNamesInDomainPtr sam_lookup_names_in_domain_func =
92 reinterpret_cast<SamLookupNamesInDomainPtr>(
93 GetProcAddress(samlibDll,"SamLookupNamesInDomain"));
94 SamOpenUserPtr sam_open_user_func =
95 reinterpret_cast<SamOpenUserPtr>(
96 GetProcAddress(samlibDll,"SamOpenUser"));
97 SamQueryInformationUserPtr sam_query_information_user_func =
98 reinterpret_cast<SamQueryInformationUserPtr>(
99 GetProcAddress(samlibDll,"SamQueryInformationUser"));
100 SamCloseHandlePtr sam_close_handle_func =
101 reinterpret_cast<SamCloseHandlePtr>(
102 GetProcAddress(samlibDll,"SamCloseHandle"));
103 SamFreeMemoryPtr sam_free_memory_func =
104 reinterpret_cast<SamFreeMemoryPtr>(
105 GetProcAddress(samlibDll,"SamFreeMemory"));
106
107 if ((sam_connect_func == NULL) ||
108 (sam_open_domain_func == NULL) ||
109 (sam_lookup_names_in_domain_func == NULL) ||
110 (sam_open_user_func == NULL) ||
111 (sam_query_information_user_func == NULL) ||
112 (sam_close_handle_func == NULL) ||
113 (sam_free_memory_func == NULL))
114 {
115 FreeLibrary(samlibDll);
116 return false;
117 }
118
119 LSA_OBJECT_ATTRIBUTES connectionAttrib = {};
120 LSA_HANDLE handlePolicy = NULL;
121
122 // http://msdn2.microsoft.com/en-us/library/ms721895(VS.85).aspx
123 PPOLICY_ACCOUNT_DOMAIN_INFO structInfoPolicy;
124
125 connectionAttrib.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
126
127 NTSTATUS retval = LsaOpenPolicy(NULL,
128 &connectionAttrib,
129 POLICY_VIEW_LOCAL_INFORMATION,
130 &handlePolicy);
131
132 if (retval == STATUS_SUCCESS) {
133 // http://msdn.microsoft.com/en-us/library/aa378313(VS.85).aspx
134 retval = LsaQueryInformationPolicy(handlePolicy,
135 PolicyAccountDomainInformation,
136 reinterpret_cast<PVOID*>(
137 &structInfoPolicy));
138
139 if (retval == STATUS_SUCCESS) {
140 // http://msdn.microsoft.com/en-us/library/cc245753.aspx
141 retval = sam_connect_func(NULL, &handleSam, MAXIMUM_ALLOWED, NULL);
142
143 if (retval == STATUS_SUCCESS) {
144 // http://msdn.microsoft.com/en-us/library/cc245748.aspx
145 retval = sam_open_domain_func(handleSam,
146 DOMAIN_READ | DOMAIN_LOOKUP,
147 structInfoPolicy->DomainSid,
148 &handleDomain);
149
150 if (retval == STATUS_SUCCESS) {
151 PULONG relativeIds = NULL;
152 PULONG use = NULL;
153 // Get the RID for the given user name.
154 // http://msdn.microsoft.com/en-us/library/cc245712.aspx.
155 retval = sam_lookup_names_in_domain_func(handleDomain,
156 1,
157 &username,
158 &relativeIds,
159 &use);
160 if (retval == STATUS_SUCCESS) {
161 PUSER_ALL_INFORMATION ptrUserInfo = NULL;
162 // http://msdn.microsoft.com/en-us/library/cc245752.aspx
163 retval = sam_open_user_func(handleDomain,
164 GENERIC_READ,
165 relativeIds[0],
166 &handleUser);
167
168 if (retval == STATUS_SUCCESS) {
169 // http://msdn.microsoft.com/en-us/library/cc245786.aspx
170 retval = sam_query_information_user_func(handleUser,
171 SAM_USERALLINFORMATION,
172 &ptrUserInfo);
173 if (retval == STATUS_SUCCESS) {
174 // If either the dBCSPwd attribute or the unicodePwd
175 // attribute does not have a value, or if either of these is
176 // equal to the respective hash of a zero-length string,
177 // PasswordCanChange MUST be 0.
178 // http://msdn.microsoft.com/en-us/library/cc245738.aspx
179 if (ptrUserInfo->PasswordCanChange.HighPart == 0 &&
180 ptrUserInfo->PasswordCanChange.LowPart == 0 ) {
181 hasBlankPassword = true;
182 }
183 sam_free_memory_func(ptrUserInfo);
184 }
185 // http://msdn.microsoft.com/en-us/library/cc245722.aspx
186 sam_close_handle_func(&handleUser);
187 }
188 }
189 }
190 }
191 LsaFreeMemory(structInfoPolicy);
192 }
193 LsaClose(handlePolicy);
194 }
195 FreeLibrary(samlibDll);
196 }
197 return hasBlankPassword;
198 }
199
200
201 bool AuthenticateUser() {
202 bool retval = false;
203 CREDUI_INFO cui = {};
204 WCHAR username[CREDUI_MAX_USERNAME_LENGTH+1] = {};
205 WCHAR displayname[CREDUI_MAX_USERNAME_LENGTH+1] = {};
206 WCHAR password[CREDUI_MAX_PASSWORD_LENGTH+1] = {};
207 DWORD username_length = CREDUI_MAX_USERNAME_LENGTH;
208 std::wstring product_name =
209 UTF16ToWide(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
210 std::wstring password_prompt =
211 UTF16ToWide(l10n_util::GetStringUTF16(
212 IDS_PASSWORDS_PAGE_AUTHENTICATION_PROMPT));
213 HANDLE handle = INVALID_HANDLE_VALUE;
214 int tries = 0;
215 bool use_displayname = false;
216 bool use_principalname = false;
217 DWORD logon_result = 0;
218
219 // On a domain, we obtain the User Principal Name
220 // for domain authentication.
221 if (GetUserNameEx(NameUserPrincipal, username, &username_length)) {
222 use_principalname = true;
223 } else {
224 username_length = CREDUI_MAX_USERNAME_LENGTH;
225 // Otherwise, we're a workstation, use the plain local username.
226 if (!GetUserName(username, &username_length)) {
227 DLOG(ERROR) << "Unable to obtain username " << GetLastError();
228 return false;
229 } else {
230 // As we are on a workstation, it's possible the user
231 // has no password, so check here.
232 if (checkBlankPassword(username)) {
233 return true;
234 }
235 }
236 }
237
238 // Try and obtain a friendly display name.
239 username_length = CREDUI_MAX_USERNAME_LENGTH;
240 if (GetUserNameEx(NameDisplay, displayname, &username_length)) {
241 use_displayname = true;
242 }
243
244 cui.cbSize = sizeof(CREDUI_INFO);
245 cui.hwndParent = NULL;
246 cui.pszMessageText = password_prompt.c_str();
247 cui.pszCaptionText = product_name.c_str();
248
249 cui.hbmBanner = NULL;
250 BOOL save_password = FALSE;
251 DWORD credErr = NO_ERROR;
252
253 do {
254 tries++;
255
256 // TODO(wfh) Make sure we support smart cards here.
257 credErr = CredUIPromptForCredentials(
258 &cui,
259 product_name.c_str(),
260 NULL,
261 0,
262 use_displayname ? displayname : username,
263 CREDUI_MAX_USERNAME_LENGTH+1,
264 password,
265 CREDUI_MAX_PASSWORD_LENGTH+1,
266 &save_password,
267 kCredUiDefaultFlags |
268 (tries > 1 ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0));
269
270 if (credErr == NO_ERROR) {
271 logon_result = LogonUser(username,
272 use_principalname ? NULL : L".",
273 password,
274 LOGON32_LOGON_NETWORK,
275 LOGON32_PROVIDER_DEFAULT,
276 &handle);
277 if (logon_result) {
278 retval = true;
279 CloseHandle(handle);
280 } else {
281 if (GetLastError() == ERROR_ACCOUNT_RESTRICTION &&
282 wcslen(password) == 0) {
283 // Password is blank, so permit.
284 retval = true;
285 } else {
286 DLOG(WARNING) << "Unable to authenticate " << GetLastError();
287 }
288 }
289 SecureZeroMemory(password, sizeof(password));
290 }
291 } while (credErr == NO_ERROR &&
292 (retval == false && tries < kMaxPasswordRetries));
293 return retval;
294 }
295
296 } // namespace password_manager_util
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698