555 lines
19 KiB
C++
555 lines
19 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "OSReauthenticator.h"
|
|
|
|
#include "OSKeyStore.h"
|
|
#include "nsNetCID.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsIBaseWindow.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsISupportsUtils.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "mozilla/ipc/IPCTypes.h"
|
|
|
|
NS_IMPL_ISUPPORTS(OSReauthenticator, nsIOSReauthenticator)
|
|
|
|
extern mozilla::LazyLogModule gCredentialManagerSecretLog;
|
|
|
|
using mozilla::LogLevel;
|
|
using mozilla::Maybe;
|
|
using mozilla::Preferences;
|
|
using mozilla::WindowsHandle;
|
|
using mozilla::dom::Promise;
|
|
|
|
#define PREF_BLANK_PASSWORD "security.osreauthenticator.blank_password"
|
|
#define PREF_PASSWORD_LAST_CHANGED_LO \
|
|
"security.osreauthenticator.password_last_changed_lo"
|
|
#define PREF_PASSWORD_LAST_CHANGED_HI \
|
|
"security.osreauthenticator.password_last_changed_hi"
|
|
|
|
#if defined(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>
|
|
# include <lm.h>
|
|
# undef ACCESS_READ // nsWindowsRegKey defines its own ACCESS_READ
|
|
struct HandleCloser {
|
|
typedef HANDLE pointer;
|
|
void operator()(HANDLE h) {
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(h);
|
|
}
|
|
}
|
|
};
|
|
struct BufferFreer {
|
|
typedef LPVOID pointer;
|
|
ULONG mSize;
|
|
explicit BufferFreer(ULONG size) : mSize(size) {}
|
|
void operator()(LPVOID b) {
|
|
SecureZeroMemory(b, mSize);
|
|
CoTaskMemFree(b);
|
|
}
|
|
};
|
|
struct LsaDeregistrator {
|
|
typedef HANDLE pointer;
|
|
void operator()(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(new char[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) {
|
|
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);
|
|
}
|
|
|
|
bool IsAutoAdminLogonEnabled() {
|
|
// https://support.microsoft.com/en-us/help/324737/how-to-turn-on-automatic-logon-in-windows
|
|
nsresult rv;
|
|
nsCOMPtr<nsIWindowsRegKey> regKey =
|
|
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
rv = regKey->Open(
|
|
nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
|
|
nsLiteralString(
|
|
u"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
|
|
nsIWindowsRegKey::ACCESS_READ);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
nsAutoString value;
|
|
rv = regKey->ReadStringValue(u"AutoAdminLogon"_ns, value);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
regKey->Close();
|
|
|
|
return value.Equals(u"1"_ns);
|
|
}
|
|
|
|
bool IsRequireSignonEnabled() {
|
|
// https://docs.microsoft.com/en-us/windows-hardware/customize/power-settings/no-subgroup-settings-prompt-for-password-on-resume
|
|
nsresult rv;
|
|
nsCOMPtr<nsIWindowsRegKey> regKey =
|
|
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
|
|
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
|
|
u"System\\CurrentControlSet\\Control\\Power\\User\\Power"
|
|
"Schemes"_ns,
|
|
nsIWindowsRegKey::ACCESS_READ);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
|
|
nsAutoString activePowerScheme;
|
|
rv = regKey->ReadStringValue(u"ActivePowerScheme"_ns, activePowerScheme);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
regKey->Close();
|
|
|
|
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
|
|
u"System\\CurrentControlSet\\Control\\Power\\User\\Power"
|
|
"Schemes\\"_ns +
|
|
activePowerScheme +
|
|
u"\\0e796bdb-100d-47d6-a2d5-f7d2daa51f51"_ns,
|
|
nsIWindowsRegKey::ACCESS_READ);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
|
|
uint32_t value;
|
|
rv = regKey->ReadIntValue(u"ACSettingIndex"_ns, &value);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
regKey->Close();
|
|
|
|
return !!value;
|
|
}
|
|
|
|
// 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 (!GetUserNameEx(NameSamCompatible, username, &usernameLength)) {
|
|
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
|
|
("Error getting username"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
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);
|
|
} else if (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;
|
|
}
|
|
|
|
isAutoAdminLogonEnabled = IsAutoAdminLogonEnabled();
|
|
|
|
isRequireSignonEnabled = IsRequireSignonEnabled();
|
|
|
|
// Is used in next iteration if the previous login failed.
|
|
DWORD err = 0;
|
|
std::unique_ptr<char[]> userTokenInfo = GetUserTokenInfo();
|
|
|
|
// CredUI prompt.
|
|
CREDUI_INFOW credui = {};
|
|
credui.cbSize = sizeof(credui);
|
|
credui.hwndParent = reinterpret_cast<HWND>(hwndParent);
|
|
const nsString& messageText = PromiseFlatString(aMessageText);
|
|
credui.pszMessageText = messageText.get();
|
|
const nsString& captionText = PromiseFlatString(aCaptionText);
|
|
credui.pszCaptionText = captionText.get();
|
|
credui.hbmBanner = nullptr; // ignored
|
|
|
|
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;
|
|
}
|
|
|
|
ULONG authPackage = 0;
|
|
ULONG outCredSize = 0;
|
|
LPVOID outCredBuffer = nullptr;
|
|
|
|
// 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;
|
|
}
|
|
|
|
NTSTATUS substs;
|
|
void* profileBuffer = nullptr;
|
|
ULONG profileBufferLength = 0;
|
|
QUOTA_LIMITS limits = {0};
|
|
LUID luid;
|
|
HANDLE token = INVALID_HANDLE_VALUE;
|
|
LSA_STRING name;
|
|
name.Buffer = contextName;
|
|
name.Length = strlen(name.Buffer);
|
|
name.MaximumLength = name.Length;
|
|
// https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-lsalogonuser
|
|
NTSTATUS sts = LsaLogonUser(
|
|
scopedLsa.get(), &name, (SECURITY_LOGON_TYPE)Interactive, authPackage,
|
|
scopedOutCredBuffer.get(), outCredSize, nullptr, &source,
|
|
&profileBuffer, &profileBufferLength, &luid, &token, &limits, &substs);
|
|
ScopedHANDLE scopedToken(token);
|
|
LsaFreeReturnBuffer(profileBuffer);
|
|
if (sts == ERROR_SUCCESS) {
|
|
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
|
|
("User logged in successfully."));
|
|
} else {
|
|
err = LsaNtStatusToWinError(sts);
|
|
MOZ_LOG(gCredentialManagerSecretLog, LogLevel::Debug,
|
|
("Login failed with %lx (%lx).", sts, err));
|
|
continue;
|
|
}
|
|
|
|
// 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;
|
|
#if defined(XP_WIN)
|
|
return ReauthenticateUserWindows(
|
|
prompt, caption, hwndParent, reauthenticated, isBlankPassword,
|
|
prefLastChanged, isAutoAdminLogonEnabled, isRequireSignonEnabled);
|
|
#elif defined(XP_MACOSX)
|
|
return ReauthenticateUserMacOS(prompt, reauthenticated, isBlankPassword);
|
|
#else
|
|
return NS_OK;
|
|
#endif // Reauthentication is not implemented for this platform.
|
|
}
|
|
|
|
static void BackgroundReauthenticateUser(RefPtr<Promise>& aPromise,
|
|
const nsAString& aMessageText,
|
|
const nsAString& aCaptionText,
|
|
const WindowsHandle& hwndParent,
|
|
bool isBlankPassword,
|
|
int64_t prefLastChanged) {
|
|
nsAutoCString recovery;
|
|
bool reauthenticated;
|
|
bool isAutoAdminLogonEnabled;
|
|
bool isRequireSignonEnabled;
|
|
nsresult rv = ReauthenticateUser(
|
|
aMessageText, aCaptionText, hwndParent, reauthenticated, isBlankPassword,
|
|
prefLastChanged, isAutoAdminLogonEnabled, isRequireSignonEnabled);
|
|
|
|
nsTArray<int32_t> prefLastChangedUpdates;
|
|
#if defined(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
|
|
|
|
nsTArray<int32_t> results;
|
|
results.AppendElement(reauthenticated);
|
|
results.AppendElement(isBlankPassword);
|
|
#if defined(XP_WIN)
|
|
results.AppendElement(isAutoAdminLogonEnabled);
|
|
results.AppendElement(isRequireSignonEnabled);
|
|
#endif
|
|
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
|
|
"BackgroundReauthenticateUserResolve",
|
|
[rv, results = std::move(results),
|
|
prefLastChangedUpdates = std::move(prefLastChangedUpdates),
|
|
aPromise = std::move(aPromise)]() {
|
|
if (NS_FAILED(rv)) {
|
|
aPromise->MaybeReject(rv);
|
|
} else {
|
|
aPromise->MaybeResolve(results);
|
|
}
|
|
|
|
nsresult rv = Preferences::SetBool(PREF_BLANK_PASSWORD, results[1]);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
if (prefLastChangedUpdates.Length() > 1) {
|
|
rv = Preferences::SetInt(PREF_PASSWORD_LAST_CHANGED_HI,
|
|
prefLastChangedUpdates[0]);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
Preferences::SetInt(PREF_PASSWORD_LAST_CHANGED_LO,
|
|
prefLastChangedUpdates[1]);
|
|
}
|
|
}));
|
|
NS_DispatchToMainThread(runnable.forget());
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
OSReauthenticator::AsyncReauthenticateUser(const nsAString& aMessageText,
|
|
const nsAString& aCaptionText,
|
|
mozIDOMWindow* aParentWindow,
|
|
JSContext* aCx,
|
|
Promise** promiseOut) {
|
|
NS_ENSURE_ARG_POINTER(aCx);
|
|
|
|
RefPtr<Promise> promiseHandle;
|
|
nsresult rv = GetPromise(aCx, promiseHandle);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
WindowsHandle hwndParent = 0;
|
|
if (aParentWindow) {
|
|
nsPIDOMWindowInner* win = nsPIDOMWindowInner::From(aParentWindow);
|
|
nsIDocShell* docShell = win->GetDocShell();
|
|
if (docShell) {
|
|
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(docShell);
|
|
if (baseWindow) {
|
|
nsCOMPtr<nsIWidget> widget;
|
|
baseWindow->GetMainWidget(getter_AddRefs(widget));
|
|
if (widget) {
|
|
hwndParent = reinterpret_cast<WindowsHandle>(
|
|
widget->GetNativeData(NS_NATIVE_WINDOW));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int64_t prefLastChanged = 0;
|
|
bool isBlankPassword = false;
|
|
#if defined(XP_WIN)
|
|
// These preferences are only supported on Windows.
|
|
// Preferences are read/write main-thread only.
|
|
int32_t prefLastChangedLo;
|
|
int32_t prefLastChangedHi;
|
|
rv = Preferences::GetBool(PREF_BLANK_PASSWORD, &isBlankPassword);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
rv = Preferences::GetInt(PREF_PASSWORD_LAST_CHANGED_LO, &prefLastChangedLo);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
rv = Preferences::GetInt(PREF_PASSWORD_LAST_CHANGED_HI, &prefLastChangedHi);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
prefLastChanged = prefLastChangedHi * Int32Modulo + prefLastChangedLo;
|
|
#endif
|
|
|
|
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
|
|
"BackgroundReauthenticateUser",
|
|
[promiseHandle, aMessageText = nsAutoString(aMessageText),
|
|
aCaptionText = nsAutoString(aCaptionText), hwndParent, isBlankPassword,
|
|
prefLastChanged]() mutable {
|
|
BackgroundReauthenticateUser(promiseHandle, aMessageText, aCaptionText,
|
|
hwndParent, isBlankPassword,
|
|
prefLastChanged);
|
|
}));
|
|
|
|
nsCOMPtr<nsIEventTarget> target(
|
|
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID));
|
|
if (!target) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
promiseHandle.forget(promiseOut);
|
|
return NS_OK;
|
|
}
|