diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-25 16:21:57 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-25 16:21:57 +0000 |
commit | 82810fe1c2733add9da822ee5434c46d123a4fc2 (patch) | |
tree | 0402394507c107f42ae3d4c67a3eb5f5da892a16 /chrome/browser/shell_integration_linux.cc | |
parent | d0a100a843b5a1826ead775e06ed008befe5c9f3 (diff) | |
download | chromium_src-82810fe1c2733add9da822ee5434c46d123a4fc2.zip chromium_src-82810fe1c2733add9da822ee5434c46d123a4fc2.tar.gz chromium_src-82810fe1c2733add9da822ee5434c46d123a4fc2.tar.bz2 |
Improve desktop shortcut creation:
- remove more comments (which generally only apply to the browser itself)
- add #!/usr/bin/env xdg-open shebang
- make the .desktop file placed on the desktop executable
- add more tests to make sure we're still secure
TEST=Covered by unit_tests.
BUG=22589
Review URL: http://codereview.chromium.org/232003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27194 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/shell_integration_linux.cc')
-rw-r--r-- | chrome/browser/shell_integration_linux.cc | 100 |
1 files changed, 72 insertions, 28 deletions
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc index 78c8443..dab372f 100644 --- a/chrome/browser/shell_integration_linux.cc +++ b/chrome/browser/shell_integration_linux.cc @@ -14,6 +14,7 @@ #include <vector> #include "base/command_line.h" +#include "base/eintr_wrapper.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/message_loop.h" @@ -117,16 +118,65 @@ class CreateDesktopShortcutTask : public Task { if (!GetDesktopShortcutTemplate(&template_contents)) return; + FilePath shortcut_filename = + ShellIntegration::GetDesktopShortcutFilename(shortcut_info_.url); + std::string contents = ShellIntegration::GetDesktopFileContents( template_contents, shortcut_info_.url, shortcut_info_.title); + if (shortcut_info_.create_on_desktop) + CreateOnDesktop(shortcut_filename, contents); + + if (shortcut_info_.create_in_applications_menu) + CreateInApplicationsMenu(shortcut_filename, contents); + } + + private: + void CreateOnDesktop(const FilePath& shortcut_filename, + const std::string& contents) { + // TODO(phajdan.jr): Report errors from this function, possibly as infobars. + + // Make sure that we will later call openat in a secure way. + DCHECK_EQ(shortcut_filename.BaseName().value(), shortcut_filename.value()); + + FilePath desktop_path; + if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) + return; + + int desktop_fd = open(desktop_path.value().c_str(), O_RDONLY | O_DIRECTORY); + if (desktop_fd < 0) + return; + + int fd = openat(desktop_fd, shortcut_filename.value().c_str(), + O_CREAT | O_EXCL | O_WRONLY, + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (fd < 0) { + HANDLE_EINTR(close(desktop_fd)); + return; + } + + ssize_t bytes_written = file_util::WriteFileDescriptor(fd, contents.data(), + contents.length()); + HANDLE_EINTR(close(fd)); + + if (bytes_written != static_cast<ssize_t>(contents.length())) { + // Delete the file. No shortuct is better than corrupted one. Use unlinkat + // to make sure we're deleting the file in the directory we think we are. + // Even if an attacker manager to put something other at + // |shortcut_filename| we'll just undo his action. + unlinkat(desktop_fd, shortcut_filename.value().c_str(), 0); + } + + HANDLE_EINTR(close(desktop_fd)); + } + + void CreateInApplicationsMenu(const FilePath& shortcut_filename, + const std::string& contents) { + // TODO(phajdan.jr): Report errors from this function, possibly as infobars. ScopedTempDir temp_dir; if (!temp_dir.CreateUniqueTempDir()) return; - FilePath shortcut_filename = - ShellIntegration::GetDesktopShortcutFilename(shortcut_info_.url); - FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), @@ -135,32 +185,19 @@ class CreateDesktopShortcutTask : public Task { if (bytes_written != static_cast<int>(contents.length())) return; - if (shortcut_info_.create_on_desktop) { - FilePath desktop_path; - if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) - return; - desktop_path = desktop_path.Append(shortcut_filename); - - if (!file_util::PathExists(desktop_path)) - file_util::CopyFile(temp_file_path, desktop_path); - } - - if (shortcut_info_.create_in_applications_menu) { - std::vector<std::string> argv; - argv.push_back("xdg-desktop-menu"); - argv.push_back("install"); + std::vector<std::string> argv; + argv.push_back("xdg-desktop-menu"); + argv.push_back("install"); - // Always install in user mode, even if someone runs the browser as root - // (people do that). - argv.push_back("--mode"); - argv.push_back("user"); + // Always install in user mode, even if someone runs the browser as root + // (people do that). + argv.push_back("--mode"); + argv.push_back("user"); - argv.push_back(temp_file_path.value()); - LaunchXdgUtility(argv); - } + argv.push_back(temp_file_path.value()); + LaunchXdgUtility(argv); } - private: const ShellIntegration::ShortcutInfo shortcut_info_; DISALLOW_COPY_AND_ASSIGN(CreateDesktopShortcutTask); @@ -226,7 +263,9 @@ std::string ShellIntegration::GetDesktopFileContents( const std::string& template_contents, const GURL& url, const string16& title) { // See http://standards.freedesktop.org/desktop-entry-spec/latest/ - std::string output_buffer; + // Although not required by the spec, Nautilus on Ubuntu Karmic creates its + // launchers with an xdg-open shebang. Follow that convention. + std::string output_buffer("#!/usr/bin/env xdg-open\n"); StringTokenizer tokenizer(template_contents, "\n"); while (tokenizer.GetNext()) { // TODO(phajdan.jr): Add the icon. @@ -243,7 +282,10 @@ std::string ShellIntegration::GetDesktopFileContents( std::string app_switch(StringPrintf("\"--%s=%s\"", WideToUTF8(app_switch_wide).c_str(), url.spec().c_str())); + // Sanitize the command line string. ReplaceSubstringsAfterOffset(&app_switch, 0, "%", "%%"); + ReplaceSubstringsAfterOffset(&app_switch, 0, ";", ""); + ReplaceSubstringsAfterOffset(&app_switch, 0, "$", ""); output_buffer += std::string("Exec=") + final_path + app_switch + "\n"; } else if (tokenizer.token().substr(0, 5) == "Name=") { std::string final_title = UTF16ToUTF8(title); @@ -255,8 +297,10 @@ std::string ShellIntegration::GetDesktopFileContents( final_title.find("\r") != std::string::npos) final_title = url.spec(); output_buffer += StringPrintf("Name=%s\n", final_title.c_str()); - } else if (tokenizer.token().substr(0, 8) == "Comment=") { - // Skip the line. + } else if (tokenizer.token().substr(0, 11) == "GenericName" || + tokenizer.token().substr(0, 7) == "Comment" || + tokenizer.token().substr(0, 1) == "#") { + // Skip comment lines. } else { output_buffer += tokenizer.token() + "\n"; } |