Commit message: None
CVE: CVE-2011-3105
CWE: CWE-399
Vulnerability description: Use-after-free vulnerability in the Cascading Style Sheets (CSS) implementation in Google Chrome before 19.0.1084.52 allows remote attackers to cause a denial of service or possibly have unspecified other impact via vectors related to the :first-letter pseudo-element.

Project: Chrome

void SyncManager::DoneRefreshNigori(const base::Closure& done_callback,
                                    bool is_ready) {
  if (is_ready)
    data_->RefreshEncryption();
  done_callback.Run();
}

Project: Chrome

syncable::ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
    syncable::ModelTypeSet types,
    sync_api::UserShare* share) {
  syncable::ScopedDirLookup lookup(share->dir_manager.get(),
                                   share->name);
  if (!lookup.good()) {
    NOTREACHED() << "ScopedDirLookup failed for "
                  << "GetTypesWithEmptyProgressMarkerToken";
    return syncable::ModelTypeSet();
  }

  syncable::ModelTypeSet result;
  for (syncable::ModelTypeSet::Iterator i = types.First();
       i.Good(); i.Inc()) {
    sync_pb::DataTypeProgressMarker marker;
    lookup->GetDownloadProgress(i.Get(), &marker);

    if (marker.token().empty())
      result.Put(i.Get());

  }
  return result;
}

Project: Chrome

void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
    const ImmutableWriteTransactionInfo& write_transaction_info,
    syncable::BaseTransaction* trans) {
  if (!scheduler()) {
    return;
  }

  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
      "CALCULATE_CHANGES called with unapplied old changes.";

  syncable::ModelType mutated_model_type = syncable::UNSPECIFIED;

  const syncable::ImmutableEntryKernelMutationMap& mutations =
      write_transaction_info.Get().mutations;
  for (syncable::EntryKernelMutationMap::const_iterator it =
           mutations.Get().begin(); it != mutations.Get().end(); ++it) {
    if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) {
      continue;
    }

    syncable::ModelType model_type =
        syncable::GetModelTypeFromSpecifics(
            it->second.mutated.ref(SPECIFICS));
    if (model_type < syncable::FIRST_REAL_MODEL_TYPE) {
      NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
      continue;
    }

    if (mutated_model_type == syncable::UNSPECIFIED) {
      mutated_model_type = model_type;
      break;
    }
  }

  if (mutated_model_type != syncable::UNSPECIFIED) {
    if (weak_handle_this_.IsInitialized()) {
      weak_handle_this_.Call(FROM_HERE,
                             &SyncInternal::RequestNudgeForDataType,
                             FROM_HERE,
                             mutated_model_type);
    } else {
      NOTREACHED();
    }
  }
}

Project: Chrome

void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
    const ImmutableWriteTransactionInfo& write_transaction_info,
    syncable::BaseTransaction* trans) {
  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
      "CALCULATE_CHANGES called with unapplied old changes.";

  Cryptographer* crypto = dir_manager()->GetCryptographer(trans);
  const syncable::ImmutableEntryKernelMutationMap& mutations =
      write_transaction_info.Get().mutations;
  for (syncable::EntryKernelMutationMap::const_iterator it =
           mutations.Get().begin(); it != mutations.Get().end(); ++it) {
    bool existed_before = !it->second.original.ref(syncable::IS_DEL);
    bool exists_now = !it->second.mutated.ref(syncable::IS_DEL);

    syncable::ModelType type =
        syncable::GetModelTypeFromSpecifics(
            it->second.mutated.ref(SPECIFICS));
    if (type < syncable::FIRST_REAL_MODEL_TYPE)
      continue;

    int64 handle = it->first;
    if (exists_now && !existed_before)
      change_buffers_[type].PushAddedItem(handle);
    else if (!exists_now && existed_before)
      change_buffers_[type].PushDeletedItem(handle);
    else if (exists_now && existed_before &&
             VisiblePropertiesDiffer(it->second, crypto)) {
      change_buffers_[type].PushUpdatedItem(
          handle, VisiblePositionsDiffer(it->second));
    }

    SetExtraChangeRecordData(handle, type, &change_buffers_[type], crypto,
                             it->second.original, existed_before, exists_now);
  }
}

