Commit message: None
CVE: CVE-2011-2358
CWE: CWE-20
Vulnerability description: Google Chrome before 13.0.782.107 does not ensure that extension installations are confirmed by a browser dialog, which makes it easier for remote attackers to modify the product's functionality via a Trojan horse extension.

Project: Chrome

DictionaryValue* CreateLoginResult(Profile* profile) {
  DictionaryValue* dictionary = new DictionaryValue();
  std::string username = GetBrowserSignin(profile)->GetSignedInUsername();
  dictionary->SetString(kLoginKey, username);
  if (!username.empty()) {
    CommandLine* cmdline = CommandLine::ForCurrentProcess();
    TokenService* token_service = profile->GetTokenService();
    if (cmdline->HasSwitch(switches::kAppsGalleryReturnTokens) &&
        token_service->HasTokenForService(GaiaConstants::kGaiaService)) {
      dictionary->SetString(kTokenKey,
                            token_service->GetTokenForService(
                                GaiaConstants::kGaiaService));
    }
  }
  return dictionary;
}

Project: Chrome

BrowserSignin* GetBrowserSignin(Profile* profile) {
  if (test_signin)
    return test_signin;
  else
    return profile->GetBrowserSignin();
}

Project: Chrome

Profile* GetDefaultProfile(Profile* profile) {
  if (!profile->IsOffTheRecord())
    return profile;
  else
    return g_browser_process->profile_manager()->GetDefaultProfile();
}

Project: Chrome

string16 PromptBrowserLoginFunction::GetLoginMessage() {
  using l10n_util::GetStringUTF16;
  using l10n_util::GetStringFUTF16;

  string16 message;
  message = ASCIIToUTF16("<p>")
      + GetStringUTF16(IDS_WEB_STORE_LOGIN_INTRODUCTION_1)
      + ASCIIToUTF16("</p>");
  message = message + ASCIIToUTF16("<p>")
      + GetStringFUTF16(IDS_WEB_STORE_LOGIN_INTRODUCTION_2,
                        GetStringUTF16(IDS_PRODUCT_NAME))
      + ASCIIToUTF16("</p>");
  return message;
}

Project: Chrome

 ProfileSyncService* GetSyncService(Profile* profile) {
   if (test_sync_service)
    return test_sync_service;
  else
    return profile->GetProfileSyncService();
}

Project: Chrome

void BeginInstallWithManifestFunction::InstallUIAbort() {
  error_ = std::string(kUserCancelledError);
  SetResult(USER_CANCELLED);
  SendResponse(false);

  Release();
}

Project: Chrome

void BeginInstallWithManifestFunction::InstallUIProceed() {
  CrxInstaller::SetWhitelistedManifest(id_, parsed_manifest_.release());
  SetResult(ERROR_NONE);
  SendResponse(true);

  Release();
}

Project: Chrome

bool IsWebStoreURL(Profile* profile, const GURL& url) {
  ExtensionService* service = profile->GetExtensionService();
  const Extension* store = service->GetWebStoreApp();
  if (!store) {
    NOTREACHED();
    return false;
  }
  return (service->GetExtensionByWebExtent(url) == store);
}

Project: Chrome

  virtual void OnDecodeImageFailed() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    icon_decode_complete_ = true;
    error_ = std::string(kImageDecodeError);
    parse_error_ = BeginInstallWithManifestFunction::ICON_ERROR;
    ReportResultsIfComplete();
  }

Project: Chrome

  virtual void OnDecodeImageSucceeded(const SkBitmap& decoded_image) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    icon_ = decoded_image;
    icon_decode_complete_ = true;
    ReportResultsIfComplete();
  }

Project: Chrome

  virtual void OnJSONParseFailed(const std::string& error_message) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    manifest_parse_complete_ = true;
    error_ = error_message;
    parse_error_ = BeginInstallWithManifestFunction::MANIFEST_ERROR;
    ReportResultsIfComplete();
  }

