| 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 #include "cryptohome/service.h" | 4 #include "cryptohome/service.h" |
| 5 | 5 |
| 6 #include <base/logging.h> | 6 #include <base/logging.h> |
| 7 #include <chromeos/dbus/dbus.h> | 7 #include <chromeos/dbus/dbus.h> |
| 8 #include <stdio.h> | 8 #include <stdio.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 | 10 |
| 11 #include "cryptohome/authenticator.h" | |
| 12 #include "cryptohome/interface.h" | 11 #include "cryptohome/interface.h" |
| 13 #include "cryptohome/username_passhash.h" | 12 #include "cryptohome/mount.h" |
| 13 #include "cryptohome/secure_blob.h" |
| 14 #include "cryptohome/username_passkey.h" |
| 14 | 15 |
| 15 // Forcibly namespace the dbus-bindings generated server bindings instead of | 16 // Forcibly namespace the dbus-bindings generated server bindings instead of |
| 16 // modifying the files afterward. | 17 // modifying the files afterward. |
| 17 namespace cryptohome { // NOLINT | 18 namespace cryptohome { // NOLINT |
| 18 namespace gobject { // NOLINT | 19 namespace gobject { // NOLINT |
| 19 #include "cryptohome/bindings/server.h" | 20 #include "cryptohome/bindings/server.h" |
| 20 } // namespace gobject | 21 } // namespace gobject |
| 21 } // namespace cryptohome | 22 } // namespace cryptohome |
| 22 | 23 |
| 23 namespace cryptohome { | 24 namespace cryptohome { |
| 24 | 25 |
| 25 const char *Service::kDefaultMountCommand = "/usr/sbin/mount.cryptohome"; | 26 Service::Service() : loop_(NULL), |
| 26 const char *Service::kDefaultUnmountCommand = "/usr/sbin/umount.cryptohome"; | 27 cryptohome_(NULL), |
| 27 const char *Service::kDefaultIsMountedCommand = | 28 system_salt_(), |
| 28 "/bin/mount | /bin/grep -q ' /home/chronos/user '"; | 29 mount_(NULL) { } |
| 29 | 30 |
| 30 Service::Service() : loop_(NULL), | |
| 31 auth_(new Authenticator), | |
| 32 cryptohome_(NULL), | |
| 33 mount_command_(kDefaultMountCommand), | |
| 34 unmount_command_(kDefaultUnmountCommand), | |
| 35 is_mounted_command_(kDefaultIsMountedCommand) { } | |
| 36 Service::~Service() { | 31 Service::~Service() { |
| 37 if (loop_) | 32 if (loop_) |
| 38 g_main_loop_unref(loop_); | 33 g_main_loop_unref(loop_); |
| 39 if (cryptohome_) | 34 if (cryptohome_) |
| 40 g_object_unref(cryptohome_); | 35 g_object_unref(cryptohome_); |
| 36 if (mount_) |
| 37 delete mount_; |
| 41 } | 38 } |
| 42 | 39 |
| 43 bool Service::Initialize() { | 40 bool Service::Initialize() { |
| 41 if(mount_ == NULL) { |
| 42 mount_ = new cryptohome::Mount(); |
| 43 mount_->Init(); |
| 44 } |
| 44 // Install the type-info for the service with dbus. | 45 // Install the type-info for the service with dbus. |
| 45 dbus_g_object_type_install_info(gobject::cryptohome_get_type(), | 46 dbus_g_object_type_install_info(gobject::cryptohome_get_type(), |
| 46 &gobject::dbus_glib_cryptohome_object_info); | 47 &gobject::dbus_glib_cryptohome_object_info); |
| 47 return Reset(); | 48 return Reset(); |
| 48 } | 49 } |
| 49 | 50 |
| 50 bool Service::Reset() { | 51 bool Service::Reset() { |
| 51 if (cryptohome_) | 52 if (cryptohome_) |
| 52 g_object_unref(cryptohome_); | 53 g_object_unref(cryptohome_); |
| 53 cryptohome_ = reinterpret_cast<gobject::Cryptohome*>( | 54 cryptohome_ = reinterpret_cast<gobject::Cryptohome*>( |
| 54 g_object_new(gobject::cryptohome_get_type(), NULL)); | 55 g_object_new(gobject::cryptohome_get_type(), NULL)); |
| 55 // Allow references to this instance. | 56 // Allow references to this instance. |
| 56 cryptohome_->service = this; | 57 cryptohome_->service = this; |
| 57 | 58 |
| 58 if (loop_) { | 59 if (loop_) { |
| 59 ::g_main_loop_unref(loop_); | 60 ::g_main_loop_unref(loop_); |
| 60 } | 61 } |
| 61 loop_ = g_main_loop_new(NULL, false); | 62 loop_ = g_main_loop_new(NULL, false); |
| 62 if (!loop_) { | 63 if (!loop_) { |
| 63 LOG(ERROR) << "Failed to create main loop"; | 64 LOG(ERROR) << "Failed to create main loop"; |
| 64 return false; | 65 return false; |
| 65 } | 66 } |
| 66 return true; | 67 return true; |
| 67 } | 68 } |
| 68 | 69 |
| 69 gboolean Service::CheckKey(gchar *userid, | 70 gboolean Service::CheckKey(gchar *userid, |
| 70 gchar *key, | 71 gchar *key, |
| 71 gboolean *OUT_success, | 72 gboolean *OUT_success, |
| 72 GError **error) { | 73 GError **error) { |
| 73 UsernamePasshash creds(userid, strlen(userid), key, strlen(key)); | 74 UsernamePasskey credentials(userid, strlen(userid), |
| 74 if (!auth_->Init()) { | 75 chromeos::Blob(key, key + strlen(key))); |
| 75 *OUT_success = FALSE; | 76 |
| 76 return TRUE; | 77 // TODO(fes): Handle CHROMEOS_PAM_LOCALACCOUNT |
| 78 *OUT_success = mount_->TestCredentials(credentials); |
| 79 return TRUE; |
| 80 } |
| 81 |
| 82 gboolean Service::MigrateKey(gchar *userid, |
| 83 gchar *from_key, |
| 84 gchar *to_key, |
| 85 gboolean *OUT_success, |
| 86 GError **error) { |
| 87 UsernamePasskey credentials(userid, strlen(userid), |
| 88 chromeos::Blob(to_key, to_key + strlen(to_key))); |
| 89 |
| 90 *OUT_success = mount_->MigratePasskey(credentials, from_key); |
| 91 return TRUE; |
| 92 } |
| 93 |
| 94 gboolean Service::Remove(gchar *userid, |
| 95 gboolean *OUT_success, |
| 96 GError **error) { |
| 97 UsernamePasskey credentials(userid, strlen(userid), |
| 98 chromeos::Blob()); |
| 99 |
| 100 *OUT_success = mount_->RemoveCryptohome(credentials); |
| 101 return TRUE; |
| 102 } |
| 103 |
| 104 gboolean Service::GetSystemSalt(GArray **OUT_salt, GError **error) { |
| 105 if(system_salt_.size() == 0) { |
| 106 system_salt_ = mount_->GetSystemSalt(); |
| 77 } | 107 } |
| 78 *OUT_success = auth_->TestAllMasterKeys(creds); | 108 *OUT_salt = g_array_new(false, false, 1); |
| 109 g_array_append_vals(*OUT_salt, &system_salt_.front(), system_salt_.size()); |
| 110 |
| 79 return TRUE; | 111 return TRUE; |
| 80 } | 112 } |
| 81 | 113 |
| 82 gboolean Service::IsMounted(gboolean *OUT_is_mounted, GError **error) { | 114 gboolean Service::IsMounted(gboolean *OUT_is_mounted, GError **error) { |
| 83 int status = system(is_mounted_command()); | 115 *OUT_is_mounted = mount_->IsCryptohomeMounted(); |
| 84 *OUT_is_mounted = !status; | |
| 85 return TRUE; | 116 return TRUE; |
| 86 } | 117 } |
| 87 | 118 |
| 88 gboolean Service::Mount(gchar *userid, | 119 gboolean Service::Mount(gchar *userid, |
| 89 gchar *key, | 120 gchar *key, |
| 90 gboolean *OUT_done, | 121 gboolean *OUT_done, |
| 91 GError **error) { | 122 GError **error) { |
| 92 // Never double mount. | 123 UsernamePasskey credentials(userid, strlen(userid), |
| 93 // This will mean we don't mount over existing mounts, | 124 chromeos::Blob(key, key + strlen(key))); |
| 94 // but at present, we reboot on user change so it is ok. | 125 |
| 95 // Later, this can be more intelligent. | 126 if(mount_->IsCryptohomeMounted()) { |
| 96 if (IsMounted(OUT_done, error) && *OUT_done) { | 127 if(mount_->IsCryptohomeMountedForUser(credentials)) { |
| 97 *OUT_done = FALSE; | 128 LOG(INFO) << "Cryptohome already mounted for this user"; |
| 98 return TRUE; | 129 *OUT_done = TRUE; |
| 130 return TRUE; |
| 131 } else { |
| 132 if(!mount_->UnmountCryptohome()) { |
| 133 LOG(ERROR) << "Could not unmount cryptohome from previous user"; |
| 134 *OUT_done = FALSE; |
| 135 return TRUE; |
| 136 } |
| 137 } |
| 99 } | 138 } |
| 100 // Note, by doing this we allow any chronos caller to | 139 |
| 101 // send a variable for use in the scripts. Bad idea. | 140 // TODO(fes): Iterate keys if we change how cryptohome keeps track of key |
| 102 // Thankfully, this will go away with the scripts. | 141 // indexes. Right now, 0 is always the current, and 0+n should only be used |
| 103 setenv("CHROMEOS_USER", userid, 1); | 142 // temporarily during password migration. |
| 104 FILE *mount = popen(mount_command(), "w"); | 143 Mount::MountError mount_error = Mount::MOUNT_ERROR_NONE; |
| 105 if (!mount) { | 144 *OUT_done = mount_->MountCryptohome(credentials, 0, &mount_error); |
| 106 // TODO(wad) *error = | 145 if(!(*OUT_done) && (mount_error == Mount::MOUNT_ERROR_KEY_FAILURE)) { |
| 107 return FALSE; | 146 // If there is a key failure, create cryptohome from scratch. |
| 108 } | 147 // TODO(fes): remove this when Chrome is no longer expecting this behavior. |
| 109 fprintf(mount, "%s", key); | 148 if(mount_->RemoveCryptohome(credentials)) { |
| 110 int status = pclose(mount); | 149 *OUT_done = mount_->MountCryptohome(credentials, 0, &mount_error); |
| 111 if (status != 0) { | 150 } |
| 112 *OUT_done = FALSE; | |
| 113 } else { | |
| 114 *OUT_done = TRUE; | |
| 115 } | 151 } |
| 116 return TRUE; | 152 return TRUE; |
| 117 } | 153 } |
| 118 | 154 |
| 119 gboolean Service::Unmount(gboolean *OUT_done, GError **error) { | 155 gboolean Service::Unmount(gboolean *OUT_done, GError **error) { |
| 120 // Check for a mount first. | 156 if(mount_->IsCryptohomeMounted()) { |
| 121 if (IsMounted(OUT_done, error) && !*OUT_done) { | 157 *OUT_done = mount_->UnmountCryptohome(); |
| 122 *OUT_done = TRUE; // unmounting nothing works fine. | 158 } else { |
| 123 return TRUE; | 159 *OUT_done = true; |
| 124 } | 160 } |
| 125 | |
| 126 int status = system(unmount_command()); | |
| 127 *OUT_done = !status; | |
| 128 return TRUE; | 161 return TRUE; |
| 129 } | 162 } |
| 130 | 163 |
| 131 } // namespace cryptohome | 164 } // namespace cryptohome |
| OLD | NEW |