Project: Chrome

bool SyncManager::Init(
    const FilePath& database_location,
    const WeakHandle<JsEventHandler>& event_handler,
    const std::string& sync_server_and_path,
    int sync_server_port,
    bool use_ssl,
    HttpPostProviderFactory* post_factory,
    ModelSafeWorkerRegistrar* registrar,
    ChangeDelegate* change_delegate,
    const std::string& user_agent,
    const SyncCredentials& credentials,
    sync_notifier::SyncNotifier* sync_notifier,
    const std::string& restored_key_for_bootstrapping,
    bool setup_for_test_mode,
    UnrecoverableErrorHandler* unrecoverable_error_handler) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(post_factory);
  DVLOG(1) << "SyncManager starting Init...";
  string server_string(sync_server_and_path);
  return data_->Init(database_location,
                     event_handler,
                     server_string,
                     sync_server_port,
                     use_ssl,
                     post_factory,
                     registrar,
                     change_delegate,
                     user_agent,
                     credentials,
                     sync_notifier,
                     restored_key_for_bootstrapping,
                     setup_for_test_mode,
                     unrecoverable_error_handler);
}

Project: Chrome

bool InitialSyncEndedForTypes(syncable::ModelTypeSet types,
                              sync_api::UserShare* share) {
  syncable::ScopedDirLookup lookup(share->dir_manager.get(),
                                   share->name);
  if (!lookup.good()) {
    DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
    return false;
  }

  for (syncable::ModelTypeSet::Iterator i = types.First();
       i.Good(); i.Inc()) {
    if (!lookup->initial_sync_ended_for_type(i.Get()))
      return false;
  }
  return true;
}

Project: Chrome

void SyncManager::SyncInternal::MaybeSetSyncTabsInNigoriNode(
    const ModelTypeSet enabled_types) {
  if (initialized_ && enabled_types.Has(syncable::SESSIONS)) {
    WriteTransaction trans(FROM_HERE, GetUserShare());
    WriteNode node(&trans);
    if (!node.InitByTagLookup(kNigoriTag)) {
      NOTREACHED() << "Unable to set 'sync_tabs' bit because Nigori node not "
                   << "found.";
      return;
    }

    sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
    specifics.set_sync_tabs(true);
    node.SetNigoriSpecifics(specifics);
  }
}

Project: Chrome

void SyncManager::SyncInternal::OnIncomingNotification(
    const syncable::ModelTypePayloadMap& type_payloads,
    sync_notifier::IncomingNotificationSource source) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (source == sync_notifier::LOCAL_NOTIFICATION) {
    if (scheduler()) {
      scheduler()->ScheduleNudgeWithPayloads(
          TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
          browser_sync::NUDGE_SOURCE_LOCAL_REFRESH,
          type_payloads, FROM_HERE);
    }
  } else if (!type_payloads.empty()) {
    if (scheduler()) {
      scheduler()->ScheduleNudgeWithPayloads(
          TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
          browser_sync::NUDGE_SOURCE_NOTIFICATION,
          type_payloads, FROM_HERE);
    }
    allstatus_.IncrementNotificationsReceived();
    UpdateNotificationInfo(type_payloads);
  } else {
    LOG(WARNING) << "Sync received notification without any type information.";
  }

  if (js_event_handler_.IsInitialized()) {
    DictionaryValue details;
    ListValue* changed_types = new ListValue();
    details.Set("changedTypes", changed_types);
    for (syncable::ModelTypePayloadMap::const_iterator
             it = type_payloads.begin();
         it != type_payloads.end(); ++it) {
      const std::string& model_type_str =
          syncable::ModelTypeToString(it->first);
      changed_types->Append(Value::CreateStringValue(model_type_str));
    }
    details.SetString("source", (source == sync_notifier::LOCAL_NOTIFICATION) ?
        "LOCAL_NOTIFICATION" : "REMOTE_NOTIFICATION");
    js_event_handler_.Call(FROM_HERE,
                           &JsEventHandler::HandleJsEvent,
                           "onIncomingNotification",
                           JsEventDetails(&details));
  }
}

