Skip to content

Commit 781b200

Browse files
committed
Bug 1882413 - Part 3: Modify powershell set default to more accurately mirror the Win32 API set default implementation. r=nalexander,mhughes
This modifies the implementation to delete the registry keys via `DeleteSubKey` instead of `DeleteSubKeyTree`. This no longer throws when the DENY permission is set on a registry key as is the case for file association keys. This does throw when we are unable to delete a registry key as has been observed in newer versions of windows. Similar to the Win32 API implementation, this now halts execution and returns an error to the invoking process. Differential Revision: https://phabricator.services.mozilla.com/D203069
1 parent 2ddad82 commit 781b200

File tree

3 files changed

+30
-43
lines changed

3 files changed

+30
-43
lines changed

browser/components/shell/WindowsUserChoice.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -284,19 +284,17 @@ UniquePtr<wchar_t[]> GetAssociationKeyPath(const wchar_t* aExt) {
284284
return keyPath;
285285
}
286286

287-
nsresult AppendAssociationKeyPath(const wchar_t* aExt, nsString& output) {
287+
void AppendAssociationKeyPath(const wchar_t* aExt, nsAString& aOutput) {
288288
if (aExt[0] == L'.') {
289-
output.AppendLiteral(
289+
aOutput.AppendLiteral(
290290
u"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
291291
} else {
292-
output.AppendLiteral(
292+
aOutput.AppendLiteral(
293293
u"SOFTWARE\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations"
294294
u"\\");
295295
}
296296

297-
output.Append(aExt);
298-
299-
return NS_OK;
297+
aOutput.Append(aExt);
300298
}
301299

302300
UniquePtr<wchar_t[]> GenerateUserChoiceHash(const wchar_t* aExt,

browser/components/shell/WindowsUserChoice.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ mozilla::UniquePtr<wchar_t[]> GetAssociationKeyPath(const wchar_t* aExt);
6565
* Appends the registry path for the given association, file extension or
6666
* protocol to the parameter string.
6767
*
68-
* @return The path, or nullptr on failure.
68+
* @param aExt File extension or protocol association to return path to.
69+
* @param aOutput String to append registry path to.
6970
*/
70-
nsresult AppendAssociationKeyPath(const wchar_t* aExt, nsString& output);
71+
void AppendAssociationKeyPath(const wchar_t* aExt, nsAString& aOutput);
7172

7273
/*
7374
* Get the current user's SID

toolkit/mozapps/defaultagent/SetDefaultBrowser.cpp

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ static UINT GetSystemSleepIntervalInMilliseconds(UINT defaultValue) {
512512
}
513513

514514
/*
515-
* MSIX implementation o SetDefaultExtensionHandlersUserChoice.
515+
* MSIX implementation for SetDefaultExtensionHandlersUserChoice.
516516
*
517517
* Due to the fact that MSIX builds run in a virtual, walled off environment,
518518
* calling into the Win32 registry APIs doesn't work to set registry keys.
@@ -530,7 +530,7 @@ static UINT GetSystemSleepIntervalInMilliseconds(UINT defaultValue) {
530530
* Powershell, to make it as quick as possible.
531531
*
532532
*/
533-
nsresult SetDefaultExtensionHandlersUserChoiceImplMsix(
533+
static nsresult SetDefaultExtensionHandlersUserChoiceImplMsix(
534534
const wchar_t* aAumi, const wchar_t* const aSid,
535535
const nsTArray<nsString>& aFileExtensions) {
536536
mozilla::UniquePtr<wchar_t[]> exePath;
@@ -544,24 +544,20 @@ nsresult SetDefaultExtensionHandlersUserChoiceImplMsix(
544544
// extension, done below.
545545
nsString startScript(
546546
uR"(
547+
# Force exceptions to stop execution
548+
$ErrorActionPreference = 'Stop'
549+
547550
function Set-DefaultHandlerRegistry($Path, $ProgID, $Hash) {
548551
$Path = "$Path\UserChoice"
549552
$CurrentUser = [Microsoft.Win32.Registry]::CurrentUser
550-
$ReadWriteSubTreePerm = [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree
551-
try {
552-
$CurrentUser.DeleteSubKeyTree($Path, $false)
553-
$key = $CurrentUser.CreateSubKey($Path, $ReadWriteSubTreePerm)
554-
} catch {
555-
$key = $CurrentUser.OpenSubKey($Path, $ReadWriteSubTreePerm, [System.Security.AccessControl.RegistryRights]::ChangePermissions)
556-
$acl = $key.GetAccessControl()
557-
$CurrentName = [Security.Principal.WindowsIdentity]::GetCurrent().Name
558-
$rule = New-Object System.Security.AccessControl.RegistryAccessRule($CurrentName, 'SetValue', 'Deny')
559-
$acl.RemoveAccessRule($rule)
560-
$key.SetAccessControl($acl)
561-
$key.Close()
562-
563-
$key = $CurrentUser.OpenSubKey($Path, $ReadWriteSubTreePerm)
564-
}
553+
554+
# DeleteSubKey throws if we don't have sufficient permissions to delete key,
555+
# signaling failure to launching process.
556+
#
557+
# Note: DeleteSubKeyTree fails when DENY permissions are set on key, whereas
558+
# DeleteSubKey succeeds.
559+
$CurrentUser.DeleteSubKey($Path, $false)
560+
$key = $CurrentUser.CreateSubKey($Path)
565561
566562
$StringType = [Microsoft.Win32.RegistryValueKind]::String
567563
$key.SetValue('ProgID', $ProgID, $StringType)
@@ -620,28 +616,20 @@ function Set-DefaultHandlerRegistry($Path, $ProgID, $Hash) {
620616
for (size_t i = 0; i + 1 < aFileExtensions.Length(); i += 2) {
621617
const wchar_t* fileExtension = aFileExtensions[i].get();
622618

623-
// Append a line to the script buffer in the form:
624-
// Set-DefaultHandlerRegistry $RegistryKeyPath $ProgID $UserChoiceHash
625-
626-
// Use Append to minimize string allocation and processing
619+
nsAutoString keyPath;
620+
AppendAssociationKeyPath(fileExtension, keyPath);
627621

628-
scriptBuffer.AppendLiteral(u"Set-DefaultHandlerRegistry ");
629-
rv = AppendAssociationKeyPath(fileExtension, scriptBuffer);
630-
NS_ENSURE_SUCCESS(rv, rv);
631-
632-
scriptBuffer.AppendLiteral(u" ");
633-
634-
scriptBuffer.Append(progIDs[i / 2].get());
635-
scriptBuffer.AppendLiteral(u" ");
636-
637-
auto hash = GenerateUserChoiceHash(fileExtension, aSid,
638-
progIDs[i / 2].get(), hashTimestamp);
639-
if (!hash) {
622+
auto hashWchar = GenerateUserChoiceHash(
623+
fileExtension, aSid, progIDs[i / 2].get(), hashTimestamp);
624+
if (!hashWchar) {
640625
return NS_ERROR_FAILURE;
641626
}
627+
auto hash = nsDependentString(hashWchar.get());
642628

643-
scriptBuffer.Append(hash.get());
644-
scriptBuffer.AppendLiteral(u"\n");
629+
// Append a line to the script buffer in the form:
630+
// Set-DefaultHandlerRegistry $RegistryKeyPath $ProgID $UserChoiceHash
631+
scriptBuffer += u"Set-DefaultHandlerRegistry "_ns + keyPath + u" "_ns +
632+
progIDs[i / 2] + u" "_ns + hash + u"\n"_ns;
645633
}
646634

647635
// The hash changes at the end of each minute, so check that the hash should

0 commit comments

Comments
 (0)