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 |