Project: Chrome

void SyncManager::SyncInternal::OnServerConnectionEvent(
    const ServerConnectionEvent& event) {
  DCHECK(thread_checker_.CalledOnValidThread());
  allstatus_.HandleServerConnectionEvent(event);
  if (event.connection_code ==
      browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnAuthError(AuthError::None()));
  }

  if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
    observing_ip_address_changes_ = false;
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
        OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
  }

  if (event.connection_code ==
      browser_sync::HttpResponse::SYNC_SERVER_ERROR) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
        OnAuthError(AuthError(AuthError::CONNECTION_FAILED)));
  }
}

Project: Chrome

void SyncManager::SyncInternal::OnSyncEngineEvent(
    const SyncEngineEvent& event) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
    ModelSafeRoutingInfo enabled_types;
    registrar_->GetModelSafeRoutingInfo(&enabled_types);
    {
      sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
      Cryptographer* cryptographer = trans.GetCryptographer();
      if (cryptographer->has_pending_keys()) {
        DVLOG(1) << "OnPassPhraseRequired Sent";
        sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
        FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                          OnPassphraseRequired(sync_api::REASON_DECRYPTION,
                                               pending_keys));
      } else if (!cryptographer->is_ready() &&
                 event.snapshot->initial_sync_ended.Has(syncable::NIGORI)) {
        DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
                 << "ready";
        FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                          OnPassphraseRequired(sync_api::REASON_ENCRYPTION,
                                               sync_pb::EncryptedData()));
      }

      allstatus_.SetCryptographerReady(cryptographer->is_ready());
      allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
      allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
    }

    if (!initialized_) {
      LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
                << "initialized";
      return;
    }

    if (!event.snapshot->has_more_to_sync) {
      DVLOG(1) << "Sending OnSyncCycleCompleted";
      FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                        OnSyncCycleCompleted(event.snapshot));
    }

    bool is_notifiable_commit =
        (event.snapshot->syncer_status.num_successful_commits > 0);
    if (is_notifiable_commit) {
      if (sync_notifier_.get()) {
        const ModelTypeSet changed_types =
            syncable::ModelTypePayloadMapToEnumSet(
                event.snapshot->source.types);
        sync_notifier_->SendNotification(changed_types);
      } else {
        DVLOG(1) << "Not sending notification: sync_notifier_ is NULL";
      }
    }
  }

  if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnStopSyncingPermanently());
    return;
  }

  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnClearServerDataSucceeded());
    return;
  }

  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnClearServerDataFailed());
    return;
  }

  if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnUpdatedToken(event.updated_token));
    return;
  }

  if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnActionableError(
                          event.snapshot->errors.sync_protocol_error));
    return;
  }

}

Project: Chrome

bool SyncManager::SyncInternal::OpenDirectory() {
  DCHECK(!initialized_) << "Should only happen once";

  change_observer_ =
      browser_sync::MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr());

  bool share_opened =
      dir_manager()->Open(
          username_for_share(),
          this,
          unrecoverable_error_handler_,
          browser_sync::MakeWeakHandle(
              js_mutation_event_observer_.AsWeakPtr()));
  if (!share_opened) {
    LOG(ERROR) << "Could not open share for:" << username_for_share();
    return false;
  }

  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
  if (!lookup.good()) {
    NOTREACHED();
    return false;
  }

  connection_manager()->set_client_id(lookup->cache_guid());
  return true;
}

Project: Chrome

