OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 // |
| 5 // Cryptohome client that uses the dbus client interface |
| 6 |
| 7 #include <base/basictypes.h> |
| 8 #include <base/command_line.h> |
| 9 #include <base/logging.h> |
| 10 #include <base/string_util.h> |
| 11 #include <chromeos/dbus/dbus.h> |
| 12 #include <chromeos/dbus/service_constants.h> |
| 13 #include <chromeos/utility.h> |
| 14 |
| 15 #include <iostream> |
| 16 #include <openssl/err.h> |
| 17 #include <openssl/evp.h> |
| 18 #include <openssl/rand.h> |
| 19 #include <openssl/sha.h> |
| 20 #include <termios.h> |
| 21 #include <unistd.h> |
| 22 |
| 23 #include "cryptohome/username_passkey.h" |
| 24 #include "cryptohome/bindings/client.h" |
| 25 |
| 26 namespace switches { |
| 27 static const char kActionSwitch[] = "action"; |
| 28 static const char *kActions[] = { |
| 29 "mount", |
| 30 "unmount", |
| 31 "is_mounted", |
| 32 "test_auth", |
| 33 "migrate_key", |
| 34 "remove", |
| 35 NULL }; |
| 36 enum ActionEnum { |
| 37 ACTION_MOUNT, |
| 38 ACTION_UNMOUNT, |
| 39 ACTION_MOUNTED, |
| 40 ACTION_TEST_AUTH, |
| 41 ACTION_MIGRATE_KEY, |
| 42 ACTION_REMOVE }; |
| 43 static const char kUserSwitch[] = "user"; |
| 44 static const char kPasswordSwitch[] = "password"; |
| 45 static const char kOldPasswordSwitch[] = "old_password"; |
| 46 } // namespace switches |
| 47 |
| 48 chromeos::Blob GetSystemSalt(const chromeos::dbus::Proxy& proxy) { |
| 49 chromeos::glib::ScopedError error; |
| 50 GArray* salt; |
| 51 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 52 if (!org_chromium_CryptohomeInterface_get_system_salt(proxy.gproxy(), |
| 53 &salt, |
| 54 errptr)) { |
| 55 LOG(ERROR) << "GetSystemSalt failed: " << error->message; |
| 56 return chromeos::Blob(); |
| 57 } |
| 58 |
| 59 chromeos::Blob system_salt; |
| 60 system_salt.resize(salt->len); |
| 61 if(system_salt.size() == salt->len) { |
| 62 memcpy(&system_salt[0], static_cast<const void*>(salt->data), salt->len); |
| 63 } else { |
| 64 system_salt.clear(); |
| 65 } |
| 66 g_array_free(salt, false); |
| 67 return system_salt; |
| 68 } |
| 69 |
| 70 bool GetUsername(const CommandLine* cl, std::string* user_out) { |
| 71 *user_out = cl->GetSwitchValueASCII(switches::kUserSwitch); |
| 72 |
| 73 if(user_out->length() == 0) { |
| 74 LOG(ERROR) << "No user specified (--user=<user>)"; |
| 75 return false; |
| 76 } |
| 77 return true; |
| 78 } |
| 79 |
| 80 bool GetUsernamePassword(const chromeos::dbus::Proxy& proxy, |
| 81 const CommandLine* cl, |
| 82 std::string* user_out, |
| 83 std::string* password_out, |
| 84 std::string* old_password_out = NULL) { |
| 85 if(!GetUsername(cl, user_out)) { |
| 86 return false; |
| 87 } |
| 88 |
| 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) { |
| 106 struct termios original_attr; |
| 107 struct termios new_attr; |
| 108 tcgetattr(0, &original_attr); |
| 109 memcpy(&new_attr, &original_attr, sizeof(new_attr)); |
| 110 new_attr.c_lflag &= ~(ECHO); |
| 111 tcsetattr(0, TCSANOW, &new_attr); |
| 112 std::cout << "Enter password for <" << (*user_out) << ">: "; |
| 113 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; |
| 119 tcsetattr(0, TCSANOW, &original_attr); |
| 120 if(verification != password) { |
| 121 LOG(ERROR) << "Passwords do not match."; |
| 122 return false; |
| 123 } |
| 124 } |
| 125 |
| 126 std::string trimmed_password; |
| 127 TrimString(password, "\r\n", &trimmed_password); |
| 128 cryptohome::UsernamePasskey up( |
| 129 cryptohome::UsernamePasskey::FromUsernamePassword((*user_out).c_str(), |
| 130 trimmed_password.c_str(), GetSystemSalt(proxy))); |
| 131 cryptohome::SecureBlob passkey = up.GetPasskey(); |
| 132 *password_out = std::string(reinterpret_cast<char*>(&passkey[0]), |
| 133 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 |
| 144 return true; |
| 145 } |
| 146 |
| 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) { |
| 171 std::cout << "!!! Are you sure you want to remove the user's cryptohome?" |
| 172 << std::endl |
| 173 << "!!!" |
| 174 << std::endl |
| 175 << "!!! Re-enter the username at the prompt to remove the" |
| 176 << std::endl |
| 177 << "!!! cryptohome for the user." |
| 178 << std::endl |
| 179 << "Enter the username <" << user << ">: "; |
| 180 std::string verification; |
| 181 std::cin >> verification; |
| 182 if(user != verification) { |
| 183 LOG(ERROR) << "Usernames do not match."; |
| 184 return false; |
| 185 } |
| 186 return true; |
| 187 } |
| 188 |
| 189 int main(int argc, char **argv) { |
| 190 CommandLine::Init(argc, argv); |
| 191 logging::InitLogging(NULL, |
| 192 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, |
| 193 logging::DONT_LOCK_LOG_FILE, |
| 194 logging::APPEND_TO_OLD_LOG_FILE); |
| 195 |
| 196 CommandLine *cl = CommandLine::ForCurrentProcess(); |
| 197 std::string action = cl->GetSwitchValueASCII(switches::kActionSwitch); |
| 198 g_type_init(); |
| 199 chromeos::dbus::BusConnection bus = chromeos::dbus::GetSystemBusConnection(); |
| 200 chromeos::dbus::Proxy proxy(bus, |
| 201 cryptohome::kCryptohomeServiceName, |
| 202 cryptohome::kCryptohomeServicePath, |
| 203 cryptohome::kCryptohomeInterface); |
| 204 DCHECK(proxy.gproxy()) << "Failed to acquire proxy"; |
| 205 |
| 206 if (!strcmp(switches::kActions[switches::ACTION_MOUNT], action.c_str())) { |
| 207 std::string user, password; |
| 208 |
| 209 if(!GetUsernamePassword(proxy, cl, &user, &password)) { |
| 210 return 1; |
| 211 } |
| 212 |
| 213 gboolean done = false; |
| 214 chromeos::glib::ScopedError error; |
| 215 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(), |
| 231 user.c_str(), |
| 232 password.c_str(), |
| 233 &done, |
| 234 errptr)) { |
| 235 LOG(ERROR) << "Mount call failed: " << error->message; |
| 236 } |
| 237 LOG_IF(ERROR, !done) << "Mount did not complete?"; |
| 238 LOG_IF(INFO, done) << "Call completed"; |
| 239 } else if (!strcmp(switches::kActions[switches::ACTION_TEST_AUTH], |
| 240 action.c_str())) { |
| 241 std::string user, password; |
| 242 |
| 243 if(!GetUsernamePassword(proxy, cl, &user, &password)) { |
| 244 return 1; |
| 245 } |
| 246 |
| 247 gboolean done = false; |
| 248 chromeos::glib::ScopedError error; |
| 249 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 250 if (!org_chromium_CryptohomeInterface_check_key(proxy.gproxy(), |
| 251 user.c_str(), |
| 252 password.c_str(), |
| 253 &done, |
| 254 errptr)) { |
| 255 LOG(ERROR) << "CheckKey call failed: " << error->message; |
| 256 } |
| 257 LOG_IF(ERROR, !done) << "CheckKey did not complete?"; |
| 258 LOG_IF(INFO, done) << "Call completed"; |
| 259 } else if (!strcmp(switches::kActions[switches::ACTION_MIGRATE_KEY], |
| 260 action.c_str())) { |
| 261 std::string user, password, old_password; |
| 262 |
| 263 if(!GetUsernamePassword(proxy, cl, &user, &password, &old_password)) { |
| 264 return 1; |
| 265 } |
| 266 |
| 267 gboolean done = false; |
| 268 chromeos::glib::ScopedError error; |
| 269 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 270 if (!org_chromium_CryptohomeInterface_migrate_key(proxy.gproxy(), |
| 271 user.c_str(), |
| 272 old_password.c_str(), |
| 273 password.c_str(), |
| 274 &done, |
| 275 errptr)) { |
| 276 LOG(ERROR) << "MigrateKey call failed: " << error->message; |
| 277 } |
| 278 LOG_IF(ERROR, !done) << "MigrateKey did not complete?"; |
| 279 LOG_IF(INFO, done) << "Call completed"; |
| 280 } else if (!strcmp(switches::kActions[switches::ACTION_REMOVE], |
| 281 action.c_str())) { |
| 282 std::string user; |
| 283 |
| 284 if(!GetUsername(cl, &user)) { |
| 285 return 1; |
| 286 } |
| 287 |
| 288 if(!ConfirmRemove(user)) { |
| 289 return 1; |
| 290 } |
| 291 |
| 292 gboolean done = false; |
| 293 chromeos::glib::ScopedError error; |
| 294 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 295 if (!org_chromium_CryptohomeInterface_remove(proxy.gproxy(), |
| 296 user.c_str(), |
| 297 &done, |
| 298 errptr)) { |
| 299 LOG(ERROR) << "Remove call failed: " << error->message; |
| 300 } |
| 301 LOG_IF(ERROR, !done) << "Remove did not complete?"; |
| 302 LOG_IF(INFO, done) << "Call completed"; |
| 303 } else if (!strcmp(switches::kActions[switches::ACTION_UNMOUNT], |
| 304 action.c_str())) { |
| 305 chromeos::glib::ScopedError error; |
| 306 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 307 gboolean done = false; |
| 308 if (!org_chromium_CryptohomeInterface_unmount(proxy.gproxy(), |
| 309 &done, |
| 310 errptr)) { |
| 311 LOG(ERROR) << "Unmount call failed: " << error->message; |
| 312 } |
| 313 LOG_IF(ERROR, !done) << "Unmount did not complete?"; |
| 314 LOG_IF(INFO, done) << "Call completed"; |
| 315 } else if (!strcmp(switches::kActions[switches::ACTION_MOUNTED], |
| 316 action.c_str())) { |
| 317 chromeos::glib::ScopedError error; |
| 318 GError **errptr = &chromeos::Resetter(&error).lvalue(); |
| 319 gboolean done = false; |
| 320 if (!org_chromium_CryptohomeInterface_is_mounted(proxy.gproxy(), |
| 321 &done, |
| 322 errptr)) { |
| 323 LOG(ERROR) << "IsMounted call failed: " << error->message; |
| 324 } |
| 325 std::cout << done << std::endl; |
| 326 |
| 327 } else { |
| 328 LOG(ERROR) << "Unknown action or no action given. Available actions: "; |
| 329 for(int i = 0; /* loop forever */; i++) { |
| 330 if(!switches::kActions[i]) { |
| 331 break; |
| 332 } |
| 333 LOG(ERROR) << " --action=" << switches::kActions[i]; |
| 334 } |
| 335 } |
| 336 return 0; |
| 337 } |
OLD | NEW |