Project: Chrome

  virtual void OnJSONParseSucceeded(const ListValue& wrapper) {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    manifest_parse_complete_ = true;
    Value* value = NULL;
    CHECK(wrapper.Get(0, &value));
    if (value->IsType(Value::TYPE_DICTIONARY)) {
      parsed_manifest_.reset(
          static_cast<DictionaryValue*>(value)->DeepCopy());
    } else {
      parse_error_ = BeginInstallWithManifestFunction::MANIFEST_ERROR;
    }
    ReportResultsIfComplete();
  }

Project: Chrome

void PromptBrowserLoginFunction::OnLoginFailure(
    const GoogleServiceAuthError& error) {
  SendResponse(false);
  Release();
}

Project: Chrome

void PromptBrowserLoginFunction::OnLoginSuccess() {
  ProfileSyncService* service = GetSyncService(GetDefaultProfile(profile_));
  syncable::ModelTypeSet types;
  if (service->HasSyncSetupCompleted())
    service->GetPreferredDataTypes(&types);
  types.insert(syncable::APPS);
  service->ChangePreferredDataTypes(types);
  service->SetSyncSetupCompleted();

  waiting_for_token_ = true;
}

Project: Chrome

void BeginInstallWithManifestFunction::OnParseFailure(
    ResultCode result_code, const std::string& error_message) {
  SetResult(result_code);
  error_ = error_message;
  SendResponse(false);

  Release();
}

Project: Chrome

PromptBrowserLoginFunction::PromptBrowserLoginFunction()
    : waiting_for_token_(false) {}

Project: Chrome

  void ReportResultsIfComplete() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

    if (!icon_decode_complete_ || !manifest_parse_complete_)
      return;

    utility_host_->EndBatchMode();
    utility_host_ = NULL;

    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        NewRunnableMethod(this,
                          &SafeBeginInstallHelper::ReportResultFromUIThread));
  }

Project: Chrome

bool BeginInstallFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url()))
    return false;

  std::string id;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id));
  if (!Extension::IdIsValid(id)) {
    error_ = kInvalidIdError;
    return false;
  }

  if (!user_gesture() && !ignore_user_gesture_for_tests) {
    error_ = kUserGestureRequiredError;
    return false;
  }

  CrxInstaller::SetWhitelistedInstallId(id);
  return true;
}

Project: Chrome

bool BeginInstallWithManifestFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url())) {
    SetResult(PERMISSION_DENIED);
    return false;
  }

  if (!user_gesture() && !ignore_user_gesture_for_tests) {
    SetResult(NO_GESTURE);
    error_ = kUserGestureRequiredError;
    return false;
  }

  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_));
  if (!Extension::IdIsValid(id_)) {
    SetResult(INVALID_ID);
    error_ = kInvalidIdError;
    return false;
  }

  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &icon_data_));
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &manifest_));

  scoped_refptr<SafeBeginInstallHelper> helper =
      new SafeBeginInstallHelper(this, icon_data_, manifest_);
  helper->Start();

  AddRef();

  return true;
}

Project: Chrome

bool CompleteInstallFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url()))
    return false;

  std::string id;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id));
  if (!Extension::IdIsValid(id)) {
    error_ = kInvalidIdError;
    return false;
  }

  if (!CrxInstaller::IsIdWhitelisted(id) &&
      !CrxInstaller::GetWhitelistedManifest(id)) {
    error_ = ExtensionErrorUtils::FormatErrorMessage(
        kNoPreviousBeginInstallError, id);
    return false;
  }

  std::vector<std::string> params;
  params.push_back("id=" + id);
  params.push_back("lang=" + g_browser_process->GetApplicationLocale());
  params.push_back("uc");
  std::string url_string = Extension::GalleryUpdateUrl(true).spec();

  GURL url(url_string + "?response=redirect&x=" +
      EscapeQueryParamValue(JoinString(params, '&'), true));
  DCHECK(url.is_valid());

  NavigationController& controller =
      dispatcher()->delegate()->associated_tab_contents()->controller();
  controller.LoadURL(url, source_url(), PageTransition::LINK);

  return true;
}

Project: Chrome

bool GetBrowserLoginFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url()))
    return false;
  result_.reset(CreateLoginResult(GetDefaultProfile(profile_)));
  return true;
}

