| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Cryptohome client that uses the dbus client interface | 5 // Cryptohome client that uses the dbus client interface |
| 6 | 6 |
| 7 #include <openssl/err.h> |
| 8 #include <openssl/evp.h> |
| 9 #include <openssl/rand.h> |
| 10 #include <openssl/sha.h> |
| 11 #include <termios.h> |
| 12 #include <unistd.h> |
| 13 |
| 7 #include <base/basictypes.h> | 14 #include <base/basictypes.h> |
| 8 #include <base/command_line.h> | 15 #include <base/command_line.h> |
| 9 #include <base/logging.h> | 16 #include <base/logging.h> |
| 10 #include <base/string_util.h> | 17 #include <base/string_util.h> |
| 11 #include <chromeos/dbus/dbus.h> | 18 #include <chromeos/dbus/dbus.h> |
| 12 #include <chromeos/dbus/service_constants.h> | 19 #include <chromeos/dbus/service_constants.h> |
| 13 #include <chromeos/utility.h> | 20 #include <chromeos/utility.h> |
| 21 #include <iostream> |
| 14 | 22 |
| 15 #include <iostream> | 23 #include "bindings/client.h" |
| 16 #include <openssl/err.h> | 24 #include "crypto.h" |
| 17 #include <openssl/evp.h> | 25 #include "secure_blob.h" |
| 18 #include <openssl/rand.h> | 26 #include "username_passkey.h" |
| 19 #include <openssl/sha.h> | |
| 20 #include <termios.h> | |
| 21 #include <unistd.h> | |
| 22 | 27 |
| 23 #include "cryptohome/username_passkey.h" | |
| 24 #include "cryptohome/bindings/client.h" | |
| 25 | 28 |
| 26 namespace switches { | 29 namespace switches { |
| 27 static const char kActionSwitch[] = "action"; | 30 static const char kActionSwitch[] = "action"; |
| 28 static const char *kActions[] = { | 31 static const char *kActions[] = { |
| 29 "mount", | 32 "mount", |
| 33 "mount_guest", |
| 30 "unmount", | 34 "unmount", |
| 31 "is_mounted", | 35 "is_mounted", |
| 32 "test_auth", | 36 "test_auth", |
| 33 "migrate_key", | 37 "migrate_key", |
| 34 "remove", | 38 "remove", |
| 39 "obfuscate_user", |
| 35 NULL }; | 40 NULL }; |
| 36 enum ActionEnum { | 41 enum ActionEnum { |
| 37 ACTION_MOUNT, | 42 ACTION_MOUNT, |
| 43 ACTION_MOUNT_GUEST, |
| 38 ACTION_UNMOUNT, | 44 ACTION_UNMOUNT, |
| 39 ACTION_MOUNTED, | 45 ACTION_MOUNTED, |
| 40 ACTION_TEST_AUTH, | 46 ACTION_TEST_AUTH, |
| 41 ACTION_MIGRATE_KEY, | 47 ACTION_MIGRATE_KEY, |
| 42 ACTION_REMOVE }; | 48 ACTION_REMOVE, |
| 49 ACTION_OBFUSCATE_USER }; |
| 43 static const char kUserSwitch[] = "user"; | 50 static const char kUserSwitch[] = "user"; |
| 44 static const char kPasswordSwitch[] = "password"; | 51 static const char kPasswordSwitch[] = "password"; |
| 45 static const char kOldPasswordSwitch[] = "old_password"; | 52 static const char kOldPasswordSwitch[] = "old_password"; |
| 46 } // namespace switches | 53 } // namespace switches |
| 47 | 54 |
| 48 chromeos::Blob GetSystemSalt(const chromeos::dbus::Proxy& proxy) { | 55 chromeos::Blob GetSystemSalt(const chromeos::dbus::Proxy& proxy) { |
| 49 chromeos::glib::ScopedError error; | 56 chromeos::glib::ScopedError error; |
| 50 GArray* salt; | 57 GArray* salt; |
| 51 GError **errptr = &chromeos::Resetter(&error).lvalue(); | 58 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 52 if (!org_chromium_CryptohomeInterface_get_system_salt(proxy.gproxy(), | 59 if (!org_chromium_CryptohomeInterface_get_system_salt(proxy.gproxy(), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 70 bool GetUsername(const CommandLine* cl, std::string* user_out) { | 77 bool GetUsername(const CommandLine* cl, std::string* user_out) { |
| 71 *user_out = cl->GetSwitchValueASCII(switches::kUserSwitch); | 78 *user_out = cl->GetSwitchValueASCII(switches::kUserSwitch); |
| 72 | 79 |
| 73 if(user_out->length() == 0) { | 80 if(user_out->length() == 0) { |
| 74 LOG(ERROR) << "No user specified (--user=<user>)"; | 81 LOG(ERROR) << "No user specified (--user=<user>)"; |
| 75 return false; | 82 return false; |
| 76 } | 83 } |
| 77 return true; | 84 return true; |
| 78 } | 85 } |
| 79 | 86 |
| 80 bool GetUsernamePassword(const chromeos::dbus::Proxy& proxy, | 87 bool GetPassword(const chromeos::dbus::Proxy& proxy, |
| 81 const CommandLine* cl, | 88 const CommandLine* cl, |
| 82 std::string* user_out, | 89 const std::string& cl_switch, |
| 83 std::string* password_out, | 90 const std::string& prompt, |
| 84 std::string* old_password_out = NULL) { | 91 std::string* password_out) { |
| 85 if(!GetUsername(cl, user_out)) { | 92 std::string password = cl->GetSwitchValueASCII(cl_switch); |
| 86 return false; | |
| 87 } | |
| 88 | 93 |
| 89 std::string password = cl->GetSwitchValueASCII(switches::kPasswordSwitch); | |
| 90 std::string old_password = cl->GetSwitchValueASCII( | |
| 91 switches::kOldPasswordSwitch); | |
| 92 | |
| 93 if(old_password_out != NULL && old_password.length() == 0) { | |
| 94 struct termios original_attr; | |
| 95 struct termios new_attr; | |
| 96 tcgetattr(0, &original_attr); | |
| 97 memcpy(&new_attr, &original_attr, sizeof(new_attr)); | |
| 98 new_attr.c_lflag &= ~(ECHO); | |
| 99 tcsetattr(0, TCSANOW, &new_attr); | |
| 100 std::cout << "Enter old password for <" << (*user_out) << ">: "; | |
| 101 std::cin >> old_password; | |
| 102 std::cout << std::endl; | |
| 103 tcsetattr(0, TCSANOW, &original_attr); | |
| 104 } | |
| 105 if(password.length() == 0) { | 94 if(password.length() == 0) { |
| 106 struct termios original_attr; | 95 struct termios original_attr; |
| 107 struct termios new_attr; | 96 struct termios new_attr; |
| 108 tcgetattr(0, &original_attr); | 97 tcgetattr(0, &original_attr); |
| 109 memcpy(&new_attr, &original_attr, sizeof(new_attr)); | 98 memcpy(&new_attr, &original_attr, sizeof(new_attr)); |
| 110 new_attr.c_lflag &= ~(ECHO); | 99 new_attr.c_lflag &= ~(ECHO); |
| 111 tcsetattr(0, TCSANOW, &new_attr); | 100 tcsetattr(0, TCSANOW, &new_attr); |
| 112 std::cout << "Enter password for <" << (*user_out) << ">: "; | 101 std::cout << prompt << ": "; |
| 113 std::cin >> password; | 102 std::cin >> password; |
| 114 std::cout << std::endl | |
| 115 << "Re-enter password for <" << (*user_out) << ">: "; | |
| 116 std::string verification; | |
| 117 std::cin >> verification; | |
| 118 std::cout << std::endl; | 103 std::cout << std::endl; |
| 119 tcsetattr(0, TCSANOW, &original_attr); | 104 tcsetattr(0, TCSANOW, &original_attr); |
| 120 if(verification != password) { | |
| 121 LOG(ERROR) << "Passwords do not match."; | |
| 122 return false; | |
| 123 } | |
| 124 } | 105 } |
| 125 | 106 |
| 126 std::string trimmed_password; | 107 std::string trimmed_password; |
| 127 TrimString(password, "\r\n", &trimmed_password); | 108 TrimString(password, "\r\n", &trimmed_password); |
| 128 cryptohome::UsernamePasskey up( | 109 cryptohome::SecureBlob passkey; |
| 129 cryptohome::UsernamePasskey::FromUsernamePassword((*user_out).c_str(), | 110 cryptohome::Crypto::PasswordToPasskey(trimmed_password.c_str(), |
| 130 trimmed_password.c_str(), GetSystemSalt(proxy))); | 111 GetSystemSalt(proxy), &passkey); |
| 131 cryptohome::SecureBlob passkey = up.GetPasskey(); | 112 *password_out = std::string(static_cast<char*>(passkey.data()), |
| 132 *password_out = std::string(reinterpret_cast<char*>(&passkey[0]), | |
| 133 passkey.size()); | 113 passkey.size()); |
| 134 if(old_password_out != NULL) { | |
| 135 TrimString(old_password, "\r\n", &trimmed_password); | |
| 136 cryptohome::UsernamePasskey old_up( | |
| 137 cryptohome::UsernamePasskey::FromUsernamePassword((*user_out).c_str(), | |
| 138 trimmed_password.c_str(), GetSystemSalt(proxy))); | |
| 139 passkey = old_up.GetPasskey(); | |
| 140 *old_password_out = std::string(reinterpret_cast<char*>(&passkey[0]), | |
| 141 passkey.size()); | |
| 142 } | |
| 143 | 114 |
| 144 return true; | 115 return true; |
| 145 } | 116 } |
| 146 | 117 |
| 147 bool AskHardQuestion(const std::string& user) { | |
| 148 std::cout << "!!! The password you entered did not unwrap the user's" | |
| 149 << std::endl | |
| 150 << "!!! vault key. If you proceed, the user's cryptohome" | |
| 151 << std::endl | |
| 152 << "!!! will be DELETED and RECREATED." | |
| 153 << std::endl | |
| 154 << "!!!" | |
| 155 << std::endl | |
| 156 << "!!! Re-enter the username at the prompt to create a new" | |
| 157 << std::endl | |
| 158 << "!!! cryptohome for the user." | |
| 159 << std::endl | |
| 160 << "Enter the username <" << user << ">: "; | |
| 161 std::string verification; | |
| 162 std::cin >> verification; | |
| 163 if(user != verification) { | |
| 164 LOG(ERROR) << "Usernames do not match."; | |
| 165 return false; | |
| 166 } | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 bool ConfirmRemove(const std::string& user) { | 118 bool ConfirmRemove(const std::string& user) { |
| 171 std::cout << "!!! Are you sure you want to remove the user's cryptohome?" | 119 std::cout << "!!! Are you sure you want to remove the user's cryptohome?" |
| 172 << std::endl | 120 << std::endl |
| 173 << "!!!" | 121 << "!!!" |
| 174 << std::endl | 122 << std::endl |
| 175 << "!!! Re-enter the username at the prompt to remove the" | 123 << "!!! Re-enter the username at the prompt to remove the" |
| 176 << std::endl | 124 << std::endl |
| 177 << "!!! cryptohome for the user." | 125 << "!!! cryptohome for the user." |
| 178 << std::endl | 126 << std::endl |
| 179 << "Enter the username <" << user << ">: "; | 127 << "Enter the username <" << user << ">: "; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 199 chromeos::dbus::BusConnection bus = chromeos::dbus::GetSystemBusConnection(); | 147 chromeos::dbus::BusConnection bus = chromeos::dbus::GetSystemBusConnection(); |
| 200 chromeos::dbus::Proxy proxy(bus, | 148 chromeos::dbus::Proxy proxy(bus, |
| 201 cryptohome::kCryptohomeServiceName, | 149 cryptohome::kCryptohomeServiceName, |
| 202 cryptohome::kCryptohomeServicePath, | 150 cryptohome::kCryptohomeServicePath, |
| 203 cryptohome::kCryptohomeInterface); | 151 cryptohome::kCryptohomeInterface); |
| 204 DCHECK(proxy.gproxy()) << "Failed to acquire proxy"; | 152 DCHECK(proxy.gproxy()) << "Failed to acquire proxy"; |
| 205 | 153 |
| 206 if (!strcmp(switches::kActions[switches::ACTION_MOUNT], action.c_str())) { | 154 if (!strcmp(switches::kActions[switches::ACTION_MOUNT], action.c_str())) { |
| 207 std::string user, password; | 155 std::string user, password; |
| 208 | 156 |
| 209 if(!GetUsernamePassword(proxy, cl, &user, &password)) { | 157 if (!GetUsername(cl, &user)) { |
| 158 LOG(ERROR) << "No username specified"; |
| 210 return 1; | 159 return 1; |
| 211 } | 160 } |
| 212 | 161 |
| 162 GetPassword(proxy, cl, switches::kPasswordSwitch, |
| 163 StringPrintf("Enter the password for <%s>", user.c_str()), |
| 164 &password); |
| 165 |
| 213 gboolean done = false; | 166 gboolean done = false; |
| 167 gint mount_error = 0; |
| 214 chromeos::glib::ScopedError error; | 168 chromeos::glib::ScopedError error; |
| 215 GError **errptr = &chromeos::Resetter(&error).lvalue(); | 169 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 216 org_chromium_CryptohomeInterface_check_key(proxy.gproxy(), | |
| 217 user.c_str(), | |
| 218 password.c_str(), | |
| 219 &done, | |
| 220 errptr); | |
| 221 if(!done) { | |
| 222 // TODO(fes): Remove when Mount no longer automatically deletes cryptohome | |
| 223 // on passkey failure. | |
| 224 if(!AskHardQuestion(user)) { | |
| 225 return 1; | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 errptr = &chromeos::Resetter(&error).lvalue(); | |
| 230 if (!org_chromium_CryptohomeInterface_mount(proxy.gproxy(), | 170 if (!org_chromium_CryptohomeInterface_mount(proxy.gproxy(), |
| 231 user.c_str(), | 171 user.c_str(), |
| 232 password.c_str(), | 172 password.c_str(), |
| 173 &mount_error, |
| 233 &done, | 174 &done, |
| 234 errptr)) { | 175 errptr)) { |
| 235 LOG(ERROR) << "Mount call failed: " << error->message; | 176 LOG(ERROR) << "Mount call failed: " << error->message |
| 177 << ", with reason code: " << mount_error; |
| 236 } | 178 } |
| 237 LOG_IF(ERROR, !done) << "Mount did not complete?"; | 179 LOG_IF(ERROR, !done) << "Mount did not complete?"; |
| 238 LOG_IF(INFO, done) << "Call completed"; | 180 LOG_IF(INFO, done) << "Call completed"; |
| 181 } else if (!strcmp(switches::kActions[switches::ACTION_MOUNT_GUEST], |
| 182 action.c_str())) { |
| 183 gboolean done = false; |
| 184 gint mount_error = 0; |
| 185 chromeos::glib::ScopedError error; |
| 186 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 187 if (!org_chromium_CryptohomeInterface_mount_guest(proxy.gproxy(), |
| 188 &mount_error, |
| 189 &done, |
| 190 errptr)) { |
| 191 LOG(ERROR) << "MountGuest call failed: " << error->message |
| 192 << ", with reason code: " << mount_error; |
| 193 } |
| 194 LOG_IF(ERROR, !done) << "MountGuest did not complete?"; |
| 195 LOG_IF(INFO, done) << "Call completed"; |
| 239 } else if (!strcmp(switches::kActions[switches::ACTION_TEST_AUTH], | 196 } else if (!strcmp(switches::kActions[switches::ACTION_TEST_AUTH], |
| 240 action.c_str())) { | 197 action.c_str())) { |
| 241 std::string user, password; | 198 std::string user, password; |
| 242 | 199 |
| 243 if(!GetUsernamePassword(proxy, cl, &user, &password)) { | 200 if (!GetUsername(cl, &user)) { |
| 201 LOG(ERROR) << "No username specified"; |
| 244 return 1; | 202 return 1; |
| 245 } | 203 } |
| 246 | 204 |
| 205 GetPassword(proxy, cl, switches::kPasswordSwitch, |
| 206 StringPrintf("Enter the password for <%s>", user.c_str()), |
| 207 &password); |
| 208 |
| 247 gboolean done = false; | 209 gboolean done = false; |
| 248 chromeos::glib::ScopedError error; | 210 chromeos::glib::ScopedError error; |
| 249 GError **errptr = &chromeos::Resetter(&error).lvalue(); | 211 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 250 if (!org_chromium_CryptohomeInterface_check_key(proxy.gproxy(), | 212 if (!org_chromium_CryptohomeInterface_check_key(proxy.gproxy(), |
| 251 user.c_str(), | 213 user.c_str(), |
| 252 password.c_str(), | 214 password.c_str(), |
| 253 &done, | 215 &done, |
| 254 errptr)) { | 216 errptr)) { |
| 255 LOG(ERROR) << "CheckKey call failed: " << error->message; | 217 LOG(ERROR) << "CheckKey call failed: " << error->message; |
| 256 } | 218 } |
| 257 LOG_IF(ERROR, !done) << "CheckKey did not complete?"; | 219 LOG_IF(ERROR, !done) << "CheckKey did not complete?"; |
| 258 LOG_IF(INFO, done) << "Call completed"; | 220 LOG_IF(INFO, done) << "Call completed"; |
| 259 } else if (!strcmp(switches::kActions[switches::ACTION_MIGRATE_KEY], | 221 } else if (!strcmp(switches::kActions[switches::ACTION_MIGRATE_KEY], |
| 260 action.c_str())) { | 222 action.c_str())) { |
| 261 std::string user, password, old_password; | 223 std::string user, password, old_password; |
| 262 | 224 |
| 263 if(!GetUsernamePassword(proxy, cl, &user, &password, &old_password)) { | 225 if (!GetUsername(cl, &user)) { |
| 226 LOG(ERROR) << "No username specified"; |
| 264 return 1; | 227 return 1; |
| 265 } | 228 } |
| 266 | 229 |
| 230 GetPassword(proxy, cl, switches::kPasswordSwitch, |
| 231 StringPrintf("Enter the password for <%s>", user.c_str()), |
| 232 &password); |
| 233 GetPassword(proxy, cl, switches::kOldPasswordSwitch, |
| 234 StringPrintf("Enter the old password for <%s>", user.c_str()), |
| 235 &old_password); |
| 236 |
| 267 gboolean done = false; | 237 gboolean done = false; |
| 268 chromeos::glib::ScopedError error; | 238 chromeos::glib::ScopedError error; |
| 269 GError **errptr = &chromeos::Resetter(&error).lvalue(); | 239 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 270 if (!org_chromium_CryptohomeInterface_migrate_key(proxy.gproxy(), | 240 if (!org_chromium_CryptohomeInterface_migrate_key(proxy.gproxy(), |
| 271 user.c_str(), | 241 user.c_str(), |
| 272 old_password.c_str(), | 242 old_password.c_str(), |
| 273 password.c_str(), | 243 password.c_str(), |
| 274 &done, | 244 &done, |
| 275 errptr)) { | 245 errptr)) { |
| 276 LOG(ERROR) << "MigrateKey call failed: " << error->message; | 246 LOG(ERROR) << "MigrateKey call failed: " << error->message; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 chromeos::glib::ScopedError error; | 287 chromeos::glib::ScopedError error; |
| 318 GError **errptr = &chromeos::Resetter(&error).lvalue(); | 288 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 319 gboolean done = false; | 289 gboolean done = false; |
| 320 if (!org_chromium_CryptohomeInterface_is_mounted(proxy.gproxy(), | 290 if (!org_chromium_CryptohomeInterface_is_mounted(proxy.gproxy(), |
| 321 &done, | 291 &done, |
| 322 errptr)) { | 292 errptr)) { |
| 323 LOG(ERROR) << "IsMounted call failed: " << error->message; | 293 LOG(ERROR) << "IsMounted call failed: " << error->message; |
| 324 } | 294 } |
| 325 std::cout << done << std::endl; | 295 std::cout << done << std::endl; |
| 326 | 296 |
| 297 } else if (!strcmp(switches::kActions[switches::ACTION_OBFUSCATE_USER], |
| 298 action.c_str())) { |
| 299 std::string user; |
| 300 |
| 301 if(!GetUsername(cl, &user)) { |
| 302 return 1; |
| 303 } |
| 304 |
| 305 cryptohome::UsernamePasskey up(user.c_str(), cryptohome::SecureBlob()); |
| 306 LOG(INFO) << up.GetObfuscatedUsername(GetSystemSalt(proxy)); |
| 327 } else { | 307 } else { |
| 328 LOG(ERROR) << "Unknown action or no action given. Available actions: "; | 308 LOG(ERROR) << "Unknown action or no action given. Available actions: "; |
| 329 for(int i = 0; /* loop forever */; i++) { | 309 for(int i = 0; /* loop forever */; i++) { |
| 330 if(!switches::kActions[i]) { | 310 if(!switches::kActions[i]) { |
| 331 break; | 311 break; |
| 332 } | 312 } |
| 333 LOG(ERROR) << " --action=" << switches::kActions[i]; | 313 LOG(ERROR) << " --action=" << switches::kActions[i]; |
| 334 } | 314 } |
| 335 } | 315 } |
| 336 return 0; | 316 return 0; |
| 337 } | 317 } |
| OLD | NEW |