Home | History | Annotate | Download | only in cros
      1 // Copyright (c) 2011 The Chromium 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 #include "chrome/browser/chromeos/cros/login_library.h"
      6 
      7 #include "base/message_loop.h"
      8 #include "base/task.h"
      9 #include "base/timer.h"
     10 #include "chrome/browser/browser_process.h"
     11 #include "chrome/browser/chromeos/cros/cros_library.h"
     12 #include "chrome/browser/chromeos/login/signed_settings.h"
     13 #include "chrome/browser/chromeos/login/signed_settings_temp_storage.h"
     14 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
     15 #include "chrome/browser/prefs/pref_service.h"
     16 #include "content/browser/browser_thread.h"
     17 #include "content/common/notification_service.h"
     18 #include "content/common/notification_type.h"
     19 
     20 namespace em = enterprise_management;
     21 namespace chromeos {
     22 
     23 class LoginLibraryImpl : public LoginLibrary {
     24  public:
     25   LoginLibraryImpl()
     26       : job_restart_request_(NULL),
     27         set_owner_key_callback_(NULL),
     28         whitelist_op_callback_(NULL),
     29         property_op_callback_(NULL) {
     30     if (CrosLibrary::Get()->EnsureLoaded())
     31       Init();
     32   }
     33 
     34   virtual ~LoginLibraryImpl() {
     35     if (session_connection_) {
     36       chromeos::DisconnectSession(session_connection_);
     37     }
     38   }
     39 
     40   bool EmitLoginPromptReady() {
     41     return chromeos::EmitLoginPromptReady();
     42   }
     43 
     44   bool CheckWhitelist(const std::string& email,
     45                       std::vector<uint8>* OUT_signature) {
     46     CryptoBlob* sig = NULL;
     47     if (chromeos::CheckWhitelistSafe(email.c_str(), &sig)) {
     48       OUT_signature->assign(sig->data, sig->data + sig->length);
     49       chromeos::FreeCryptoBlob(sig);
     50       return true;
     51     }
     52     return false;
     53   }
     54 
     55   void RequestRetrievePolicy(RetrievePolicyCallback callback, void* delegate) {
     56     DCHECK(callback) << "must provide a callback to RequestRetrievePolicy()";
     57     chromeos::RetrievePolicy(callback, delegate);
     58   }
     59 
     60   void RequestRetrieveProperty(const std::string& name,
     61                                RetrievePropertyCallback callback,
     62                                void* user_data) {
     63     DCHECK(callback) << "must provide a callback to RequestRetrieveProperty()";
     64     chromeos::RequestRetrieveProperty(name.c_str(), callback, user_data);
     65   }
     66 
     67   void RequestStorePolicy(const std::string& policy,
     68                           StorePolicyCallback callback,
     69                           void* delegate) {
     70     DCHECK(callback) << "must provide a callback to StorePolicy()";
     71     chromeos::StorePolicy(policy.c_str(), policy.length(), callback, delegate);
     72   }
     73 
     74   bool StorePropertyAsync(const std::string& name,
     75                           const std::string& value,
     76                           const std::vector<uint8>& signature,
     77                           Delegate* callback) {
     78     DCHECK(callback) << "must provide a callback to StorePropertyAsync()";
     79     if (property_op_callback_)
     80       return false;
     81     property_op_callback_ = callback;
     82     Property* prop = chromeos::CreateProperty(name.c_str(),
     83                                               value.c_str(),
     84                                               &signature[0],
     85                                               signature.size());
     86     bool rv = chromeos::StorePropertySafe(prop);
     87     chromeos::FreeProperty(prop);
     88     return rv;
     89   }
     90 
     91   bool UnwhitelistAsync(const std::string& email,
     92                         const std::vector<uint8>& signature,
     93                         Delegate* callback) {
     94     DCHECK(callback) << "must provide a callback to UnwhitelistAsync()";
     95     if (whitelist_op_callback_)
     96       return false;
     97     whitelist_op_callback_ =  callback;
     98     CryptoBlob* sig = chromeos::CreateCryptoBlob(&signature[0],
     99                                                  signature.size());
    100     bool rv = chromeos::UnwhitelistSafe(email.c_str(), sig);
    101     chromeos::FreeCryptoBlob(sig);
    102     return rv;
    103   }
    104 
    105   bool WhitelistAsync(const std::string& email,
    106                       const std::vector<uint8>& signature,
    107                       Delegate* callback) {
    108     DCHECK(callback) << "must provide a callback to WhitelistAsync()";
    109     if (whitelist_op_callback_)
    110       return false;
    111     whitelist_op_callback_ =  callback;
    112     CryptoBlob* sig = chromeos::CreateCryptoBlob(&signature[0],
    113                                                  signature.size());
    114     bool rv = chromeos::WhitelistSafe(email.c_str(), sig);
    115     chromeos::FreeCryptoBlob(sig);
    116     return rv;
    117   }
    118 
    119   // DEPRECATED.
    120   bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
    121     NOTREACHED();
    122     UserList* list = NULL;
    123     if (chromeos::EnumerateWhitelistedSafe(&list)) {
    124       for (int i = 0; i < list->num_users; i++)
    125         whitelisted->push_back(std::string(list->users[i]));
    126       chromeos::FreeUserList(list);
    127       return true;
    128     }
    129     return false;
    130   }
    131 
    132   bool StartSession(const std::string& user_email,
    133                     const std::string& unique_id /* unused */) {
    134     // only pass unique_id through once we use it for something.
    135     return chromeos::StartSession(user_email.c_str(), "");
    136   }
    137 
    138   bool StopSession(const std::string& unique_id /* unused */) {
    139     // only pass unique_id through once we use it for something.
    140     return chromeos::StopSession("");
    141   }
    142 
    143   bool RestartEntd() {
    144     return chromeos::RestartEntd();
    145   }
    146 
    147   bool RestartJob(int pid, const std::string& command_line) {
    148     if (job_restart_request_) {
    149       NOTREACHED();
    150       return false;
    151     }
    152     job_restart_request_ = new JobRestartRequest(pid, command_line);
    153     return true;
    154   }
    155 
    156  private:
    157   class JobRestartRequest
    158       : public base::RefCountedThreadSafe<JobRestartRequest> {
    159    public:
    160     JobRestartRequest(int pid, const std::string& command_line)
    161         : pid_(pid),
    162           command_line_(command_line),
    163           local_state_(g_browser_process->local_state()) {
    164       AddRef();
    165       if (local_state_) {
    166         // XXX: normally this call must not be needed, however RestartJob
    167         // just kills us so settings may be lost. See http://crosbug.com/13102
    168         local_state_->CommitPendingWrite();
    169         timer_.Start(
    170             base::TimeDelta::FromSeconds(3), this,
    171             &JobRestartRequest::RestartJob);
    172         // Post task on file thread thus it occurs last on task queue, so it
    173         // would be executed after committing pending write on file thread.
    174         BrowserThread::PostTask(
    175             BrowserThread::FILE, FROM_HERE,
    176             NewRunnableMethod(this, &JobRestartRequest::RestartJob));
    177       } else {
    178         RestartJob();
    179       }
    180     }
    181 
    182    private:
    183     void RestartJob() {
    184       if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    185         if (!chromeos::RestartJob(pid_, command_line_.c_str()))
    186           NOTREACHED();
    187       } else {
    188         BrowserThread::PostTask(
    189             BrowserThread::UI, FROM_HERE,
    190             NewRunnableMethod(this, &JobRestartRequest::RestartJob));
    191         MessageLoop::current()->AssertIdle();
    192       }
    193     }
    194 
    195     int pid_;
    196     std::string command_line_;
    197     PrefService* local_state_;
    198     base::OneShotTimer<JobRestartRequest> timer_;
    199   };
    200 
    201   class StubDelegate
    202       : public SignedSettings::Delegate<const em::PolicyFetchResponse&> {
    203    public:
    204     StubDelegate() : polfetcher_(NULL) {}
    205     virtual ~StubDelegate() {}
    206     void set_fetcher(SignedSettings* s) { polfetcher_ = s; }
    207     SignedSettings* fetcher() { return polfetcher_.get(); }
    208     // Implementation of SignedSettings::Delegate
    209     virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
    210                                        const em::PolicyFetchResponse& value) {
    211       VLOG(2) << "Done Fetching Policy";
    212       delete this;
    213     }
    214    private:
    215     scoped_refptr<SignedSettings> polfetcher_;
    216     DISALLOW_COPY_AND_ASSIGN(StubDelegate);
    217   };
    218 
    219   static void Handler(void* object, const OwnershipEvent& event) {
    220     LoginLibraryImpl* self = static_cast<LoginLibraryImpl*>(object);
    221     switch (event) {
    222       case SetKeySuccess:
    223         self->CompleteSetOwnerKey(true);
    224         break;
    225       case SetKeyFailure:
    226         self->CompleteSetOwnerKey(false);
    227         break;
    228       case WhitelistOpSuccess:
    229         self->CompleteWhitelistOp(true);
    230         break;
    231       case WhitelistOpFailure:
    232         self->CompleteWhitelistOp(false);
    233         break;
    234       case PropertyOpSuccess:
    235         self->CompletePropertyOp(true);
    236         break;
    237       case PropertyOpFailure:
    238         self->CompletePropertyOp(false);
    239         break;
    240       default:
    241         NOTREACHED();
    242         break;
    243     }
    244   }
    245 
    246   void Init() {
    247     session_connection_ = chromeos::MonitorSession(&Handler, this);
    248   }
    249 
    250   void CompleteSetOwnerKey(bool value) {
    251     VLOG(1) << "Owner key generation: " << (value ? "success" : "fail");
    252     NotificationType result =
    253         NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED;
    254     if (!value)
    255       result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_FAILED;
    256 
    257     // Whether we exported the public key or not, send a notification indicating
    258     // that we're done with this attempt.
    259     NotificationService::current()->Notify(result,
    260                                            NotificationService::AllSources(),
    261                                            NotificationService::NoDetails());
    262 
    263     // We stored some settings in transient storage before owner was assigned.
    264     // Now owner is assigned and key is generated and we should persist
    265     // those settings into signed storage.
    266     if (g_browser_process && g_browser_process->local_state()) {
    267       SignedSettingsTempStorage::Finalize(g_browser_process->local_state());
    268     }
    269   }
    270 
    271   void CompleteWhitelistOp(bool result) {
    272     if (whitelist_op_callback_) {
    273       whitelist_op_callback_->OnComplete(result);
    274       whitelist_op_callback_ = NULL;
    275     }
    276   }
    277 
    278   void CompletePropertyOp(bool result) {
    279     if (result) {
    280       StubDelegate* stub = new StubDelegate();  // Manages its own lifetime.
    281       stub->set_fetcher(SignedSettings::CreateRetrievePolicyOp(stub));
    282       stub->fetcher()->Execute();
    283     }
    284   }
    285 
    286   chromeos::SessionConnection session_connection_;
    287   JobRestartRequest* job_restart_request_;
    288 
    289   Delegate* set_owner_key_callback_;
    290   Delegate* whitelist_op_callback_;
    291   Delegate* property_op_callback_;
    292 
    293   DISALLOW_COPY_AND_ASSIGN(LoginLibraryImpl);
    294 };
    295 
    296 class LoginLibraryStubImpl : public LoginLibrary {
    297  public:
    298   LoginLibraryStubImpl() {}
    299   virtual ~LoginLibraryStubImpl() {}
    300 
    301   bool EmitLoginPromptReady() { return true; }
    302   bool CheckWhitelist(const std::string& email,
    303                       std::vector<uint8>* OUT_signature) {
    304     OUT_signature->assign(2, 0);
    305     return true;
    306   }
    307   void RequestRetrievePolicy(RetrievePolicyCallback callback, void* delegate) {
    308     callback(delegate, "", 0);
    309   }
    310   void RequestRetrieveProperty(const std::string& name,
    311                                RetrievePropertyCallback callback,
    312                                void* user_data) {
    313     uint8 sig_bytes[] = { 0, 0 };
    314     CryptoBlob sig = { sig_bytes, arraysize(sig_bytes) };
    315     Property prop = {
    316       "prop_name",
    317       "stub",
    318       &sig,
    319     };
    320 
    321     callback(user_data, true, &prop);
    322   }
    323   void RequestStorePolicy(const std::string& policy,
    324                           StorePolicyCallback callback,
    325                           void* delegate) {
    326     callback(delegate, true);
    327   }
    328   bool StorePropertyAsync(const std::string& name,
    329                           const std::string& value,
    330                           const std::vector<uint8>& signature,
    331                           Delegate* callback) {
    332     BrowserThread::PostTask(
    333         BrowserThread::UI, FROM_HERE,
    334         NewRunnableFunction(&DoStubCallback, callback));
    335     return true;
    336   }
    337   bool UnwhitelistAsync(const std::string& email,
    338                         const std::vector<uint8>& signature,
    339                         Delegate* callback) {
    340     BrowserThread::PostTask(
    341         BrowserThread::UI, FROM_HERE,
    342         NewRunnableFunction(&DoStubCallback, callback));
    343     return true;
    344   }
    345   bool WhitelistAsync(const std::string& email,
    346                       const std::vector<uint8>& signature,
    347                       Delegate* callback) {
    348     BrowserThread::PostTask(
    349         BrowserThread::UI, FROM_HERE,
    350         NewRunnableFunction(&DoStubCallback, callback));
    351     return true;
    352   }
    353   bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
    354     return true;
    355   }
    356   bool StartSession(const std::string& user_email,
    357                     const std::string& unique_id /* unused */) { return true; }
    358   bool StopSession(const std::string& unique_id /* unused */) { return true; }
    359   bool RestartJob(int pid, const std::string& command_line) { return true; }
    360   bool RestartEntd() { return true; }
    361 
    362  private:
    363   static void DoStubCallback(Delegate* callback) {
    364     callback->OnComplete(true);
    365   }
    366 
    367   DISALLOW_COPY_AND_ASSIGN(LoginLibraryStubImpl);
    368 };
    369 
    370 // static
    371 LoginLibrary* LoginLibrary::GetImpl(bool stub) {
    372   if (stub)
    373     return new LoginLibraryStubImpl();
    374   else
    375     return new LoginLibraryImpl();
    376 }
    377 
    378 }  // namespace chromeos
    379