blob: 3be8806ae36aeac60f7eb1cc10dd5e2ef03528ab [file] [log] [blame]
cfroussios3b5a4e42016-05-31 11:02:181// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/os_crypt/key_storage_linux.h"
6
Christos Froussios4e170cb2017-12-01 09:42:337#include "base/bind.h"
cfroussios3ea4c692016-07-18 19:15:148#include "base/environment.h"
cfroussios3ea4c692016-07-18 19:15:149#include "base/logging.h"
10#include "base/nix/xdg_util.h"
Christos Froussios4e170cb2017-12-01 09:42:3311#include "base/sequenced_task_runner.h"
12#include "base/synchronization/waitable_event.h"
13#include "base/task_runner_util.h"
14#include "base/threading/thread_restrictions.h"
Christos Froussios494196d2017-07-14 10:10:0415#include "components/os_crypt/key_storage_config_linux.h"
cfroussios2f05d7f2016-08-17 15:58:5016#include "components/os_crypt/key_storage_util_linux.h"
cfroussios3ea4c692016-07-18 19:15:1417
18#if defined(USE_LIBSECRET)
cfroussios3b5a4e42016-05-31 11:02:1819#include "components/os_crypt/key_storage_libsecret.h"
cfroussios3ea4c692016-07-18 19:15:1420#endif
cfroussiosb013c15b2016-09-03 01:10:1621#if defined(USE_KEYRING)
22#include "components/os_crypt/key_storage_keyring.h"
23#endif
cfroussios2e6729a42016-07-26 09:18:1224#if defined(USE_KWALLET)
25#include "components/os_crypt/key_storage_kwallet.h"
26#endif
27
thestigc0bfd642016-08-22 18:10:3528#if defined(GOOGLE_CHROME_BUILD)
cfroussios2e6729a42016-07-26 09:18:1229const char KeyStorageLinux::kFolderName[] = "Chrome Keys";
30const char KeyStorageLinux::kKey[] = "Chrome Safe Storage";
31#else
32const char KeyStorageLinux::kFolderName[] = "Chromium Keys";
33const char KeyStorageLinux::kKey[] = "Chromium Safe Storage";
34#endif
35
Christos Froussios4e170cb2017-12-01 09:42:3336namespace {
37
38// Copies the password value from |result| to |password| and notifies on
39// |on_password_received| that the result is ready.
40void OnPasswordReceived(base::WaitableEvent* on_password_received,
41 std::string* password,
42 const std::string& result) {
43 *password = result;
44 if (on_password_received)
45 on_password_received->Signal();
46}
47
48// Copies the initialisation result from |result| to |success| and notifies on
49// |on_initialized| that the result is ready.
50void OnInitialized(base::WaitableEvent* on_initialized,
51 bool* success,
52 const bool& result) {
53 *success = result;
54 if (on_initialized)
55 on_initialized->Signal();
56}
57
58} // namespace
59
cfroussios3ea4c692016-07-18 19:15:1460// static
Christos Froussios494196d2017-07-14 10:10:0461std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateService(
62 const os_crypt::Config& config) {
slana881a862016-09-09 21:36:0763#if defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
cfroussios2f05d7f2016-08-17 15:58:5064 // Select a backend.
Christos Froussios494196d2017-07-14 10:10:0465 bool use_backend = !config.should_use_preference ||
66 os_crypt::GetBackendUse(config.user_data_path);
cfroussios2f05d7f2016-08-17 15:58:5067 std::unique_ptr<base::Environment> env(base::Environment::Create());
68 base::nix::DesktopEnvironment desktop_env =
69 base::nix::GetDesktopEnvironment(env.get());
70 os_crypt::SelectedLinuxBackend selected_backend =
Christos Froussios494196d2017-07-14 10:10:0471 os_crypt::SelectBackend(config.store, use_backend, desktop_env);
cfroussios3b5a4e42016-05-31 11:02:1872
Christos Froussios985d1aac2017-11-09 11:01:0773 // TODO(crbug.com/782851) Schedule the initialisation on each backend's
74 // favourite thread.
75
cfroussios2f05d7f2016-08-17 15:58:5076 // Try initializing the selected backend.
cfroussiosb013c15b2016-09-03 01:10:1677 // In case of GNOME_ANY, prefer Libsecret
cfroussios3ea4c692016-07-18 19:15:1478 std::unique_ptr<KeyStorageLinux> key_storage;
cfroussiosb013c15b2016-09-03 01:10:1679
80#if defined(USE_LIBSECRET)
cfroussios2f05d7f2016-08-17 15:58:5081 if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
82 selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) {
cfroussios3ea4c692016-07-18 19:15:1483 key_storage.reset(new KeyStorageLibsecret());
Christos Froussios4e170cb2017-12-01 09:42:3384 if (key_storage->WaitForInitOnTaskRunner()) {
cfroussios3ea4c692016-07-18 19:15:1485 VLOG(1) << "OSCrypt using Libsecret as backend.";
86 return key_storage;
87 }
cfroussiosb013c15b2016-09-03 01:10:1688 }
slana881a862016-09-09 21:36:0789#endif // defined(USE_LIBSECRET)
cfroussiosb013c15b2016-09-03 01:10:1690
91#if defined(USE_KEYRING)
92 if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
93 selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) {
Christos Froussios494196d2017-07-14 10:10:0494 key_storage.reset(new KeyStorageKeyring(config.main_thread_runner));
Christos Froussios4e170cb2017-12-01 09:42:3395 if (key_storage->WaitForInitOnTaskRunner()) {
cfroussiosb013c15b2016-09-03 01:10:1696 VLOG(1) << "OSCrypt using Keyring as backend.";
97 return key_storage;
98 }
99 }
slana881a862016-09-09 21:36:07100#endif // defined(USE_KEYRING)
cfroussiosb013c15b2016-09-03 01:10:16101
cfroussios2e6729a42016-07-26 09:18:12102#if defined(USE_KWALLET)
cfroussiosb013c15b2016-09-03 01:10:16103 if (selected_backend == os_crypt::SelectedLinuxBackend::KWALLET ||
104 selected_backend == os_crypt::SelectedLinuxBackend::KWALLET5) {
Christos Froussios494196d2017-07-14 10:10:04105 DCHECK(!config.product_name.empty());
cfroussios2f05d7f2016-08-17 15:58:50106 base::nix::DesktopEnvironment used_desktop_env =
107 selected_backend == os_crypt::SelectedLinuxBackend::KWALLET
108 ? base::nix::DESKTOP_ENVIRONMENT_KDE4
109 : base::nix::DESKTOP_ENVIRONMENT_KDE5;
cfroussios2e6729a42016-07-26 09:18:12110 key_storage.reset(
Christos Froussios494196d2017-07-14 10:10:04111 new KeyStorageKWallet(used_desktop_env, config.product_name));
Christos Froussios4e170cb2017-12-01 09:42:33112 if (key_storage->WaitForInitOnTaskRunner()) {
cfroussios2e6729a42016-07-26 09:18:12113 VLOG(1) << "OSCrypt using KWallet as backend.";
114 return key_storage;
115 }
cfroussios3ea4c692016-07-18 19:15:14116 }
slana881a862016-09-09 21:36:07117#endif // defined(USE_KWALLET)
118#endif // defined(USE_LIBSECRET) || defined(USE_KEYRING) ||
119 // defined(USE_KWALLET)
cfroussios3b5a4e42016-05-31 11:02:18120
cfroussios3ea4c692016-07-18 19:15:14121 // The appropriate store was not available.
cfroussios6b340f812017-07-06 15:05:10122 VLOG(1) << "OSCrypt did not initialize a backend.";
cfroussios3b5a4e42016-05-31 11:02:18123 return nullptr;
124}
Christos Froussios985d1aac2017-11-09 11:01:07125
Christos Froussios4e170cb2017-12-01 09:42:33126bool KeyStorageLinux::WaitForInitOnTaskRunner() {
127 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_sync_primitives;
128 base::SequencedTaskRunner* task_runner = GetTaskRunner();
129
130 // We don't need to change threads if the backend has no preference or if we
131 // are already on the right thread.
132 if (!task_runner || task_runner->RunsTasksInCurrentSequence())
133 return Init();
134
135 base::WaitableEvent initialized(
136 base::WaitableEvent::ResetPolicy::MANUAL,
137 base::WaitableEvent::InitialState::NOT_SIGNALED);
138 bool success;
139 PostTaskAndReplyWithResult(
140 task_runner, FROM_HERE,
141 base::BindOnce(&KeyStorageLinux::Init, base::Unretained(this)),
142 base::BindOnce(&OnInitialized, &initialized, &success));
143 initialized.Wait();
144 return success;
145}
146
Christos Froussios985d1aac2017-11-09 11:01:07147std::string KeyStorageLinux::GetKey() {
Christos Froussios4e170cb2017-12-01 09:42:33148 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_sync_primitives;
149 base::SequencedTaskRunner* task_runner = GetTaskRunner();
150
151 // We don't need to change threads if the backend has no preference or if we
152 // are already on the right thread.
153 if (!task_runner || task_runner->RunsTasksInCurrentSequence())
154 return GetKeyImpl();
155
156 base::WaitableEvent password_loaded(
157 base::WaitableEvent::ResetPolicy::MANUAL,
158 base::WaitableEvent::InitialState::NOT_SIGNALED);
159 std::string password;
160 PostTaskAndReplyWithResult(
161 task_runner, FROM_HERE,
162 base::BindOnce(&KeyStorageLinux::GetKeyImpl, base::Unretained(this)),
163 base::BindOnce(&OnPasswordReceived, &password_loaded, &password));
164 password_loaded.Wait();
165 return password;
166}
167
168base::SequencedTaskRunner* KeyStorageLinux::GetTaskRunner() {
169 return nullptr;
Christos Froussios985d1aac2017-11-09 11:01:07170}