Project: Chrome

bool GetStoreLoginFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url()))
    return false;
  ExtensionService* service = profile_->GetExtensionService();
  ExtensionPrefs* prefs = service->extension_prefs();
  std::string login;
  if (prefs->GetWebStoreLogin(&login)) {
    result_.reset(Value::CreateStringValue(login));
  } else {
    result_.reset(Value::CreateStringValue(std::string()));
  }
  return true;
}

Project: Chrome

bool SetStoreLoginFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url()))
    return false;
  std::string login;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &login));
  ExtensionService* service = profile_->GetExtensionService();
  ExtensionPrefs* prefs = service->extension_prefs();
  prefs->SetWebStoreLogin(login);
  return true;
}

Project: Chrome

bool PromptBrowserLoginFunction::RunImpl() {
  if (!IsWebStoreURL(profile_, source_url()))
    return false;

  std::string preferred_email;
  if (args_->GetSize() > 0) {
    EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &preferred_email));
  }

  Profile* profile = GetDefaultProfile(profile_);

  TabContents* tab = dispatcher()->delegate()->associated_tab_contents();
  if (!tab)
    return false;

  AddRef();

  TokenService* token_service = profile->GetTokenService();
  registrar_.Add(this,
                 NotificationType::TOKEN_AVAILABLE,
                 Source<TokenService>(token_service));
  registrar_.Add(this,
                 NotificationType::TOKEN_REQUEST_FAILED,
                 Source<TokenService>(token_service));

  GetBrowserSignin(profile)->RequestSignin(tab,
                                           ASCIIToUTF16(preferred_email),
                                           GetLoginMessage(),
                                           this);

  return true;
}

Project: Chrome

  SafeBeginInstallHelper(BeginInstallWithManifestFunction* client,
                         const std::string& icon_data,
                         const std::string& manifest)
      : client_(client),
        icon_data_(icon_data),
        manifest_(manifest),
        utility_host_(NULL),
        icon_decode_complete_(false),
        manifest_parse_complete_(false),
        parse_error_(BeginInstallWithManifestFunction::UNKNOWN_ERROR) {}

Project: Chrome

void BeginInstallFunction::SetIgnoreUserGestureForTests(bool ignore) {
  ignore_user_gesture_for_tests = ignore;
}

Project: Chrome

void BeginInstallWithManifestFunction::SetResult(ResultCode code) {
  switch (code) {
    case ERROR_NONE:
      result_.reset(Value::CreateStringValue(""));
      break;
    case UNKNOWN_ERROR:
      result_.reset(Value::CreateStringValue("unknown_error"));
      break;
    case USER_CANCELLED:
      result_.reset(Value::CreateStringValue("user_cancelled"));
      break;
    case MANIFEST_ERROR:
      result_.reset(Value::CreateStringValue("manifest_error"));
      break;
    case ICON_ERROR:
      result_.reset(Value::CreateStringValue("icon_error"));
      break;
    case INVALID_ID:
      result_.reset(Value::CreateStringValue("invalid_id"));
      break;
    case PERMISSION_DENIED:
      result_.reset(Value::CreateStringValue("permission_denied"));
      break;
    case NO_GESTURE:
      result_.reset(Value::CreateStringValue("no_gesture"));
      break;
    default:
      CHECK(false);
   }
 }

Project: Chrome

void WebstorePrivateApi::SetTestingBrowserSignin(BrowserSignin* signin) {
  test_signin = signin;
}

Project: Chrome

  void StartWorkOnIOThread() {
    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    utility_host_ = new UtilityProcessHost(this, BrowserThread::IO);
    utility_host_->StartBatchMode();
    if (icon_data_.empty())
      icon_decode_complete_ = true;
    else
      utility_host_->StartImageDecodingBase64(icon_data_);
    utility_host_->StartJSONParsing(manifest_);
  }

Project: Chrome

BeginInstallWithManifestFunction::~BeginInstallWithManifestFunction() {}

Project: Chrome

PromptBrowserLoginFunction::~PromptBrowserLoginFunction() {
}