void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
  Cryptographer* cryptographer = trans->GetCryptographer();
  if (!cryptographer || !cryptographer->is_ready())
    return;
  syncable::ModelTypeSet encrypted_types = GetEncryptedTypes(trans);
  ModelSafeRoutingInfo routes;
  registrar_->GetModelSafeRoutingInfo(&routes);
  std::string tag;
  for (syncable::ModelTypeSet::Iterator iter = encrypted_types.First();
       iter.Good(); iter.Inc()) {
    if (iter.Get() == syncable::PASSWORDS ||
        iter.Get() == syncable::NIGORI ||
        routes.count(iter.Get()) == 0)
      continue;
    ReadNode type_root(trans);
    tag = syncable::ModelTypeToRootTag(iter.Get());
    if (!type_root.InitByTagLookup(tag)) {
      continue;
    }

    std::queue<int64> to_visit;
    int64 child_id = type_root.GetFirstChildId();
    to_visit.push(child_id);
    while (!to_visit.empty()) {
      child_id = to_visit.front();
      to_visit.pop();
      if (child_id == kInvalidId)
        continue;

      WriteNode child(trans);
      if (!child.InitByIdLookup(child_id)) {
        NOTREACHED();
        continue;
      }
      if (child.GetIsFolder()) {
        to_visit.push(child.GetFirstChildId());
      }
      if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
        child.ResetFromSpecifics();
      }
      to_visit.push(child.GetSuccessorId());
    }
  }

  if (routes.count(syncable::PASSWORDS) > 0) {
    ReadNode passwords_root(trans);
    std::string passwords_tag =
        syncable::ModelTypeToRootTag(syncable::PASSWORDS);
    if (passwords_root.InitByTagLookup(passwords_tag)) {
      int64 child_id = passwords_root.GetFirstChildId();
      while (child_id != kInvalidId) {
        WriteNode child(trans);
        if (!child.InitByIdLookup(child_id)) {
          NOTREACHED();
          return;
        }
        child.SetPasswordSpecifics(child.GetPasswordSpecifics());
        child_id = child.GetSuccessorId();
      }
    }
  }

  FOR_EACH_OBSERVER(SyncManager::Observer, observers_, OnEncryptionComplete());
}

Project: Chrome

bool SyncManager::ReceivedExperimentalTypes(syncable::ModelTypeSet* to_add)
    const {
  ReadTransaction trans(FROM_HERE, GetUserShare());
  ReadNode node(&trans);
  if (!node.InitByTagLookup(kNigoriTag)) {
    DVLOG(1) << "Couldn't find Nigori node.";
    return false;
  }
  if (node.GetNigoriSpecifics().sync_tabs()) {
    to_add->Put(syncable::SESSIONS);
    return true;
  }
  return false;
}

Project: Chrome

void SyncManager::SyncInternal::RefreshEncryption() {
  DCHECK(initialized_);

  WriteTransaction trans(FROM_HERE, GetUserShare());
  WriteNode node(&trans);
  if (!node.InitByTagLookup(kNigoriTag)) {
    NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not "
                 << "found.";
    return;
  }

  Cryptographer* cryptographer = trans.GetCryptographer();

  if (!cryptographer->is_ready()) {
    DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not "
             << "initialized, prompting for passphrase.";
    sync_pb::EncryptedData pending_keys;
    if (cryptographer->has_pending_keys())
      pending_keys = cryptographer->GetPendingKeys();
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnPassphraseRequired(sync_api::REASON_DECRYPTION,
                                           pending_keys));
    return;
  }

  sync_pb::NigoriSpecifics nigori;
  nigori.CopyFrom(node.GetNigoriSpecifics());
  cryptographer->UpdateNigoriFromEncryptedTypes(&nigori);
  node.SetNigoriSpecifics(nigori);
  allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());

  ReEncryptEverything(&trans);
}

Project: Chrome

void SyncManager::RefreshNigori(const base::Closure& done_callback) {
  DCHECK(thread_checker_.CalledOnValidThread());
  data_->UpdateCryptographerAndNigori(base::Bind(
      &SyncManager::DoneRefreshNigori,
      base::Unretained(this),
      done_callback));
}

Project: Chrome

bool SyncManager::SyncInternal::SetDecryptionPassphrase(
    const KeyParams& key_params,
    bool nigori_has_explicit_passphrase,
    bool is_explicit,
    bool user_provided,
    Cryptographer* cryptographer,
    std::string *bootstrap_token) {
  if (!cryptographer->has_pending_keys()) {
    NOTREACHED() << "Attempt to set decryption passphrase failed because there "
                 << "were no pending keys.";
    return false;

  }
  if (!nigori_has_explicit_passphrase) {
    if (!is_explicit) {
      if (!user_provided) {
        if (cryptographer->DecryptPendingKeys(key_params)) {
          DVLOG(1) << "Implicit internal passphrase accepted for decryption.";
          cryptographer->GetBootstrapToken(bootstrap_token);
          return true;
        } else {
          DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding "
                   << "anyways as default passphrase and persisting via "
                   << "bootstrap token.";
          Cryptographer temp_cryptographer;
          temp_cryptographer.AddKey(key_params);
          temp_cryptographer.GetBootstrapToken(bootstrap_token);
          cryptographer->AddKey(key_params);
          return false;
        }
      } else {  // user_provided == true
        if (cryptographer->is_initialized()) {
          Cryptographer temp_cryptographer;
          temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
          if (temp_cryptographer.DecryptPendingKeys(key_params)) {
            sync_pb::EncryptedData encrypted;
            cryptographer->GetKeys(&encrypted);
            if (temp_cryptographer.CanDecrypt(encrypted)) {
              DVLOG(1) << "Implicit user provided passphrase accepted for "
                       << "decryption, overwriting default.";
              cryptographer->DecryptPendingKeys(key_params);
              cryptographer->GetBootstrapToken(bootstrap_token);
              return true;
            } else {
              DVLOG(1) << "Implicit user provided passphrase accepted for "
                       << "decryption, restoring implicit internal passphrase "
                       << "as default.";
              std::string bootstrap_token_from_current_key;
              cryptographer->GetBootstrapToken(
                  &bootstrap_token_from_current_key);
              cryptographer->DecryptPendingKeys(key_params);
              cryptographer->AddKeyFromBootstrapToken(
                  bootstrap_token_from_current_key);
              return true;
            }
          }
        } else if (cryptographer->DecryptPendingKeys(key_params)) {
          DVLOG(1) << "Implicit user provided passphrase accepted, initializing"
                   << " cryptographer.";
          return true;
        } else {
          DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
          return false;
        }
      }  // user_provided
    } else {  // is_explicit == true
      DVLOG(1) << "Explicit passphrase failed to decrypt because nigori had "
               << "implicit passphrase.";
      return false;
    }  // is_explicit
  } else {  // nigori_has_explicit_passphrase == true
    if (!is_explicit) {
      DVLOG(1) << "Implicit passphrase rejected because nigori had explicit "
               << "passphrase.";
      return false;
    } else {  // is_explicit == true
      if (cryptographer->DecryptPendingKeys(key_params)) {
        DVLOG(1) << "Explicit passphrase accepted for decryption.";
        cryptographer->GetBootstrapToken(bootstrap_token);
        return true;
      } else {
        DVLOG(1) << "Explicit passphrase failed to decrypt.";
        return false;
      }
    }  // is_explicit
  }  // nigori_has_explicit_passphrase
  NOTREACHED();
  return false;
}

Project: Chrome

bool SyncManager::SyncInternal::SetEncryptionPassphrase(
    const KeyParams& key_params,
    bool nigori_has_explicit_passphrase,
    bool is_explicit,
    Cryptographer* cryptographer,
    std::string *bootstrap_token) {
  if (cryptographer->has_pending_keys()) {
    LOG(ERROR) << "Attempt to set encryption passphrase failed because there "
               << "were pending keys.";
    return false;
  }
  if (!nigori_has_explicit_passphrase) {
    if (cryptographer->AddKey(key_params)) {
      DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" )
               << " passphrase for encryption.";
      cryptographer->GetBootstrapToken(bootstrap_token);
      return true;
    } else {
      NOTREACHED() << "Failed to add key to cryptographer.";
      return false;
    }
  } else {  // nigori_has_explicit_passphrase == true
    NOTREACHED() << "Attempting to change explicit passphrase when one has "
                 << "already been set.";
    return false;
  }  // nigori_has_explicit_passphrase
  NOTREACHED();
  return false;
}

Project: Chrome

void SyncManager::SetPassphrase(const std::string& passphrase,
                                bool is_explicit,
                                bool user_provided) {
  DCHECK(thread_checker_.CalledOnValidThread());
  data_->SetPassphrase(passphrase, is_explicit, user_provided);
}

Project: Chrome

void SyncManager::SyncInternal::SetPassphrase(
    const std::string& passphrase, bool is_explicit, bool user_provided) {
  DCHECK(user_provided || !is_explicit);
  if (passphrase.empty()) {
    DVLOG(1) << "Rejecting empty passphrase.";
    WriteTransaction trans(FROM_HERE, GetUserShare());
    Cryptographer* cryptographer = trans.GetCryptographer();
    sync_pb::EncryptedData pending_keys;
    if (cryptographer->has_pending_keys())
      pending_keys = cryptographer->GetPendingKeys();
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
        OnPassphraseRequired(sync_api::REASON_SET_PASSPHRASE_FAILED,
                             pending_keys));
    return;
  }

  WriteTransaction trans(FROM_HERE, GetUserShare());
  Cryptographer* cryptographer = trans.GetCryptographer();
  KeyParams key_params = {"localhost", "dummy", passphrase};

  WriteNode node(&trans);
  if (!node.InitByTagLookup(kNigoriTag)) {
    NOTREACHED();
    return;
  }
  bool nigori_has_explicit_passphrase =
      node.GetNigoriSpecifics().using_explicit_passphrase();

  std::string bootstrap_token;
  bool success = false;
  sync_pb::EncryptedData pending_keys;
  if (cryptographer->has_pending_keys()) {
    pending_keys = cryptographer->GetPendingKeys();
    success = SetDecryptionPassphrase(key_params,
                                      nigori_has_explicit_passphrase,
                                      is_explicit,
                                      user_provided,
                                      cryptographer,
                                      &bootstrap_token);
    if (success) {
      RequestNudge(FROM_HERE);
    }
  } else {
    success = SetEncryptionPassphrase(key_params,
                                      nigori_has_explicit_passphrase,
                                      is_explicit,
                                      cryptographer,
                                      &bootstrap_token);
  }

  if (!bootstrap_token.empty()) {
    DVLOG(1) << "Bootstrap token updated.";
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                      OnBootstrapTokenUpdated(bootstrap_token));
  }

  if (!success) {
    DVLOG(1) << "SetPassphrase failure, notifying and returning.";
    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
    OnPassphraseRequired(sync_api::REASON_SET_PASSPHRASE_FAILED,
                         pending_keys));
    return;
  }
  DVLOG(1) << "SetPassphrase success, updating nigori and reencrypting.";
  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                    OnPassphraseAccepted());
  DCHECK(cryptographer->is_ready());

  sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
  if (!cryptographer->GetKeys(specifics.mutable_encrypted())) {
    NOTREACHED();
    return;
  }
  specifics.set_using_explicit_passphrase(is_explicit);
  node.SetNigoriSpecifics(specifics);

  ReEncryptEverything(&trans);
}

Project: Chrome

void SyncManager::SyncInternal::ShutdownOnSyncThread() {
  DCHECK(thread_checker_.CalledOnValidThread());

  weak_ptr_factory_.InvalidateWeakPtrs();
  js_mutation_event_observer_.InvalidateWeakPtrs();

  scheduler_.reset();

  SetJsEventHandler(WeakHandle<JsEventHandler>());
  RemoveObserver(&js_sync_manager_observer_);

  RemoveObserver(&debug_info_event_listener_);

  if (sync_notifier_.get()) {
    sync_notifier_->RemoveObserver(this);
  }
  sync_notifier_.reset();

  if (connection_manager_.get()) {
    connection_manager_->RemoveListener(this);
  }
  connection_manager_.reset();

  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
  observing_ip_address_changes_ = false;

  if (initialized_ && dir_manager()) {
    {
      ReadTransaction trans(FROM_HERE, GetUserShare());
      trans.GetCryptographer()->RemoveObserver(this);
    }
    dir_manager()->FinalSaveChangesForAll();
    dir_manager()->Close(username_for_share());
  }

  share_.dir_manager.reset();

  setup_for_test_mode_ = false;
  change_delegate_ = NULL;
  registrar_ = NULL;

  initialized_ = false;

  change_observer_.Reset();
  weak_handle_this_.Reset();
}

Project: Chrome

bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(share_.name.empty());
  share_.name = credentials.email;

  DVLOG(1) << "Signing in user: " << username_for_share();
  if (!OpenDirectory())
    return false;

  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
  std::string unique_id;
  std::string state;
  if (lookup.good()) {
    unique_id = lookup->cache_guid();
    state = lookup->GetNotificationState();
    DVLOG(1) << "Read notification unique ID: " << unique_id;
    if (VLOG_IS_ON(1)) {
      std::string encoded_state;
      base::Base64Encode(state, &encoded_state);
      DVLOG(1) << "Read notification state: " << encoded_state;
    }
    allstatus_.SetUniqueId(unique_id);
  } else {
    LOG(ERROR) << "Could not read notification unique ID/state";
  }
  sync_notifier_->SetUniqueId(unique_id);
  sync_notifier_->SetState(state);

  UpdateCredentials(credentials);
  UpdateEnabledTypes();
  return true;
}

Project: Chrome

SyncManager::Status::Status()
    : summary(INVALID),
      authenticated(false),
      server_up(false),
      server_reachable(false),
      notifications_enabled(false),
      notifications_received(0),
      unsynced_count(0),
      conflicting_count(0),
      committed_count(0),
      syncing(false),
      initial_sync_ended(false),
      updates_available(0),
      updates_received(0),
      tombstone_updates_received(0),
      num_local_overwrites_total(0),
      num_server_overwrites_total(0),
      nonempty_get_updates(0),
      empty_get_updates(0),
      sync_cycles_with_commits(0),
      sync_cycles_without_commits(0),
      useless_sync_cycles(0),
      useful_sync_cycles(0),
      cryptographer_ready(false),
      crypto_has_pending_keys(false) {
}

Project: Chrome

  explicit SyncInternal(const std::string& name)
      : name_(name),
        weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
        registrar_(NULL),
        change_delegate_(NULL),
        initialized_(false),
        setup_for_test_mode_(false),
        observing_ip_address_changes_(false),
        unrecoverable_error_handler_(NULL),
        created_on_loop_(MessageLoop::current()) {
    for (int i = syncable::FIRST_REAL_MODEL_TYPE;
         i < syncable::MODEL_TYPE_COUNT; ++i) {
      notification_info_map_.insert(
          std::make_pair(syncable::ModelTypeFromInt(i), NotificationInfo()));
    }

    BindJsMessageHandler(
        "getNotificationState",
        &SyncManager::SyncInternal::GetNotificationState);
    BindJsMessageHandler(
        "getNotificationInfo",
        &SyncManager::SyncInternal::GetNotificationInfo);
    BindJsMessageHandler(
        "getRootNodeDetails",
        &SyncManager::SyncInternal::GetRootNodeDetails);
    BindJsMessageHandler(
        "getNodeSummariesById",
        &SyncManager::SyncInternal::GetNodeSummariesById);
    BindJsMessageHandler(
        "getNodeDetailsById",
        &SyncManager::SyncInternal::GetNodeDetailsById);
    BindJsMessageHandler(
        "getChildNodeIds",
        &SyncManager::SyncInternal::GetChildNodeIds);
    BindJsMessageHandler(
        "findNodesContainingString",
        &SyncManager::SyncInternal::FindNodesContainingString);
  }

Project: Chrome

void SyncManager::SyncInternal::UpdateCredentials(
    const SyncCredentials& credentials) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK_EQ(credentials.email, share_.name);
  DCHECK(!credentials.email.empty());
  DCHECK(!credentials.sync_token.empty());

  observing_ip_address_changes_ = true;
  if (connection_manager()->set_auth_token(credentials.sync_token)) {
    sync_notifier_->UpdateCredentials(
        credentials.email, credentials.sync_token);
    if (!setup_for_test_mode_ && initialized_) {
      if (scheduler())
        scheduler()->OnCredentialsUpdated();
    }
  }
}

Project: Chrome

