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 #include "service.h" | 5 #include "service.h" |
6 | 6 |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 #include <base/file_util.h> | 10 #include <base/file_util.h> |
11 #include <base/logging.h> | 11 #include <base/logging.h> |
12 #include <base/string_util.h> | 12 #include <base/string_util.h> |
13 #include <base/time.h> | 13 #include <base/time.h> |
14 #include <chromeos/dbus/dbus.h> | 14 #include <chromeos/dbus/dbus.h> |
15 #include <string> | |
16 #include <vector> | |
15 | 17 |
16 #include "cryptohome/marshal.glibmarshal.h" | 18 #include "cryptohome/marshal.glibmarshal.h" |
17 #include "cryptohome_event_source.h" | 19 #include "cryptohome_event_source.h" |
18 #include "interface.h" | 20 #include "interface.h" |
19 #include "crypto.h" | 21 #include "crypto.h" |
22 #include "lockbox.h" | |
20 #include "mount.h" | 23 #include "mount.h" |
21 #include "secure_blob.h" | 24 #include "secure_blob.h" |
22 #include "tpm.h" | 25 #include "tpm.h" |
23 #include "username_passkey.h" | 26 #include "username_passkey.h" |
24 #include "vault_keyset.pb.h" | 27 #include "vault_keyset.pb.h" |
25 | 28 |
26 // Forcibly namespace the dbus-bindings generated server bindings instead of | 29 // Forcibly namespace the dbus-bindings generated server bindings instead of |
27 // modifying the files afterward. | 30 // modifying the files afterward. |
28 namespace cryptohome { // NOLINT | 31 namespace cryptohome { // NOLINT |
29 namespace gobject { // NOLINT | 32 namespace gobject { // NOLINT |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 system_salt_(), | 82 system_salt_(), |
80 default_mount_(new cryptohome::Mount()), | 83 default_mount_(new cryptohome::Mount()), |
81 mount_(default_mount_.get()), | 84 mount_(default_mount_.get()), |
82 default_tpm_init_(new TpmInit()), | 85 default_tpm_init_(new TpmInit()), |
83 tpm_init_(default_tpm_init_.get()), | 86 tpm_init_(default_tpm_init_.get()), |
84 initialize_tpm_(true), | 87 initialize_tpm_(true), |
85 mount_thread_(kMountThreadName), | 88 mount_thread_(kMountThreadName), |
86 async_complete_signal_(-1), | 89 async_complete_signal_(-1), |
87 tpm_init_signal_(-1), | 90 tpm_init_signal_(-1), |
88 event_source_(), | 91 event_source_(), |
89 auto_cleanup_period_(kAutoCleanupPeriodMS) { | 92 auto_cleanup_period_(kAutoCleanupPeriodMS), |
93 default_lockbox_(new cryptohome::Lockbox()), | |
94 lockbox_(default_lockbox_.get()) { | |
90 } | 95 } |
91 | 96 |
92 Service::~Service() { | 97 Service::~Service() { |
93 if (loop_) | 98 if (loop_) |
94 g_main_loop_unref(loop_); | 99 g_main_loop_unref(loop_); |
95 if (cryptohome_) | 100 if (cryptohome_) |
96 g_object_unref(cryptohome_); | 101 g_object_unref(cryptohome_); |
97 if (mount_thread_.IsRunning()) { | 102 if (mount_thread_.IsRunning()) { |
98 mount_thread_.Stop(); | 103 mount_thread_.Stop(); |
99 } | 104 } |
100 } | 105 } |
101 | 106 |
102 bool Service::Initialize() { | 107 bool Service::Initialize() { |
103 bool result = true; | 108 bool result = true; |
104 | 109 |
105 mount_->Init(); | 110 mount_->Init(); |
111 // If the TPM is unowned or doesn't exist, it's safe for | |
112 // this function to be called again. However, it shouldn't | |
113 // be called across multiple threads in parallel. | |
gauravsh
2011/04/11 04:03:20
Is this comment for InitializeLockBox()? If so, ca
Will Drewry
2011/04/13 16:04:59
The part that is relevant (thread safety) is in th
| |
114 InitializeLockbox(); | |
115 | |
106 Tpm* tpm = const_cast<Tpm*>(mount_->get_crypto()->get_tpm()); | 116 Tpm* tpm = const_cast<Tpm*>(mount_->get_crypto()->get_tpm()); |
107 if (tpm && initialize_tpm_) { | 117 if (tpm && initialize_tpm_) { |
108 tpm_init_->set_tpm(tpm); | 118 tpm_init_->set_tpm(tpm); |
109 tpm_init_->Init(this); | 119 tpm_init_->Init(this); |
110 if (!SeedUrandom()) { | 120 if (!SeedUrandom()) { |
111 LOG(ERROR) << "FAILED TO SEED /dev/urandom AT START"; | 121 LOG(ERROR) << "FAILED TO SEED /dev/urandom AT START"; |
112 } | 122 } |
113 } | 123 } |
114 | |
115 // Install the type-info for the service with dbus. | 124 // Install the type-info for the service with dbus. |
116 dbus_g_object_type_install_info(gobject::cryptohome_get_type(), | 125 dbus_g_object_type_install_info(gobject::cryptohome_get_type(), |
117 &gobject::dbus_glib_cryptohome_object_info); | 126 &gobject::dbus_glib_cryptohome_object_info); |
118 if (!Reset()) { | 127 if (!Reset()) { |
119 result = false; | 128 result = false; |
120 } | 129 } |
121 | 130 |
122 async_complete_signal_ = g_signal_new("async_call_status", | 131 async_complete_signal_ = g_signal_new("async_call_status", |
123 gobject::cryptohome_get_type(), | 132 gobject::cryptohome_get_type(), |
124 G_SIGNAL_RUN_LAST, | 133 G_SIGNAL_RUN_LAST, |
(...skipping 24 matching lines...) Expand all Loading... | |
149 | 158 |
150 // Start scheduling periodic cleanup events. Note, that the first | 159 // Start scheduling periodic cleanup events. Note, that the first |
151 // event will be called by Chrome explicitly from the login screen. | 160 // event will be called by Chrome explicitly from the login screen. |
152 mount_thread_.message_loop()->PostDelayedTask( | 161 mount_thread_.message_loop()->PostDelayedTask( |
153 FROM_HERE, NewRunnableMethod(this, &Service::AutoCleanupCallback), | 162 FROM_HERE, NewRunnableMethod(this, &Service::AutoCleanupCallback), |
154 auto_cleanup_period_); | 163 auto_cleanup_period_); |
155 | 164 |
156 return result; | 165 return result; |
157 } | 166 } |
158 | 167 |
168 void Service::InitializeLockbox() { | |
gauravsh
2011/04/11 04:03:20
Should this return true or false? Otherwise the ca
Will Drewry
2011/04/13 16:04:59
The caller doesn't matter as much unless we want c
| |
169 Tpm* tpm = const_cast<Tpm*>(mount_->get_crypto()->get_tpm()); | |
170 // Don't call this until the TPM is owned. | |
171 if (tpm && !tpm->IsOwned()) | |
172 return; | |
173 // tpm will be NULL if the system lacks one. | |
174 lockbox_->Init(tpm, | |
175 Lockbox::kDefaultNvramIndex, | |
176 Lockbox::kDefaultPath); | |
177 } | |
178 | |
159 bool Service::SeedUrandom() { | 179 bool Service::SeedUrandom() { |
160 SecureBlob random; | 180 SecureBlob random; |
161 if (!tpm_init_->GetRandomData(kDefaultRandomSeedLength, &random)) { | 181 if (!tpm_init_->GetRandomData(kDefaultRandomSeedLength, &random)) { |
162 LOG(ERROR) << "Could not get random data from the TPM"; | 182 LOG(ERROR) << "Could not get random data from the TPM"; |
163 return false; | 183 return false; |
164 } | 184 } |
165 size_t written = file_util::WriteFile(FilePath(kDefaultEntropySource), | 185 size_t written = file_util::WriteFile(FilePath(kDefaultEntropySource), |
166 static_cast<const char*>(random.const_data()), random.size()); | 186 static_cast<const char*>(random.const_data()), random.size()); |
167 if (written != random.size()) { | 187 if (written != random.size()) { |
168 LOG(ERROR) << "Error writing data to /dev/urandom"; | 188 LOG(ERROR) << "Error writing data to /dev/urandom"; |
(...skipping 30 matching lines...) Expand all Loading... | |
199 | 219 |
200 void Service::NotifyEvent(CryptohomeEventBase* event) { | 220 void Service::NotifyEvent(CryptohomeEventBase* event) { |
201 if (!strcmp(event->GetEventName(), kMountTaskResultEventType)) { | 221 if (!strcmp(event->GetEventName(), kMountTaskResultEventType)) { |
202 MountTaskResult* result = static_cast<MountTaskResult*>(event); | 222 MountTaskResult* result = static_cast<MountTaskResult*>(event); |
203 g_signal_emit(cryptohome_, async_complete_signal_, 0, result->sequence_id(), | 223 g_signal_emit(cryptohome_, async_complete_signal_, 0, result->sequence_id(), |
204 result->return_status(), result->return_code()); | 224 result->return_status(), result->return_code()); |
205 } else if (!strcmp(event->GetEventName(), kTpmInitStatusEventType)) { | 225 } else if (!strcmp(event->GetEventName(), kTpmInitStatusEventType)) { |
206 TpmInitStatus* result = static_cast<TpmInitStatus*>(event); | 226 TpmInitStatus* result = static_cast<TpmInitStatus*>(event); |
207 g_signal_emit(cryptohome_, tpm_init_signal_, 0, tpm_init_->IsTpmReady(), | 227 g_signal_emit(cryptohome_, tpm_init_signal_, 0, tpm_init_->IsTpmReady(), |
208 tpm_init_->IsTpmEnabled(), result->get_took_ownership()); | 228 tpm_init_->IsTpmEnabled(), result->get_took_ownership()); |
229 // TODO(wad) should we package up a Lockbox status here too? | |
209 } | 230 } |
210 } | 231 } |
211 | 232 |
212 void Service::InitializeTpmComplete(bool status, bool took_ownership) { | 233 void Service::InitializeTpmComplete(bool status, bool took_ownership) { |
213 if (took_ownership) { | 234 if (took_ownership) { |
214 MountTaskResult ignored_result; | 235 MountTaskResult ignored_result; |
215 base::WaitableEvent event(true, false); | 236 base::WaitableEvent event(true, false); |
216 MountTaskResetTpmContext* mount_task = | 237 MountTaskResetTpmContext* mount_task = |
217 new MountTaskResetTpmContext(NULL, mount_); | 238 new MountTaskResetTpmContext(NULL, mount_); |
218 mount_task->set_result(&ignored_result); | 239 mount_task->set_result(&ignored_result); |
219 mount_task->set_complete_event(&event); | 240 mount_task->set_complete_event(&event); |
220 mount_thread_.message_loop()->PostTask(FROM_HERE, mount_task); | 241 mount_thread_.message_loop()->PostTask(FROM_HERE, mount_task); |
221 event.Wait(); | 242 event.Wait(); |
243 // Initialize the install-time locked attributes since we | |
244 // can't do it prior to ownership. | |
245 InitializeLockbox(); | |
222 } | 246 } |
223 // The event source will free this object | 247 // The event source will free this object |
224 TpmInitStatus* tpm_init_status = new TpmInitStatus(); | 248 TpmInitStatus* tpm_init_status = new TpmInitStatus(); |
225 tpm_init_status->set_status(status); | 249 tpm_init_status->set_status(status); |
226 tpm_init_status->set_took_ownership(took_ownership); | 250 tpm_init_status->set_took_ownership(took_ownership); |
227 event_source_.AddEvent(tpm_init_status); | 251 event_source_.AddEvent(tpm_init_status); |
228 } | 252 } |
229 | 253 |
230 gboolean Service::CheckKey(gchar *userid, | 254 gboolean Service::CheckKey(gchar *userid, |
231 gchar *key, | 255 gchar *key, |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
560 tpm_init_->StartInitializeTpm(); | 584 tpm_init_->StartInitializeTpm(); |
561 } | 585 } |
562 return TRUE; | 586 return TRUE; |
563 } | 587 } |
564 | 588 |
565 gboolean Service::TpmClearStoredPassword(GError** error) { | 589 gboolean Service::TpmClearStoredPassword(GError** error) { |
566 tpm_init_->ClearStoredTpmPassword(); | 590 tpm_init_->ClearStoredTpmPassword(); |
567 return TRUE; | 591 return TRUE; |
568 } | 592 } |
569 | 593 |
594 gboolean Service::LockboxGet(gchar* name, | |
595 GArray** OUT_value, | |
596 gboolean* OUT_successful, | |
597 GError** error) { | |
598 chromeos::Blob value; | |
599 *OUT_successful = lockbox_->Get(name, &value); | |
600 *OUT_value = g_array_new(false, false, sizeof(char)); | |
601 if (*OUT_successful) | |
602 g_array_append_vals(*OUT_value, &value.front(), value.size()); | |
603 return TRUE; | |
604 } | |
605 | |
606 gboolean Service::LockboxSet(gchar* name, | |
607 GArray* value, | |
608 gboolean* OUT_successful, | |
609 GError** error) { | |
610 // Convert from GArray to vector | |
611 chromeos::Blob value_blob; | |
612 value_blob.assign(value->data, value->data + value->len); | |
613 *OUT_successful = lockbox_->Set(name, value_blob); | |
614 return TRUE; | |
615 } | |
616 | |
617 gboolean Service::LockboxLock(gboolean* OUT_locked, GError** error) { | |
618 *OUT_locked = lockbox_->Lock(); | |
619 return TRUE; | |
620 } | |
621 | |
622 gboolean Service::LockboxCount(gint* OUT_count, GError** error) { | |
623 // TODO(wad) for all of these functions return error on uninit. | |
624 // Follow the CHROMEOS_LOGIN_ERROR quark example in chromeos/dbus/ | |
625 *OUT_count = lockbox_->Count(); | |
626 return TRUE; | |
627 } | |
628 | |
629 gboolean Service::LockboxIsReady(gboolean* OUT_ready, GError** error) { | |
630 // Initialization is handled automatically when possible and async | |
631 // notification implies readiness. This allows other code to poll. | |
632 *OUT_ready = (lockbox_->initialized() == true); | |
633 return TRUE; | |
634 } | |
635 | |
636 gboolean Service::LockboxIsLocked(gboolean* OUT_locked, GError** error) { | |
637 *OUT_locked = (lockbox_->locked() == true); | |
638 return TRUE; | |
639 } | |
640 | |
641 gboolean Service::LockboxIsSecure(gboolean* OUT_secure, GError** error) { | |
642 *OUT_secure = (lockbox_->secure() == true); | |
643 return TRUE; | |
644 } | |
645 | |
646 gboolean Service::LockboxIsTampered(gboolean* OUT_tampered, GError** error) { | |
647 *OUT_tampered = (lockbox_->tampered() == true); | |
648 return TRUE; | |
649 } | |
650 | |
651 gboolean Service::LockboxIsLegacy(gboolean* OUT_legacy, GError** error) { | |
652 *OUT_legacy = (lockbox_->legacy() == true); | |
653 return TRUE; | |
654 } | |
655 | |
570 gboolean Service::GetStatusString(gchar** OUT_status, GError** error) { | 656 gboolean Service::GetStatusString(gchar** OUT_status, GError** error) { |
571 Tpm::TpmStatusInfo tpm_status; | 657 Tpm::TpmStatusInfo tpm_status; |
572 mount_->get_crypto()->EnsureTpm(false); | 658 mount_->get_crypto()->EnsureTpm(false); |
573 Tpm* tpm = const_cast<Tpm*>(mount_->get_crypto()->get_tpm()); | 659 Tpm* tpm = const_cast<Tpm*>(mount_->get_crypto()->get_tpm()); |
574 | 660 |
575 if (tpm) { | 661 if (tpm) { |
576 tpm->GetStatus(true, &tpm_status); | 662 tpm->GetStatus(true, &tpm_status); |
577 } else { | 663 } else { |
578 Tpm::GetSingleton()->GetStatus(true, &tpm_status); | 664 Tpm::GetSingleton()->GetStatus(true, &tpm_status); |
579 } | 665 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
620 " (UTC)\n", | 706 " (UTC)\n", |
621 ((serialized.flags() & | 707 ((serialized.flags() & |
622 cryptohome::SerializedVaultKeyset::TPM_WRAPPED) ? "1" : "0"), | 708 cryptohome::SerializedVaultKeyset::TPM_WRAPPED) ? "1" : "0"), |
623 ((serialized.flags() & | 709 ((serialized.flags() & |
624 cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED) ? "1" : "0"), | 710 cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED) ? "1" : "0"), |
625 exploded.month, exploded.day_of_month, exploded.year, | 711 exploded.month, exploded.day_of_month, exploded.year, |
626 exploded.hour, exploded.minute, exploded.second); | 712 exploded.hour, exploded.minute, exploded.second); |
627 | 713 |
628 } while(false); | 714 } while(false); |
629 } | 715 } |
716 int lockbox_size = lockbox_->Count(); | |
717 std::string lockbox_data("Lockbox Contents:\n"); | |
718 if (lockbox_->Count()) { | |
719 std::string name; | |
720 chromeos::Blob value; | |
721 for (int pair = 0; pair < lockbox_size; ++pair) { | |
722 lockbox_data += StringPrintf( | |
gauravsh
2011/04/11 04:03:20
is using += as efficient as using append()? (not t
Will Drewry
2011/04/13 16:04:59
No idea. Done.
gauravsh
2011/04/14 07:39:52
Yeah, it seems either append or += is ok. What's n
| |
723 " Index...........................: %d\n", pair); | |
724 if (lockbox_->GetNameByIndex(pair, &name) && | |
725 lockbox_->GetValueByIndex(pair, &value)) { | |
726 std::string value_str(reinterpret_cast<const char*>(&value[0]), | |
727 value.size()); | |
728 lockbox_data += StringPrintf( | |
729 " Name............................: %s\n" | |
730 " Value...........................: %s\n", | |
731 name.c_str(), | |
732 value_str.c_str()); | |
733 } | |
734 } | |
735 } | |
630 | 736 |
631 *OUT_status = g_strdup_printf( | 737 *OUT_status = g_strdup_printf( |
632 "TPM Status:\n" | 738 "TPM Status:\n" |
633 " Enabled.........................: %s\n" | 739 " Enabled.........................: %s\n" |
634 " Owned...........................: %s\n" | 740 " Owned...........................: %s\n" |
635 " Being Owned.....................: %s\n" | 741 " Being Owned.....................: %s\n" |
636 " Can Connect.....................: %s\n" | 742 " Can Connect.....................: %s\n" |
637 " Can Load SRK....................: %s\n" | 743 " Can Load SRK....................: %s\n" |
638 " Can Load SRK Public.............: %s\n" | 744 " Can Load SRK Public.............: %s\n" |
639 " Has Cryptohome Key..............: %s\n" | 745 " Has Cryptohome Key..............: %s\n" |
640 " Can Encrypt.....................: %s\n" | 746 " Can Encrypt.....................: %s\n" |
641 " Can Decrypt.....................: %s\n" | 747 " Can Decrypt.....................: %s\n" |
642 " Instance Context................: %s\n" | 748 " Instance Context................: %s\n" |
643 " Instance Key Handle.............: %s\n" | 749 " Instance Key Handle.............: %s\n" |
644 " Last Error......................: %08x\n" | 750 " Last Error......................: %08x\n" |
645 "%s" | 751 "%s" |
646 "Mount Status:\n" | 752 "Mount Status:\n" |
647 " Vault Is Mounted................: %s\n", | 753 " Vault Is Mounted................: %s\n" |
754 "Lockbox Status:\n" | |
755 " Initialized.....................: %s\n" | |
756 " Secure..........................: %s\n" | |
757 " Legacy..........................: %s\n" | |
758 " Locked..........................: %s\n" | |
759 " Tampered........................: %s\n" | |
760 " Entries.........................: %d\n" | |
761 "%s", | |
648 (tpm_status.Enabled ? "1" : "0"), | 762 (tpm_status.Enabled ? "1" : "0"), |
649 (tpm_status.Owned ? "1" : "0"), | 763 (tpm_status.Owned ? "1" : "0"), |
650 (tpm_status.BeingOwned ? "1" : "0"), | 764 (tpm_status.BeingOwned ? "1" : "0"), |
651 (tpm_status.CanConnect ? "1" : "0"), | 765 (tpm_status.CanConnect ? "1" : "0"), |
652 (tpm_status.CanLoadSrk ? "1" : "0"), | 766 (tpm_status.CanLoadSrk ? "1" : "0"), |
653 (tpm_status.CanLoadSrkPublicKey ? "1" : "0"), | 767 (tpm_status.CanLoadSrkPublicKey ? "1" : "0"), |
654 (tpm_status.HasCryptohomeKey ? "1" : "0"), | 768 (tpm_status.HasCryptohomeKey ? "1" : "0"), |
655 (tpm_status.CanEncrypt ? "1" : "0"), | 769 (tpm_status.CanEncrypt ? "1" : "0"), |
656 (tpm_status.CanDecrypt ? "1" : "0"), | 770 (tpm_status.CanDecrypt ? "1" : "0"), |
657 (tpm_status.ThisInstanceHasContext ? "1" : "0"), | 771 (tpm_status.ThisInstanceHasContext ? "1" : "0"), |
658 (tpm_status.ThisInstanceHasKeyHandle ? "1" : "0"), | 772 (tpm_status.ThisInstanceHasKeyHandle ? "1" : "0"), |
659 tpm_status.LastTpmError, | 773 tpm_status.LastTpmError, |
660 user_data.c_str(), | 774 user_data.c_str(), |
661 (mount_->IsCryptohomeMounted() ? "1" : "0")); | 775 (mount_->IsCryptohomeMounted() ? "1" : "0"), |
776 (lockbox_->initialized() ? "1" : "0"), | |
777 (lockbox_->secure() ? "1" : "0"), | |
778 (lockbox_->legacy() ? "1" : "0"), | |
779 (lockbox_->locked() ? "1" : "0"), | |
780 (lockbox_->tampered() ? "1" : "0"), | |
781 lockbox_size, | |
782 lockbox_data.c_str()); | |
662 return TRUE; | 783 return TRUE; |
663 } | 784 } |
664 | 785 |
665 // Called on Mount thread. | 786 // Called on Mount thread. |
666 void Service::AutoCleanupCallback() { | 787 void Service::AutoCleanupCallback() { |
667 mount_->DoAutomaticFreeDiskSpaceControl(); | 788 mount_->DoAutomaticFreeDiskSpaceControl(); |
668 | 789 |
669 // Schedule our next call. If the thread is terminating, we would | 790 // Schedule our next call. If the thread is terminating, we would |
670 // not be called. | 791 // not be called. |
671 mount_thread_.message_loop()->PostDelayedTask( | 792 mount_thread_.message_loop()->PostDelayedTask( |
672 FROM_HERE, NewRunnableMethod(this, &Service::AutoCleanupCallback), | 793 FROM_HERE, NewRunnableMethod(this, &Service::AutoCleanupCallback), |
673 auto_cleanup_period_); | 794 auto_cleanup_period_); |
674 } | 795 } |
675 | 796 |
676 } // namespace cryptohome | 797 } // namespace cryptohome |
677 | 798 |
678 // We do not want AutoCleanupCallback() to refer the class and make it | 799 // We do not want AutoCleanupCallback() to refer the class and make it |
679 // wait for its execution. If Mount thread terminates, it will delete | 800 // wait for its execution. If Mount thread terminates, it will delete |
680 // our pending task or wait for it to finish. | 801 // our pending task or wait for it to finish. |
681 DISABLE_RUNNABLE_METHOD_REFCOUNT(cryptohome::Service); | 802 DISABLE_RUNNABLE_METHOD_REFCOUNT(cryptohome::Service); |
OLD | NEW |