Commit cd0412d2 authored by Mike Jackson's avatar Mike Jackson Committed by Chromium LUCI CQ

Removing bundle from login fails due to errSecParam

As part of the work to support PWA's running at OS login,
I noticed that the call to RemoveFromLoginItems was failing
with errSecParam (-50). The reason appears to be that
the original LSSharedFileListRef is being destroyed, and a new
one is created. This change factors the code so that we
always operate on the same LSSSharedFileListRef which
allows the operation to succeed.

Tested: Manually by mjackson on MacOS 11.0

Bug: 897302
Change-Id: I8d24495b9f3cae3d7df0341a5c5d0cb951e96176
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2522876
Commit-Queue: Mike Jackson <mjackson@microsoft.com>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#832372}
parent e7da4cab
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include <CoreServices/CoreServices.h>
#import <IOKit/IOKitLib.h> #import <IOKit/IOKitLib.h>
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
...@@ -31,46 +32,64 @@ namespace mac { ...@@ -31,46 +32,64 @@ namespace mac {
namespace { namespace {
// Looks into Shared File Lists corresponding to Login Items for the item class LoginItemsFileList {
// representing the current application. If such an item is found, returns a public:
// retained reference to it. Caller is responsible for releasing the reference. LoginItemsFileList() = default;
LSSharedFileListItemRef GetLoginItemForApp() { LoginItemsFileList(const LoginItemsFileList&) = delete;
ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate( LoginItemsFileList& operator=(const LoginItemsFileList&) = delete;
NULL, kLSSharedFileListSessionLoginItems, NULL)); ~LoginItemsFileList() = default;
if (!login_items.get()) { bool Initialize() WARN_UNUSED_RESULT {
DLOG(ERROR) << "Couldn't get a Login Items list."; DCHECK(!login_items_.get()) << __func__ << " called more than once.";
return NULL; login_items_.reset(LSSharedFileListCreate(
nullptr, kLSSharedFileListSessionLoginItems, nullptr));
DLOG_IF(ERROR, !login_items_.get()) << "Couldn't get a Login Items list.";
return login_items_.get();
} }
base::scoped_nsobject<NSArray> login_items_array( LSSharedFileListRef GetLoginFileList() {
CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL))); DCHECK(login_items_.get()) << "Initialize() failed or not called.";
return login_items_;
NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]]; }
for(NSUInteger i = 0; i < [login_items_array count]; ++i) { // Looks into Shared File Lists corresponding to Login Items for the item
LSSharedFileListItemRef item = // representing the specified bundle. If such an item is found, returns a
reinterpret_cast<LSSharedFileListItemRef>(login_items_array[i]); // retained reference to it. Caller is responsible for releasing the
base::ScopedCFTypeRef<CFErrorRef> error; // reference.
CFURLRef item_url_ref = ScopedCFTypeRef<LSSharedFileListItemRef> GetLoginItemForApp() {
LSSharedFileListItemCopyResolvedURL(item, 0, error.InitializeInto()); DCHECK(login_items_.get()) << "Initialize() failed or not called.";
// This function previously used LSSharedFileListItemResolve(), which could NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
// return a NULL URL even when returning no error. This caused
// <https://crbug.com/760989>. It's not clear one way or the other whether base::scoped_nsobject<NSArray> login_items_array(
// LSSharedFileListItemCopyResolvedURL() shares this behavior, so this check CFToNSCast(LSSharedFileListCopySnapshot(login_items_, nullptr)));
// remains in place.
if (!error && item_url_ref) { for (id login_item in login_items_array.get()) {
ScopedCFTypeRef<CFURLRef> item_url(item_url_ref); LSSharedFileListItemRef item =
if (CFEqual(item_url, url)) { reinterpret_cast<LSSharedFileListItemRef>(login_item);
CFRetain(item); base::ScopedCFTypeRef<CFErrorRef> error;
return item; ScopedCFTypeRef<CFURLRef> item_url(
LSSharedFileListItemCopyResolvedURL(item, 0, error.InitializeInto()));
// This function previously used LSSharedFileListItemResolve(), which
// could return a NULL URL even when returning no error. This caused
// <https://crbug.com/760989>. It's not clear one way or the other whether
// LSSharedFileListItemCopyResolvedURL() shares this behavior, so this
// check remains in place.
if (!error && item_url) {
if (CFEqual(item_url, url)) {
return ScopedCFTypeRef<LSSharedFileListItemRef>(
item, base::scoped_policy::RETAIN);
}
} }
} }
return ScopedCFTypeRef<LSSharedFileListItemRef>();
} }
return NULL; private:
} ScopedCFTypeRef<LSSharedFileListRef> login_items_;
};
bool IsHiddenLoginItem(LSSharedFileListItemRef item) { bool IsHiddenLoginItem(LSSharedFileListItemRef item) {
ScopedCFTypeRef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>( ScopedCFTypeRef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>(
...@@ -143,7 +162,12 @@ bool SetFileBackupExclusion(const FilePath& file_path) { ...@@ -143,7 +162,12 @@ bool SetFileBackupExclusion(const FilePath& file_path) {
} }
bool CheckLoginItemStatus(bool* is_hidden) { bool CheckLoginItemStatus(bool* is_hidden) {
ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp()); LoginItemsFileList login_items;
if (!login_items.Initialize())
return false;
base::ScopedCFTypeRef<LSSharedFileListItemRef> item(
login_items.GetLoginItemForApp());
if (!item.get()) if (!item.get())
return false; return false;
...@@ -154,22 +178,20 @@ bool CheckLoginItemStatus(bool* is_hidden) { ...@@ -154,22 +178,20 @@ bool CheckLoginItemStatus(bool* is_hidden) {
} }
void AddToLoginItems(bool hide_on_startup) { void AddToLoginItems(bool hide_on_startup) {
ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp()); LoginItemsFileList login_items;
if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) { if (!login_items.Initialize())
return; // Already is a login item with required hide flag. return;
}
ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate( base::ScopedCFTypeRef<LSSharedFileListItemRef> item(
NULL, kLSSharedFileListSessionLoginItems, NULL)); login_items.GetLoginItemForApp());
if (!login_items.get()) { if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) {
DLOG(ERROR) << "Couldn't get a Login Items list."; return; // Already is a login item with required hide flag.
return;
} }
// Remove the old item, it has wrong hide flag, we'll create a new one. // Remove the old item, it has wrong hide flag, we'll create a new one.
if (item.get()) { if (item.get()) {
LSSharedFileListItemRemove(login_items, item); LSSharedFileListItemRemove(login_items.GetLoginFileList(), item);
} }
NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]]; NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
...@@ -180,7 +202,7 @@ void AddToLoginItems(bool hide_on_startup) { ...@@ -180,7 +202,7 @@ void AddToLoginItems(bool hide_on_startup) {
ScopedCFTypeRef<LSSharedFileListItemRef> new_item; ScopedCFTypeRef<LSSharedFileListItemRef> new_item;
new_item.reset(LSSharedFileListInsertItemURL( new_item.reset(LSSharedFileListInsertItemURL(
login_items, kLSSharedFileListItemLast, NULL, NULL, login_items.GetLoginFileList(), kLSSharedFileListItemLast, NULL, NULL,
reinterpret_cast<CFURLRef>(url), reinterpret_cast<CFURLRef>(url),
reinterpret_cast<CFDictionaryRef>(properties), NULL)); reinterpret_cast<CFDictionaryRef>(properties), NULL));
...@@ -190,19 +212,16 @@ void AddToLoginItems(bool hide_on_startup) { ...@@ -190,19 +212,16 @@ void AddToLoginItems(bool hide_on_startup) {
} }
void RemoveFromLoginItems() { void RemoveFromLoginItems() {
ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp()); LoginItemsFileList login_items;
if (!item.get()) if (!login_items.Initialize())
return; return;
ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate( base::ScopedCFTypeRef<LSSharedFileListItemRef> item(
NULL, kLSSharedFileListSessionLoginItems, NULL)); login_items.GetLoginItemForApp());
if (!item.get())
if (!login_items.get()) {
DLOG(ERROR) << "Couldn't get a Login Items list.";
return; return;
}
LSSharedFileListItemRemove(login_items, item); LSSharedFileListItemRemove(login_items.GetLoginFileList(), item);
} }
bool WasLaunchedAsLoginOrResumeItem() { bool WasLaunchedAsLoginOrResumeItem() {
...@@ -257,7 +276,12 @@ bool WasLaunchedAsHiddenLoginItem() { ...@@ -257,7 +276,12 @@ bool WasLaunchedAsHiddenLoginItem() {
if (!WasLaunchedAsLoginOrResumeItem()) if (!WasLaunchedAsLoginOrResumeItem())
return false; return false;
ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp()); LoginItemsFileList login_items;
if (!login_items.Initialize())
return false;
base::ScopedCFTypeRef<LSSharedFileListItemRef> item(
login_items.GetLoginItemForApp());
if (!item.get()) { if (!item.get()) {
// OS X can launch items for the resume feature. // OS X can launch items for the resume feature.
return false; return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment