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

Unified 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, 2 months 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/password_manager/password_manager_util_win.cc
diff --git a/chrome/browser/password_manager/password_manager_util_win.cc b/chrome/browser/password_manager/password_manager_util_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..146670794f33f3e288990390dde5cf0c8e02ed58
--- /dev/null
+++ b/chrome/browser/password_manager/password_manager_util_win.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// windows.h must be first otherwise Win8 SDK breaks.
+#include <windows.h>
+#include <ntsecapi.h>
+#include <wincred.h>
+#include <subauth.h>
+
+// SECURITY_WIN32 must be defined in order to get
+// EXTENDED_NAME_FORMAT enumeration.
+#define SECURITY_WIN32 1
+#include <security.h>
+#undef SECURITY_WIN32
+
+#include "base/strings/utf_string_conversions.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace password_manager_util {
+
+// http://msdn.microsoft.com/en-us/library/cc245617.aspx.
+#define SAM_USERALLINFORMATION 21
+
+// http://msdn.microsoft.com/en-us/library/cc245522.aspx.
+#define DOMAIN_READ 0x00020084
+#define DOMAIN_LOOKUP 0x00000200
+
+const unsigned kMaxPasswordRetries = 3;
+const unsigned kCredUiDefaultFlags =
+ CREDUI_FLAGS_GENERIC_CREDENTIALS |
+ CREDUI_FLAGS_EXCLUDE_CERTIFICATES |
+ CREDUI_FLAGS_KEEP_USERNAME |
+ CREDUI_FLAGS_ALWAYS_SHOW_UI |
+ CREDUI_FLAGS_DO_NOT_PERSIST;
+
+// http://msdn.microsoft.com/en-us/library/cc245753.aspx.
+typedef NTSTATUS (WINAPI *SamConnectPtr)(PUNICODE_STRING ServerName,
+ PSAM_HANDLE ServerHandle,
+ DWORD DesiredAccess,
+ PVOID);
+
+// http://msdn.microsoft.com/en-us/library/cc245748.aspx.
+typedef NTSTATUS (WINAPI *SamOpenDomainPtr)(SAM_HANDLE ServerHandle,
+ DWORD dwAccess,
+ PSID DomainId,
+ PSAM_HANDLE DomainHandle);
+
+// http://msdn.microsoft.com/en-us/library/cc245712.aspx.
+typedef NTSTATUS (WINAPI *SamLookupNamesInDomainPtr)(SAM_HANDLE DomainHandle,
+ ULONG Count,
+ PUNICODE_STRING Names,
+ PULONG* RelativeIds,
+ PULONG* Use);
+
+// http://msdn.microsoft.com/en-us/library/cc245752.aspx.
+typedef NTSTATUS (WINAPI *SamOpenUserPtr)(SAM_HANDLE DomainHandle,
+ DWORD dwAccess,
+ DWORD UserId,
+ PSAM_HANDLE UserHandle);
+
+// http://msdn.microsoft.com/en-us/library/cc245786.aspx.
+typedef NTSTATUS (WINAPI *SamQueryInformationUserPtr)(
+ SAM_HANDLE UserHandle,
+ DWORD UserInformationClass,
+ PVOID Buffer);
+
+// http://msdn.microsoft.com/en-us/library/cc245722.aspx.
+typedef NTSTATUS (WINAPI *SamCloseHandlePtr)(PSAM_HANDLE SamHandle);
+typedef NTSTATUS (WINAPI *SamFreeMemoryPtr)(PVOID Buffer);
+
+static bool checkBlankPassword(WCHAR* pUsername) {
+ SAM_HANDLE handleSam = INVALID_HANDLE_VALUE;
+ 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?
+ SAM_HANDLE handleDomain = NULL;
+ SAM_HANDLE handleUser = NULL;
+ UNICODE_STRING username = {wcslen(pUsername) * sizeof(WCHAR),
+ wcslen(pUsername) * sizeof(WCHAR),
+ pUsername};
+ bool hasBlankPassword = false;
+
+ if (samlibDll) {
+ SamConnectPtr sam_connect_func =
+ reinterpret_cast<SamConnectPtr>(
+ GetProcAddress(samlibDll,"SamConnect"));
+ SamOpenDomainPtr sam_open_domain_func =
+ reinterpret_cast<SamOpenDomainPtr>(
+ GetProcAddress(samlibDll,"SamOpenDomain"));
+ SamLookupNamesInDomainPtr sam_lookup_names_in_domain_func =
+ reinterpret_cast<SamLookupNamesInDomainPtr>(
+ GetProcAddress(samlibDll,"SamLookupNamesInDomain"));
+ SamOpenUserPtr sam_open_user_func =
+ reinterpret_cast<SamOpenUserPtr>(
+ GetProcAddress(samlibDll,"SamOpenUser"));
+ SamQueryInformationUserPtr sam_query_information_user_func =
+ reinterpret_cast<SamQueryInformationUserPtr>(
+ GetProcAddress(samlibDll,"SamQueryInformationUser"));
+ SamCloseHandlePtr sam_close_handle_func =
+ reinterpret_cast<SamCloseHandlePtr>(
+ GetProcAddress(samlibDll,"SamCloseHandle"));
+ SamFreeMemoryPtr sam_free_memory_func =
+ reinterpret_cast<SamFreeMemoryPtr>(
+ GetProcAddress(samlibDll,"SamFreeMemory"));
+
+ if ((sam_connect_func == NULL) ||
+ (sam_open_domain_func == NULL) ||
+ (sam_lookup_names_in_domain_func == NULL) ||
+ (sam_open_user_func == NULL) ||
+ (sam_query_information_user_func == NULL) ||
+ (sam_close_handle_func == NULL) ||
+ (sam_free_memory_func == NULL))
+ {
+ FreeLibrary(samlibDll);
+ return false;
+ }
+
+ LSA_OBJECT_ATTRIBUTES connectionAttrib = {};
+ LSA_HANDLE handlePolicy = NULL;
+
+ // http://msdn2.microsoft.com/en-us/library/ms721895(VS.85).aspx
+ PPOLICY_ACCOUNT_DOMAIN_INFO structInfoPolicy;
+
+ connectionAttrib.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
+
+ NTSTATUS retval = LsaOpenPolicy(NULL,
+ &connectionAttrib,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &handlePolicy);
+
+ if (retval == STATUS_SUCCESS) {
+ // http://msdn.microsoft.com/en-us/library/aa378313(VS.85).aspx
+ retval = LsaQueryInformationPolicy(handlePolicy,
+ PolicyAccountDomainInformation,
+ reinterpret_cast<PVOID*>(
+ &structInfoPolicy));
+
+ if (retval == STATUS_SUCCESS) {
+ // http://msdn.microsoft.com/en-us/library/cc245753.aspx
+ retval = sam_connect_func(NULL, &handleSam, MAXIMUM_ALLOWED, NULL);
+
+ if (retval == STATUS_SUCCESS) {
+ // http://msdn.microsoft.com/en-us/library/cc245748.aspx
+ retval = sam_open_domain_func(handleSam,
+ DOMAIN_READ | DOMAIN_LOOKUP,
+ structInfoPolicy->DomainSid,
+ &handleDomain);
+
+ if (retval == STATUS_SUCCESS) {
+ PULONG relativeIds = NULL;
+ PULONG use = NULL;
+ // Get the RID for the given user name.
+ // http://msdn.microsoft.com/en-us/library/cc245712.aspx.
+ retval = sam_lookup_names_in_domain_func(handleDomain,
+ 1,
+ &username,
+ &relativeIds,
+ &use);
+ if (retval == STATUS_SUCCESS) {
+ PUSER_ALL_INFORMATION ptrUserInfo = NULL;
+ // http://msdn.microsoft.com/en-us/library/cc245752.aspx
+ retval = sam_open_user_func(handleDomain,
+ GENERIC_READ,
+ relativeIds[0],
+ &handleUser);
+
+ if (retval == STATUS_SUCCESS) {
+ // http://msdn.microsoft.com/en-us/library/cc245786.aspx
+ retval = sam_query_information_user_func(handleUser,
+ SAM_USERALLINFORMATION,
+ &ptrUserInfo);
+ if (retval == STATUS_SUCCESS) {
+ // If either the dBCSPwd attribute or the unicodePwd
+ // attribute does not have a value, or if either of these is
+ // equal to the respective hash of a zero-length string,
+ // PasswordCanChange MUST be 0.
+ // http://msdn.microsoft.com/en-us/library/cc245738.aspx
+ if (ptrUserInfo->PasswordCanChange.HighPart == 0 &&
+ ptrUserInfo->PasswordCanChange.LowPart == 0 ) {
+ hasBlankPassword = true;
+ }
+ sam_free_memory_func(ptrUserInfo);
+ }
+ // http://msdn.microsoft.com/en-us/library/cc245722.aspx
+ sam_close_handle_func(&handleUser);
+ }
+ }
+ }
+ }
+ LsaFreeMemory(structInfoPolicy);
+ }
+ LsaClose(handlePolicy);
+ }
+ FreeLibrary(samlibDll);
+ }
+ return hasBlankPassword;
+}
+
+
+bool AuthenticateUser() {
+ bool retval = false;
+ CREDUI_INFO cui = {};
+ WCHAR username[CREDUI_MAX_USERNAME_LENGTH+1] = {};
+ WCHAR displayname[CREDUI_MAX_USERNAME_LENGTH+1] = {};
+ WCHAR password[CREDUI_MAX_PASSWORD_LENGTH+1] = {};
+ DWORD username_length = CREDUI_MAX_USERNAME_LENGTH;
+ std::wstring product_name =
+ UTF16ToWide(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ std::wstring password_prompt =
+ UTF16ToWide(l10n_util::GetStringUTF16(
+ IDS_PASSWORDS_PAGE_AUTHENTICATION_PROMPT));
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ int tries = 0;
+ bool use_displayname = false;
+ bool use_principalname = false;
+ DWORD logon_result = 0;
+
+ // On a domain, we obtain the User Principal Name
+ // for domain authentication.
+ if (GetUserNameEx(NameUserPrincipal, username, &username_length)) {
+ use_principalname = true;
+ } else {
+ username_length = CREDUI_MAX_USERNAME_LENGTH;
+ // Otherwise, we're a workstation, use the plain local username.
+ if (!GetUserName(username, &username_length)) {
+ DLOG(ERROR) << "Unable to obtain username " << GetLastError();
+ return false;
+ } else {
+ // As we are on a workstation, it's possible the user
+ // has no password, so check here.
+ if (checkBlankPassword(username)) {
+ return true;
+ }
+ }
+ }
+
+ // Try and obtain a friendly display name.
+ username_length = CREDUI_MAX_USERNAME_LENGTH;
+ if (GetUserNameEx(NameDisplay, displayname, &username_length)) {
+ use_displayname = true;
+ }
+
+ cui.cbSize = sizeof(CREDUI_INFO);
+ cui.hwndParent = NULL;
+ cui.pszMessageText = password_prompt.c_str();
+ cui.pszCaptionText = product_name.c_str();
+
+ cui.hbmBanner = NULL;
+ BOOL save_password = FALSE;
+ DWORD credErr = NO_ERROR;
+
+ do {
+ tries++;
+
+ // TODO(wfh) Make sure we support smart cards here.
+ credErr = CredUIPromptForCredentials(
+ &cui,
+ product_name.c_str(),
+ NULL,
+ 0,
+ use_displayname ? displayname : username,
+ CREDUI_MAX_USERNAME_LENGTH+1,
+ password,
+ CREDUI_MAX_PASSWORD_LENGTH+1,
+ &save_password,
+ kCredUiDefaultFlags |
+ (tries > 1 ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0));
+
+ if (credErr == NO_ERROR) {
+ logon_result = LogonUser(username,
+ use_principalname ? NULL : L".",
+ password,
+ LOGON32_LOGON_NETWORK,
+ LOGON32_PROVIDER_DEFAULT,
+ &handle);
+ if (logon_result) {
+ retval = true;
+ CloseHandle(handle);
+ } else {
+ if (GetLastError() == ERROR_ACCOUNT_RESTRICTION &&
+ wcslen(password) == 0) {
+ // Password is blank, so permit.
+ retval = true;
+ } else {
+ DLOG(WARNING) << "Unable to authenticate " << GetLastError();
+ }
+ }
+ SecureZeroMemory(password, sizeof(password));
+ }
+ } while (credErr == NO_ERROR &&
+ (retval == false && tries < kMaxPasswordRetries));
+ return retval;
+}
+
+} // namespace password_manager_util

Powered by Google App Engine
This is Rietveld 408576698