void SyncManager::SyncInternal::UpdateCryptographerAndNigori(
    const base::Callback<void(bool)>& done_callback) {
  DCHECK(initialized_);
  scoped_refptr<browser_sync::GetSessionNameTask> task =
      new browser_sync::GetSessionNameTask(base::Bind(
          &SyncManager::SyncInternal::UpdateCryptographerAndNigoriCallback,
          weak_ptr_factory_.GetWeakPtr(),
          done_callback));
  content::BrowserThread::PostTask(
      content::BrowserThread::FILE,
      FROM_HERE,
      base::Bind(&browser_sync::GetSessionNameTask::GetSessionNameAsync,
                 task.get()));
}

Project: Chrome

void SyncManager::SyncInternal::UpdateCryptographerAndNigoriCallback(
    const base::Callback<void(bool)>& done_callback,
    const std::string& session_name) {
  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
  if (!lookup.good()) {
    NOTREACHED()
        << "UpdateCryptographerAndNigori: lookup not good so bailing out";
    done_callback.Run(false);
    return;
  }
  if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) {
    done_callback.Run(false);  // Should only happen during first time sync.
    return;
  }

  bool success = false;
  {
    WriteTransaction trans(FROM_HERE, GetUserShare());
    Cryptographer* cryptographer = trans.GetCryptographer();
    WriteNode node(&trans);

    if (node.InitByTagLookup(kNigoriTag)) {
      sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics());
      Cryptographer::UpdateResult result = cryptographer->Update(nigori);
      if (result == Cryptographer::NEEDS_PASSPHRASE) {
        sync_pb::EncryptedData pending_keys;
        if (cryptographer->has_pending_keys())
          pending_keys = cryptographer->GetPendingKeys();
        FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
                          OnPassphraseRequired(sync_api::REASON_DECRYPTION,
                                               pending_keys));
      }

      if (!nigori.has_encrypted() && cryptographer->is_ready()) {
        if (!cryptographer->GetKeys(nigori.mutable_encrypted())) {
          NOTREACHED();
        }
      }

      chrome::VersionInfo version_info;
      bool contains_this_device = false;
      for (int i = 0; i < nigori.device_information_size(); ++i) {
        const sync_pb::DeviceInformation& device_information =
            nigori.device_information(i);
        if (device_information.cache_guid() == lookup->cache_guid()) {
          if (device_information.chrome_version() !=
              version_info.CreateVersionString()) {
            sync_pb::DeviceInformation* mutable_device_information =
                nigori.mutable_device_information(i);
            mutable_device_information->set_chrome_version(
                version_info.CreateVersionString());
          }
          contains_this_device = true;
        }
      }

      if (!contains_this_device) {
        sync_pb::DeviceInformation* device_information =
            nigori.add_device_information();
        device_information->set_cache_guid(lookup->cache_guid());
#if defined(OS_CHROMEOS)
        device_information->set_platform("ChromeOS");
#elif defined(OS_LINUX)
        device_information->set_platform("Linux");
#elif defined(OS_MACOSX)
        device_information->set_platform("Mac");
#elif defined(OS_WIN)
        device_information->set_platform("Windows");
#endif
        device_information->set_name(session_name);
        chrome::VersionInfo version_info;
        device_information->set_chrome_version(
            version_info.CreateVersionString());
      }

      cryptographer->UpdateNigoriFromEncryptedTypes(&nigori);
      node.SetNigoriSpecifics(nigori);

      allstatus_.SetCryptographerReady(cryptographer->is_ready());
      allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
      allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());

      success = cryptographer->is_ready();
    } else {
      NOTREACHED();
    }
  }

  done_callback.Run(success);
}

Project: Chrome

void SyncManager::SyncInternal::UpdateEnabledTypes() {
  DCHECK(thread_checker_.CalledOnValidThread());
  ModelSafeRoutingInfo routes;
  registrar_->GetModelSafeRoutingInfo(&routes);
  const ModelTypeSet enabled_types = GetRoutingInfoTypes(routes);
  sync_notifier_->UpdateEnabledTypes(enabled_types);
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableSyncTabsForOtherClients)) {
    MaybeSetSyncTabsInNigoriNode(enabled_types);
  }
}