Index: src/platform/cryptohome/cryptohome.cc |
diff --git a/src/platform/cryptohome/cryptohome.cc b/src/platform/cryptohome/cryptohome.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cdc9c5b768a41849716e4e1c2afd4f6c73a3bc36 |
--- /dev/null |
+++ b/src/platform/cryptohome/cryptohome.cc |
@@ -0,0 +1,337 @@ |
+// Copyright (c) 2009 The Chromium OS Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+// |
+// Cryptohome client that uses the dbus client interface |
+ |
+#include <base/basictypes.h> |
+#include <base/command_line.h> |
+#include <base/logging.h> |
+#include <base/string_util.h> |
+#include <chromeos/dbus/dbus.h> |
+#include <chromeos/dbus/service_constants.h> |
+#include <chromeos/utility.h> |
+ |
+#include <iostream> |
+#include <openssl/err.h> |
+#include <openssl/evp.h> |
+#include <openssl/rand.h> |
+#include <openssl/sha.h> |
+#include <termios.h> |
+#include <unistd.h> |
+ |
+#include "cryptohome/username_passkey.h" |
+#include "cryptohome/bindings/client.h" |
+ |
+namespace switches { |
+ static const char kActionSwitch[] = "action"; |
+ static const char *kActions[] = { |
+ "mount", |
+ "unmount", |
+ "is_mounted", |
+ "test_auth", |
+ "migrate_key", |
+ "remove", |
+ NULL }; |
+ enum ActionEnum { |
+ ACTION_MOUNT, |
+ ACTION_UNMOUNT, |
+ ACTION_MOUNTED, |
+ ACTION_TEST_AUTH, |
+ ACTION_MIGRATE_KEY, |
+ ACTION_REMOVE }; |
+ static const char kUserSwitch[] = "user"; |
+ static const char kPasswordSwitch[] = "password"; |
+ static const char kOldPasswordSwitch[] = "old_password"; |
+} // namespace switches |
+ |
+chromeos::Blob GetSystemSalt(const chromeos::dbus::Proxy& proxy) { |
+ chromeos::glib::ScopedError error; |
+ GArray* salt; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ if (!org_chromium_CryptohomeInterface_get_system_salt(proxy.gproxy(), |
+ &salt, |
+ errptr)) { |
+ LOG(ERROR) << "GetSystemSalt failed: " << error->message; |
+ return chromeos::Blob(); |
+ } |
+ |
+ chromeos::Blob system_salt; |
+ system_salt.resize(salt->len); |
+ if(system_salt.size() == salt->len) { |
+ memcpy(&system_salt[0], static_cast<const void*>(salt->data), salt->len); |
+ } else { |
+ system_salt.clear(); |
+ } |
+ g_array_free(salt, false); |
+ return system_salt; |
+} |
+ |
+bool GetUsername(const CommandLine* cl, std::string* user_out) { |
+ *user_out = cl->GetSwitchValueASCII(switches::kUserSwitch); |
+ |
+ if(user_out->length() == 0) { |
+ LOG(ERROR) << "No user specified (--user=<user>)"; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool GetUsernamePassword(const chromeos::dbus::Proxy& proxy, |
+ const CommandLine* cl, |
+ std::string* user_out, |
+ std::string* password_out, |
+ std::string* old_password_out = NULL) { |
+ if(!GetUsername(cl, user_out)) { |
+ return false; |
+ } |
+ |
+ std::string password = cl->GetSwitchValueASCII(switches::kPasswordSwitch); |
+ std::string old_password = cl->GetSwitchValueASCII( |
+ switches::kOldPasswordSwitch); |
+ |
+ if(old_password_out != NULL && old_password.length() == 0) { |
+ struct termios original_attr; |
+ struct termios new_attr; |
+ tcgetattr(0, &original_attr); |
+ memcpy(&new_attr, &original_attr, sizeof(new_attr)); |
+ new_attr.c_lflag &= ~(ECHO); |
+ tcsetattr(0, TCSANOW, &new_attr); |
+ std::cout << "Enter old password for <" << (*user_out) << ">: "; |
+ std::cin >> old_password; |
+ std::cout << std::endl; |
+ tcsetattr(0, TCSANOW, &original_attr); |
+ } |
+ if(password.length() == 0) { |
+ struct termios original_attr; |
+ struct termios new_attr; |
+ tcgetattr(0, &original_attr); |
+ memcpy(&new_attr, &original_attr, sizeof(new_attr)); |
+ new_attr.c_lflag &= ~(ECHO); |
+ tcsetattr(0, TCSANOW, &new_attr); |
+ std::cout << "Enter password for <" << (*user_out) << ">: "; |
+ std::cin >> password; |
+ std::cout << std::endl |
+ << "Re-enter password for <" << (*user_out) << ">: "; |
+ std::string verification; |
+ std::cin >> verification; |
+ std::cout << std::endl; |
+ tcsetattr(0, TCSANOW, &original_attr); |
+ if(verification != password) { |
+ LOG(ERROR) << "Passwords do not match."; |
+ return false; |
+ } |
+ } |
+ |
+ std::string trimmed_password; |
+ TrimString(password, "\r\n", &trimmed_password); |
+ cryptohome::UsernamePasskey up( |
+ cryptohome::UsernamePasskey::FromUsernamePassword((*user_out).c_str(), |
+ trimmed_password.c_str(), GetSystemSalt(proxy))); |
+ cryptohome::SecureBlob passkey = up.GetPasskey(); |
+ *password_out = std::string(reinterpret_cast<char*>(&passkey[0]), |
+ passkey.size()); |
+ if(old_password_out != NULL) { |
+ TrimString(old_password, "\r\n", &trimmed_password); |
+ cryptohome::UsernamePasskey old_up( |
+ cryptohome::UsernamePasskey::FromUsernamePassword((*user_out).c_str(), |
+ trimmed_password.c_str(), GetSystemSalt(proxy))); |
+ passkey = old_up.GetPasskey(); |
+ *old_password_out = std::string(reinterpret_cast<char*>(&passkey[0]), |
+ passkey.size()); |
+ } |
+ |
+ return true; |
+} |
+ |
+bool AskHardQuestion(const std::string& user) { |
+ std::cout << "!!! The password you entered did not unwrap the user's" |
+ << std::endl |
+ << "!!! vault key. If you proceed, the user's cryptohome" |
+ << std::endl |
+ << "!!! will be DELETED and RECREATED." |
+ << std::endl |
+ << "!!!" |
+ << std::endl |
+ << "!!! Re-enter the username at the prompt to create a new" |
+ << std::endl |
+ << "!!! cryptohome for the user." |
+ << std::endl |
+ << "Enter the username <" << user << ">: "; |
+ std::string verification; |
+ std::cin >> verification; |
+ if(user != verification) { |
+ LOG(ERROR) << "Usernames do not match."; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool ConfirmRemove(const std::string& user) { |
+ std::cout << "!!! Are you sure you want to remove the user's cryptohome?" |
+ << std::endl |
+ << "!!!" |
+ << std::endl |
+ << "!!! Re-enter the username at the prompt to remove the" |
+ << std::endl |
+ << "!!! cryptohome for the user." |
+ << std::endl |
+ << "Enter the username <" << user << ">: "; |
+ std::string verification; |
+ std::cin >> verification; |
+ if(user != verification) { |
+ LOG(ERROR) << "Usernames do not match."; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+int main(int argc, char **argv) { |
+ CommandLine::Init(argc, argv); |
+ logging::InitLogging(NULL, |
+ logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, |
+ logging::DONT_LOCK_LOG_FILE, |
+ logging::APPEND_TO_OLD_LOG_FILE); |
+ |
+ CommandLine *cl = CommandLine::ForCurrentProcess(); |
+ std::string action = cl->GetSwitchValueASCII(switches::kActionSwitch); |
+ g_type_init(); |
+ chromeos::dbus::BusConnection bus = chromeos::dbus::GetSystemBusConnection(); |
+ chromeos::dbus::Proxy proxy(bus, |
+ cryptohome::kCryptohomeServiceName, |
+ cryptohome::kCryptohomeServicePath, |
+ cryptohome::kCryptohomeInterface); |
+ DCHECK(proxy.gproxy()) << "Failed to acquire proxy"; |
+ |
+ if (!strcmp(switches::kActions[switches::ACTION_MOUNT], action.c_str())) { |
+ std::string user, password; |
+ |
+ if(!GetUsernamePassword(proxy, cl, &user, &password)) { |
+ return 1; |
+ } |
+ |
+ gboolean done = false; |
+ chromeos::glib::ScopedError error; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ org_chromium_CryptohomeInterface_check_key(proxy.gproxy(), |
+ user.c_str(), |
+ password.c_str(), |
+ &done, |
+ errptr); |
+ if(!done) { |
+ // TODO(fes): Remove when Mount no longer automatically deletes cryptohome |
+ // on passkey failure. |
+ if(!AskHardQuestion(user)) { |
+ return 1; |
+ } |
+ } |
+ |
+ errptr = &chromeos::Resetter(&error).lvalue(); |
+ if (!org_chromium_CryptohomeInterface_mount(proxy.gproxy(), |
+ user.c_str(), |
+ password.c_str(), |
+ &done, |
+ errptr)) { |
+ LOG(ERROR) << "Mount call failed: " << error->message; |
+ } |
+ LOG_IF(ERROR, !done) << "Mount did not complete?"; |
+ LOG_IF(INFO, done) << "Call completed"; |
+ } else if (!strcmp(switches::kActions[switches::ACTION_TEST_AUTH], |
+ action.c_str())) { |
+ std::string user, password; |
+ |
+ if(!GetUsernamePassword(proxy, cl, &user, &password)) { |
+ return 1; |
+ } |
+ |
+ gboolean done = false; |
+ chromeos::glib::ScopedError error; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ if (!org_chromium_CryptohomeInterface_check_key(proxy.gproxy(), |
+ user.c_str(), |
+ password.c_str(), |
+ &done, |
+ errptr)) { |
+ LOG(ERROR) << "CheckKey call failed: " << error->message; |
+ } |
+ LOG_IF(ERROR, !done) << "CheckKey did not complete?"; |
+ LOG_IF(INFO, done) << "Call completed"; |
+ } else if (!strcmp(switches::kActions[switches::ACTION_MIGRATE_KEY], |
+ action.c_str())) { |
+ std::string user, password, old_password; |
+ |
+ if(!GetUsernamePassword(proxy, cl, &user, &password, &old_password)) { |
+ return 1; |
+ } |
+ |
+ gboolean done = false; |
+ chromeos::glib::ScopedError error; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ if (!org_chromium_CryptohomeInterface_migrate_key(proxy.gproxy(), |
+ user.c_str(), |
+ old_password.c_str(), |
+ password.c_str(), |
+ &done, |
+ errptr)) { |
+ LOG(ERROR) << "MigrateKey call failed: " << error->message; |
+ } |
+ LOG_IF(ERROR, !done) << "MigrateKey did not complete?"; |
+ LOG_IF(INFO, done) << "Call completed"; |
+ } else if (!strcmp(switches::kActions[switches::ACTION_REMOVE], |
+ action.c_str())) { |
+ std::string user; |
+ |
+ if(!GetUsername(cl, &user)) { |
+ return 1; |
+ } |
+ |
+ if(!ConfirmRemove(user)) { |
+ return 1; |
+ } |
+ |
+ gboolean done = false; |
+ chromeos::glib::ScopedError error; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ if (!org_chromium_CryptohomeInterface_remove(proxy.gproxy(), |
+ user.c_str(), |
+ &done, |
+ errptr)) { |
+ LOG(ERROR) << "Remove call failed: " << error->message; |
+ } |
+ LOG_IF(ERROR, !done) << "Remove did not complete?"; |
+ LOG_IF(INFO, done) << "Call completed"; |
+ } else if (!strcmp(switches::kActions[switches::ACTION_UNMOUNT], |
+ action.c_str())) { |
+ chromeos::glib::ScopedError error; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ gboolean done = false; |
+ if (!org_chromium_CryptohomeInterface_unmount(proxy.gproxy(), |
+ &done, |
+ errptr)) { |
+ LOG(ERROR) << "Unmount call failed: " << error->message; |
+ } |
+ LOG_IF(ERROR, !done) << "Unmount did not complete?"; |
+ LOG_IF(INFO, done) << "Call completed"; |
+ } else if (!strcmp(switches::kActions[switches::ACTION_MOUNTED], |
+ action.c_str())) { |
+ chromeos::glib::ScopedError error; |
+ GError **errptr = &chromeos::Resetter(&error).lvalue(); |
+ gboolean done = false; |
+ if (!org_chromium_CryptohomeInterface_is_mounted(proxy.gproxy(), |
+ &done, |
+ errptr)) { |
+ LOG(ERROR) << "IsMounted call failed: " << error->message; |
+ } |
+ std::cout << done << std::endl; |
+ |
+ } else { |
+ LOG(ERROR) << "Unknown action or no action given. Available actions: "; |
+ for(int i = 0; /* loop forever */; i++) { |
+ if(!switches::kActions[i]) { |
+ break; |
+ } |
+ LOG(ERROR) << " --action=" << switches::kActions[i]; |
+ } |
+ } |
+ return 0; |
+} |