Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2009-2010 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 "login_manager/session_manager_service.h" | 5 #include "login_manager/session_manager_service.h" |
| 6 | 6 |
| 7 #include <dbus/dbus-glib-lowlevel.h> | 7 #include <dbus/dbus-glib-lowlevel.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <glib.h> | 9 #include <glib.h> |
| 10 #include <grp.h> | 10 #include <grp.h> |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 ".@1234567890-+_"; | 123 ".@1234567890-+_"; |
| 124 // static | 124 // static |
| 125 const char SessionManagerService::kIncognitoUser[] = ""; | 125 const char SessionManagerService::kIncognitoUser[] = ""; |
| 126 // static | 126 // static |
| 127 const char SessionManagerService::kDeviceOwnerPref[] = "cros.device.owner"; | 127 const char SessionManagerService::kDeviceOwnerPref[] = "cros.device.owner"; |
| 128 // static | 128 // static |
| 129 const char SessionManagerService::kTestingChannelFlag[] = | 129 const char SessionManagerService::kTestingChannelFlag[] = |
| 130 "--testing-channel=NamedTestingInterface:"; | 130 "--testing-channel=NamedTestingInterface:"; |
| 131 // static | 131 // static |
| 132 const char SessionManagerService::kIOThreadName[] = "ThreadForIO"; | 132 const char SessionManagerService::kIOThreadName[] = "ThreadForIO"; |
| 133 // static | |
| 134 const char SessionManagerService::kKeygenExecutable[] = "/sbin/keygen"; | |
| 135 // static | |
| 136 const char SessionManagerService::kTemporaryKeyFilename[] = "key.pub"; | |
| 133 | 137 |
| 134 namespace { | 138 namespace { |
| 135 | 139 |
| 136 // Time we wait for child job to die (in seconds). | 140 // Time we wait for child job to die (in seconds). |
| 137 const int kKillTimeout = 3; | 141 const int kKillTimeout = 3; |
| 138 | 142 |
| 139 const int kMaxArgumentsSize = 512; | 143 const int kMaxArgumentsSize = 512; |
| 140 | 144 |
| 141 } // namespace | 145 } // namespace |
| 142 | 146 |
| 143 SessionManagerService::SessionManagerService( | 147 SessionManagerService::SessionManagerService( |
| 144 std::vector<ChildJobInterface*> child_jobs) | 148 std::vector<ChildJobInterface*> child_jobs) |
| 145 : child_jobs_(child_jobs.begin(), child_jobs.end()), | 149 : child_jobs_(child_jobs.begin(), child_jobs.end()), |
| 146 child_pids_(child_jobs.size(), -1), | 150 child_pids_(child_jobs.size(), -1), |
| 147 exit_on_child_done_(false), | 151 exit_on_child_done_(false), |
| 152 keygen_job_(NULL), | |
| 148 session_manager_(NULL), | 153 session_manager_(NULL), |
| 149 main_loop_(g_main_loop_new(NULL, FALSE)), | 154 main_loop_(g_main_loop_new(NULL, FALSE)), |
| 150 system_(new SystemUtils), | 155 system_(new SystemUtils), |
| 151 nss_(NssUtil::Create()), | 156 nss_(NssUtil::Create()), |
| 152 key_(new OwnerKey(nss_->GetOwnerKeyFilePath())), | 157 key_(new OwnerKey(nss_->GetOwnerKeyFilePath())), |
| 153 store_(new PrefStore(FilePath(PrefStore::kDefaultPath))), | 158 store_(new PrefStore(FilePath(PrefStore::kDefaultPath))), |
| 154 upstart_signal_emitter_(new UpstartSignalEmitter), | 159 upstart_signal_emitter_(new UpstartSignalEmitter), |
| 155 session_started_(false), | 160 session_started_(false), |
| 156 io_thread_(kIOThreadName), | 161 io_thread_(kIOThreadName), |
| 157 dont_use_directly_(new MessageLoopForUI), | 162 dont_use_directly_(new MessageLoopForUI), |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 StoreOwnerProperties(NULL); | 477 StoreOwnerProperties(NULL); |
| 473 // Now, the flip side...if we believe the current user to be the owner | 478 // Now, the flip side...if we believe the current user to be the owner |
| 474 // based on the cros.owner.device setting, and he DOESN'T have the private | 479 // based on the cros.owner.device setting, and he DOESN'T have the private |
| 475 // half of the public key, we must mitigate. | 480 // half of the public key, we must mitigate. |
| 476 if (CurrentUserIsOwner(error) && | 481 if (CurrentUserIsOwner(error) && |
| 477 !CurrentUserHasOwnerKey(key_->public_key_der(), error)) { | 482 !CurrentUserHasOwnerKey(key_->public_key_der(), error)) { |
| 478 if (!(*OUT_done = mitigator_->Mitigate())) | 483 if (!(*OUT_done = mitigator_->Mitigate())) |
| 479 return FALSE; | 484 return FALSE; |
| 480 } | 485 } |
| 481 | 486 |
| 482 if (set_uid_) { | 487 *OUT_done = |
| 483 *OUT_done = | 488 upstart_signal_emitter_->EmitSignal( |
| 484 upstart_signal_emitter_->EmitSignal( | 489 "start-user-session", |
| 485 "start-user-session", | 490 StringPrintf("CHROMEOS_USER=%s", current_user_.c_str()), |
| 486 StringPrintf("CHROMEOS_USER=%s USER_ID=%d", | 491 error); |
| 487 current_user_.c_str(), uid_), | |
| 488 error); | |
| 489 } else { | |
| 490 *OUT_done = | |
| 491 upstart_signal_emitter_->EmitSignal( | |
| 492 "start-user-session", | |
| 493 StringPrintf("CHROMEOS_USER=%s", current_user_.c_str()), | |
| 494 error); | |
| 495 } | |
| 496 | 492 |
| 497 if (*OUT_done) { | 493 if (*OUT_done) { |
| 498 for (size_t i_child = 0; i_child < child_jobs_.size(); ++i_child) { | 494 for (size_t i_child = 0; i_child < child_jobs_.size(); ++i_child) { |
| 499 ChildJobInterface* child_job = child_jobs_[i_child]; | 495 ChildJobInterface* child_job = child_jobs_[i_child]; |
| 500 child_job->StartSession(current_user_); | 496 child_job->StartSession(current_user_); |
| 501 } | 497 } |
| 502 session_started_ = true; | 498 session_started_ = true; |
| 503 DLOG(INFO) << "emitting D-Bus signal SessionStateChanged:started"; | 499 DLOG(INFO) << "emitting D-Bus signal SessionStateChanged:started"; |
| 504 if (signals_[kSignalSessionStateChanged]) { | 500 if (signals_[kSignalSessionStateChanged]) { |
| 505 g_signal_emit(session_manager_, | 501 g_signal_emit(session_manager_, |
| 506 signals_[kSignalSessionStateChanged], | 502 signals_[kSignalSessionStateChanged], |
| 507 0, "started", current_user_.c_str()); | 503 0, "started", current_user_.c_str()); |
| 508 } | 504 } |
| 505 if (key_->HaveCheckedDisk() && !key_->IsPopulated()) | |
| 506 StartKeyGeneration(); | |
| 509 } | 507 } |
| 510 | 508 |
| 511 return *OUT_done; | 509 return *OUT_done; |
| 512 } | 510 } |
| 513 | 511 |
| 512 void SessionManagerService::HandleKeygenExit(GPid pid, | |
| 513 gint status, | |
| 514 gpointer data) { | |
| 515 SessionManagerService* manager = static_cast<SessionManagerService*>(data); | |
| 516 int i_child = manager->FindChildByPid(pid); | |
| 517 manager->child_pids_[i_child] = -1; | |
| 518 delete *(manager->child_jobs_.erase(manager->child_jobs_.begin() + i_child)); | |
| 519 | |
| 520 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { | |
| 521 std::string key; | |
| 522 file_util::ReadFileToString( | |
| 523 FilePath(file_util::GetHomeDir().AppendASCII(kTemporaryKeyFilename)), | |
| 524 &key); | |
| 525 manager->ValidateAndStoreOwnerKey(key); | |
| 526 } else { | |
| 527 if (WIFSIGNALED(status)) | |
| 528 LOG(ERROR) << "keygen exited on signal " << WTERMSIG(status); | |
| 529 else | |
| 530 LOG(ERROR) << "keygen exited with exit code " << WEXITSTATUS(status); | |
| 531 } | |
| 532 } | |
| 533 | |
| 534 void SessionManagerService::ValidateAndStoreOwnerKey(const std::string& buf) { | |
| 535 std::vector<uint8> pub_key; | |
| 536 NssUtil::KeyFromBuffer(buf, &pub_key); | |
| 537 | |
| 538 if (!CurrentUserHasOwnerKey(pub_key, NULL)) { | |
| 539 SendSignal(chromium::kOwnerKeySetSignal, false); | |
| 540 return; | |
| 541 } | |
| 542 | |
| 543 if (!key_->PopulateFromBuffer(pub_key)) { | |
| 544 SendSignal(chromium::kOwnerKeySetSignal, false); | |
| 545 return; | |
| 546 } | |
| 547 io_thread_.message_loop()->PostTask( | |
| 548 FROM_HERE, NewRunnableMethod(this, &SessionManagerService::PersistKey)); | |
| 549 StoreOwnerProperties(NULL); | |
| 550 } | |
| 551 | |
| 552 void SessionManagerService::StartKeyGeneration() { | |
| 553 if (!keygen_job_.get()) { | |
| 554 LOG(INFO) << "Creating keygen job"; | |
| 555 std::vector<std::string> keygen_argv; | |
| 556 keygen_argv.push_back(kKeygenExecutable); | |
| 557 keygen_argv.push_back( | |
| 558 file_util::GetHomeDir().AppendASCII(kTemporaryKeyFilename).value()); | |
|
Will Drewry
2011/02/23 03:30:16
I was going to suggest a random location, but sinc
| |
| 559 keygen_job_.reset(new ChildJob(keygen_argv)); | |
| 560 } | |
| 561 | |
| 562 if (set_uid_) | |
| 563 keygen_job_->SetDesiredUid(uid_); | |
| 564 int pid = key_->StartGeneration(keygen_job_.get()); | |
| 565 g_child_watch_add_full(G_PRIORITY_HIGH_IDLE, | |
| 566 pid, | |
| 567 HandleKeygenExit, | |
| 568 this, | |
| 569 NULL); | |
| 570 child_jobs_.push_back(keygen_job_.release()); | |
| 571 child_pids_.push_back(pid); | |
| 572 } | |
| 573 | |
| 514 gboolean SessionManagerService::StopSession(gchar* unique_identifier, | 574 gboolean SessionManagerService::StopSession(gchar* unique_identifier, |
| 515 gboolean* OUT_done, | 575 gboolean* OUT_done, |
| 516 GError** error) { | 576 GError** error) { |
| 517 // Most calls to StopSession() will log the reason for the call. | 577 // Most calls to StopSession() will log the reason for the call. |
| 518 // If you don't see a log message saying the reason for the call, it is | 578 // If you don't see a log message saying the reason for the call, it is |
| 519 // likely a DBUS message. See interface.cc for that call. | 579 // likely a DBUS message. See interface.cc for that call. |
| 520 LOG(INFO) << "SessionManagerService StopSession"; | 580 LOG(INFO) << "SessionManagerService StopSession"; |
| 521 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, | 581 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, |
| 522 ServiceShutdown, | 582 ServiceShutdown, |
| 523 this, | 583 this, |
| 524 NULL); | 584 NULL); |
| 525 // TODO(cmasone): re-enable these when we try to enable logout without exiting | 585 // TODO(cmasone): re-enable these when we try to enable logout without exiting |
| 526 // the session manager | 586 // the session manager |
| 527 // child_job_->StopSession(); | 587 // child_job_->StopSession(); |
| 528 // session_started_ = false; | 588 // session_started_ = false; |
| 529 return *OUT_done = TRUE; | 589 return *OUT_done = TRUE; |
| 530 } | 590 } |
| 531 | 591 |
| 532 gboolean SessionManagerService::SetOwnerKey(GArray* public_key_der, | 592 gboolean SessionManagerService::SetOwnerKey(GArray* public_key_der, |
| 533 GError** error) { | 593 GError** error) { |
| 534 LOG(INFO) << "key size is " << public_key_der->len; | 594 SetGError(error, |
| 535 | 595 CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, |
| 536 if (!session_started_) { | 596 "The session_manager now sets the Owner's public key."); |
| 537 SetGError(error, | 597 // Just to be safe, send back a nACK in addition to returning an error. |
| 538 CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, | 598 SendSignal(chromium::kOwnerKeySetSignal, false); |
| 539 "Cannot set the owner's public key outside of a session."); | 599 return FALSE; |
| 540 return FALSE; | |
| 541 } | |
| 542 | |
| 543 std::vector<uint8> pub_key; | |
| 544 NssUtil::KeyFromBuffer(public_key_der, &pub_key); | |
| 545 | |
| 546 if (!CurrentUserHasOwnerKey(pub_key, error)) { | |
| 547 return FALSE; // error set by CurrentUserHasOwnerKey() | |
| 548 } | |
| 549 | |
| 550 if (!key_->PopulateFromBuffer(pub_key)) { | |
| 551 SetGError(error, | |
| 552 CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY, | |
| 553 "Attempted to set invalid key as owner's public key."); | |
| 554 return FALSE; | |
| 555 } | |
| 556 io_thread_.message_loop()->PostTask( | |
| 557 FROM_HERE, NewRunnableMethod(this, &SessionManagerService::PersistKey)); | |
| 558 return StoreOwnerProperties(error); | |
| 559 } | 600 } |
| 560 | 601 |
| 561 gboolean SessionManagerService::Unwhitelist(gchar* email_address, | 602 gboolean SessionManagerService::Unwhitelist(gchar* email_address, |
| 562 GArray* signature, | 603 GArray* signature, |
| 563 GError** error) { | 604 GError** error) { |
| 564 LOG(INFO) << "Unwhitelisting " << email_address; | 605 LOG(INFO) << "Unwhitelisting " << email_address; |
| 565 if (!key_->IsPopulated()) { | 606 if (!key_->IsPopulated()) { |
| 566 SetGError(error, | 607 SetGError(error, |
| 567 CHROMEOS_LOGIN_ERROR_NO_OWNER_KEY, | 608 CHROMEOS_LOGIN_ERROR_NO_OWNER_KEY, |
| 568 "Attempt to unwhitelist before owner's key is set."); | 609 "Attempt to unwhitelist before owner's key is set."); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 777 DLOG(INFO) << " Exited...somehow, without an exit code or a signal??"; | 818 DLOG(INFO) << " Exited...somehow, without an exit code or a signal??"; |
| 778 } | 819 } |
| 779 | 820 |
| 780 // If the child _ever_ exits uncleanly, we want to start it up again. | 821 // If the child _ever_ exits uncleanly, we want to start it up again. |
| 781 SessionManagerService* manager = static_cast<SessionManagerService*>(data); | 822 SessionManagerService* manager = static_cast<SessionManagerService*>(data); |
| 782 | 823 |
| 783 // Do nothing if already shutting down. | 824 // Do nothing if already shutting down. |
| 784 if (manager->shutting_down_) | 825 if (manager->shutting_down_) |
| 785 return; | 826 return; |
| 786 | 827 |
| 787 int i_child = -1; | 828 ChildJobInterface* child_job = NULL; |
| 788 for (int i = 0; i < manager->child_pids_.size(); ++i) { | 829 int i_child = manager->FindChildByPid(pid); |
| 789 if (manager->child_pids_[i] == pid) { | 830 if (i_child >= 0) { |
| 790 i_child = i; | 831 child_job = manager->child_jobs_[i_child]; |
| 791 manager->child_pids_[i] = -1; | 832 manager->child_pids_[i_child] = -1; |
| 792 break; | |
| 793 } | |
| 794 } | 833 } |
| 795 | 834 |
| 796 ChildJobInterface* child_job = i_child >= 0 | |
| 797 ? manager->child_jobs_[i_child] | |
| 798 : NULL; | |
| 799 | |
| 800 LOG(ERROR) << StringPrintf( | 835 LOG(ERROR) << StringPrintf( |
| 801 "Process %s(%d) exited.", | 836 "Process %s(%d) exited.", |
| 802 child_job ? child_job->GetName().c_str() : "", | 837 child_job ? child_job->GetName().c_str() : "", |
| 803 pid); | 838 pid); |
| 804 if (manager->screen_locked_) { | 839 if (manager->screen_locked_) { |
| 805 LOG(ERROR) << "Screen locked, shutting down", | 840 LOG(ERROR) << "Screen locked, shutting down", |
| 806 ServiceShutdown(data); | 841 ServiceShutdown(data); |
| 807 return; | 842 return; |
| 808 } | 843 } |
| 809 | 844 |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1021 if (email_string != kIncognitoUser && !ValidateEmail(email_string)) { | 1056 if (email_string != kIncognitoUser && !ValidateEmail(email_string)) { |
| 1022 SetGError(error, | 1057 SetGError(error, |
| 1023 CHROMEOS_LOGIN_ERROR_INVALID_EMAIL, | 1058 CHROMEOS_LOGIN_ERROR_INVALID_EMAIL, |
| 1024 "Provided email address is not valid. ASCII only."); | 1059 "Provided email address is not valid. ASCII only."); |
| 1025 return FALSE; | 1060 return FALSE; |
| 1026 } | 1061 } |
| 1027 current_user_ = StringToLowerASCII(email_string); | 1062 current_user_ = StringToLowerASCII(email_string); |
| 1028 return TRUE; | 1063 return TRUE; |
| 1029 } | 1064 } |
| 1030 | 1065 |
| 1066 int SessionManagerService::FindChildByPid(int pid) { | |
| 1067 for (int i = 0; i < child_pids_.size(); ++i) { | |
| 1068 if (child_pids_[i] == pid) | |
| 1069 return i; | |
| 1070 } | |
| 1071 return -1; | |
| 1072 } | |
| 1073 | |
| 1031 void SessionManagerService::CleanupChildren(int timeout) { | 1074 void SessionManagerService::CleanupChildren(int timeout) { |
| 1032 vector<pair<int, uid_t> > pids_to_kill; | 1075 vector<pair<int, uid_t> > pids_to_kill; |
| 1033 | 1076 |
| 1034 for (size_t i = 0; i < child_pids_.size(); ++i) { | 1077 for (size_t i = 0; i < child_pids_.size(); ++i) { |
| 1035 const int pid = child_pids_[i]; | 1078 const int pid = child_pids_[i]; |
| 1036 if (pid < 0) | 1079 if (pid < 0) |
| 1037 continue; | 1080 continue; |
| 1038 | 1081 |
| 1039 ChildJobInterface* job = child_jobs_[i]; | 1082 ChildJobInterface* job = child_jobs_[i]; |
| 1040 if (job->ShouldNeverKill()) | 1083 if (job->ShouldNeverKill()) |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1174 arg_list.push_back(args[i_arg]); | 1217 arg_list.push_back(args[i_arg]); |
| 1175 } | 1218 } |
| 1176 } | 1219 } |
| 1177 if (arg_list.size()) { | 1220 if (arg_list.size()) { |
| 1178 arg_lists.push_back(arg_list); | 1221 arg_lists.push_back(arg_list); |
| 1179 } | 1222 } |
| 1180 return arg_lists; | 1223 return arg_lists; |
| 1181 } | 1224 } |
| 1182 | 1225 |
| 1183 } // namespace login_manager | 1226 } // namespace login_manager |
| OLD | NEW |