/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdefined(XP_WIN) # include <combaseapi.h> # include <ntsecapi.h> # include <wincred.h> # include <windows.h> # include "nsIWindowsRegKey.h"// Must be included after <windows.h> for HKEY definition # define SECURITY_WIN32 # include <security.h> # include <shlwapi.h> # if !defined(__MINGW32__) # include <Lm.h> # undef ACCESS_READ // nsWindowsRegKey defines its own ACCESS_READ # endif // !defined(__MINGW32__) struct HandleCloser { typedef HANDLE pointer; voidoperator()(HANDLE h) { if (h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
}
}
}; struct BufferFreer { typedef LPVOID pointer;
ULONG mSize; explicit BufferFreer(ULONG size) : mSize(size) {} voidoperator()(LPVOID b) {
SecureZeroMemory(b, mSize);
CoTaskMemFree(b);
}
}; struct LsaDeregistrator { typedef HANDLE pointer; voidoperator()(HANDLE h) { if (h != INVALID_HANDLE_VALUE) {
LsaDeregisterLogonProcess(h);
}
}
}; typedef std::unique_ptr<HANDLE, HandleCloser> ScopedHANDLE; typedef std::unique_ptr<LPVOID, BufferFreer> ScopedBuffer; typedef std::unique_ptr<HANDLE, LsaDeregistrator> ScopedLsaHANDLE;
constexpr int64_t Int32Modulo = 2147483648;
// Get the token info holding the sid.
std::unique_ptr<char[]> GetTokenInfo(ScopedHANDLE& token) {
DWORD length = 0; // https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-gettokeninformation
mozilla::Unused << GetTokenInformation(token.get(), TokenUser, nullptr, 0,
&length); if (!length || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Unable to obtain current token info.")); return nullptr;
}
std::unique_ptr<char[]> token_info(newchar[length]); if (!GetTokenInformation(token.get(), TokenUser, token_info.get(), length,
&length)) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Unable to obtain current token info (second call, possible " "system error.")); return nullptr;
} return token_info;
}
std::unique_ptr<char[]> GetUserTokenInfo() { // Get current user sid to make sure the same user got logged in.
HANDLE token; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { // Couldn't get a process token. This will fail any unlock attempts later.
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Unable to obtain process token.")); return nullptr;
}
ScopedHANDLE scopedToken(token); return GetTokenInfo(scopedToken);
}
Maybe<int64_t> GetPasswordLastChanged(const WCHAR* username) { # ifdefined(__MINGW32__) // NetUserGetInfo requires Lm.h which is not provided in MinGW builds return mozilla::Nothing(); # else
LPUSER_INFO_1 user_info = NULL;
DWORD passwordAgeInSeconds = 0;
NET_API_STATUS ret =
NetUserGetInfo(NULL, username, 1, reinterpret_cast<LPBYTE*>(&user_info));
if (ret == NERR_Success) { // Returns seconds since last password change.
passwordAgeInSeconds = user_info->usri1_password_age;
NetApiBufferFree(user_info);
} else { return mozilla::Nothing();
}
// Return the time that the password was changed so we can use this // for future comparisons. return mozilla::Some(PR_Now() - passwordAgeInSeconds * PR_USEC_PER_SEC); # endif
}
// Use the Windows credential prompt to ask the user to authenticate the // currently used account. static nsresult ReauthenticateUserWindows( const nsAString& aMessageText, const nsAString& aCaptionText, const WindowsHandle& hwndParent, /* out */ bool& reauthenticated, /* inout */ bool& isBlankPassword, /* inout */ int64_t& prefLastChanged, /* out */ bool& isAutoAdminLogonEnabled, /* out */ bool& isRequireSignonEnabled) {
reauthenticated = false;
isAutoAdminLogonEnabled = false;
isRequireSignonEnabled = true;
// Check if the user has a blank password before proceeding
DWORD usernameLength = CREDUI_MAX_USERNAME_LENGTH + 1;
WCHAR username[CREDUI_MAX_USERNAME_LENGTH + 1] = {0};
if (!IsOS(OS_DOMAINMEMBER)) { const WCHAR* usernameNoDomain = username; // Don't include the domain portion of the username when calling LogonUser.
LPCWSTR backslash = wcschr(username, L'\\'); if (backslash) {
usernameNoDomain = backslash + 1;
}
Maybe<int64_t> lastChanged = GetPasswordLastChanged(usernameNoDomain); if (lastChanged.isSome()) { bool shouldCheckAgain = lastChanged.value() > prefLastChanged; // Update the value stored in preferences
prefLastChanged = lastChanged.value();
if (shouldCheckAgain) {
HANDLE logonUserHandle = INVALID_HANDLE_VALUE; bool result =
LogonUser(usernameNoDomain, L".", L"", LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &logonUserHandle); if (result) {
CloseHandle(logonUserHandle);
} // ERROR_ACCOUNT_RESTRICTION: Indicates a referenced user name and // authentication information are valid, but some user account // restriction has prevented successful authentication (such as // time-of-day restrictions).
reauthenticated = isBlankPassword =
(result || GetLastError() == ERROR_ACCOUNT_RESTRICTION);
} elseif (isBlankPassword) {
reauthenticated = true;
}
if (reauthenticated) { return NS_OK;
}
} else {
isBlankPassword = false;
}
} else { // Update any preferences, assuming domain members do not have blank // passwords
isBlankPassword = false;
}
while (!reauthenticated) {
HANDLE lsa = INVALID_HANDLE_VALUE; // Get authentication handle for future user authentications. // https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-lsaconnectuntrusted if (LsaConnectUntrusted(&lsa) != ERROR_SUCCESS) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Error acquiring lsa. Authentication attempts will fail.")); return NS_ERROR_FAILURE;
}
ScopedLsaHANDLE scopedLsa(lsa);
if (!userTokenInfo || lsa == INVALID_HANDLE_VALUE) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Error setting up login and user token.")); return NS_ERROR_FAILURE;
}
// Get user's Windows credentials. // https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-creduipromptforwindowscredentialsw
err = CredUIPromptForWindowsCredentialsW(
&credui, err, &authPackage, nullptr, 0, &outCredBuffer, &outCredSize,
nullptr, CREDUIWIN_ENUMERATE_CURRENT_USER);
ScopedBuffer scopedOutCredBuffer(outCredBuffer, BufferFreer(outCredSize)); if (err == ERROR_CANCELLED) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Error getting authPackage for user login, user cancel.")); return NS_OK;
} if (err != ERROR_SUCCESS) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Error getting authPackage for user login.")); return NS_ERROR_FAILURE;
}
// Verify the credentials.
TOKEN_SOURCE source;
PCHAR contextName = const_cast<PCHAR>("Mozilla");
size_t nameLength =
std::min(TOKEN_SOURCE_LENGTH, static_cast<int>(strlen(contextName))); // Note that the string must not be longer than TOKEN_SOURCE_LENGTH.
memcpy(source.SourceName, contextName, nameLength); // https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-allocatelocallyuniqueid if (!AllocateLocallyUniqueId(&source.SourceIdentifier)) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Error allocating ID for logon process.")); return NS_ERROR_FAILURE;
}
// The user can select any user to log-in on the authentication prompt. // Make sure that the logged in user is the current user.
std::unique_ptr<char[]> logonTokenInfo = GetTokenInfo(scopedToken); if (!logonTokenInfo) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Error getting logon token info.")); return NS_ERROR_FAILURE;
}
PSID logonSID = reinterpret_cast<TOKEN_USER*>(logonTokenInfo.get())->User.Sid;
PSID userSID = reinterpret_cast<TOKEN_USER*>(userTokenInfo.get())->User.Sid; if (EqualSid(userSID, logonSID)) {
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
("Login successfully (correct user)."));
reauthenticated = true; break;
} else {
err = ERROR_LOGON_FAILURE;
}
} return NS_OK;
} #endif// XP_WIN
static nsresult ReauthenticateUser(const nsAString& prompt, const nsAString& caption, const WindowsHandle& hwndParent, /* out */ bool& reauthenticated, /* inout */ bool& isBlankPassword, /* inout */ int64_t& prefLastChanged, /* out */ bool& isAutoAdminLogonEnabled, /* out */ bool& isRequireSignonEnabled) {
reauthenticated = false; #ifdefined(XP_WIN) return ReauthenticateUserWindows(
prompt, caption, hwndParent, reauthenticated, isBlankPassword,
prefLastChanged, isAutoAdminLogonEnabled, isRequireSignonEnabled); #elifdefined(XP_MACOSX) return ReauthenticateUserMacOS(prompt, reauthenticated, isBlankPassword); #else return NS_OK; #endif// Reauthentication is not implemented for this platform.
}
nsTArray<int32_t> prefLastChangedUpdates; #ifdefined(XP_WIN) // Increase the lastChanged time to account for clock skew.
prefLastChanged += PR_USEC_PER_SEC; // Need to split the 64bit integer to its hi and lo bits before sending it // back to JS.
int32_t prefLastChangedHi = prefLastChanged / Int32Modulo;
int32_t prefLastChangedLo = prefLastChanged % Int32Modulo;
prefLastChangedUpdates.AppendElement(prefLastChangedHi);
prefLastChangedUpdates.AppendElement(prefLastChangedLo); #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.