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 <windows.h>
6#include <atlsecurity.h>  // NOLINT
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/win/registry.h"
10#include "chrome/installer/util/delete_reg_key_work_item.h"
11#include "chrome/installer/util/registry_test_data.h"
12#include "chrome/installer/util/work_item.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15using base::win::RegKey;
16
17class DeleteRegKeyWorkItemTest : public testing::Test {
18 protected:
19  static void TearDownTestCase() {
20    logging::CloseLogFile();
21  }
22
23  virtual void SetUp() {
24    ASSERT_TRUE(test_data_.Initialize(HKEY_CURRENT_USER, L"SOFTWARE\\TmpTmp"));
25  }
26
27  RegistryTestData test_data_;
28};
29
30// Test that deleting a key that doesn't exist succeeds, and that rollback does
31// nothing.
32TEST_F(DeleteRegKeyWorkItemTest, TestNoKey) {
33  const std::wstring key_paths[] = {
34    std::wstring(test_data_.base_path() + L"\\NoKeyHere"),
35    std::wstring(test_data_.base_path() + L"\\NoKeyHere\\OrHere")
36  };
37  RegKey key;
38  for (size_t i = 0; i < arraysize(key_paths); ++i) {
39    const std::wstring& key_path = key_paths[i];
40    scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
41        test_data_.root_key(), key_path, WorkItem::kWow64Default));
42    EXPECT_TRUE(item->Do());
43    EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
44                                      KEY_READ));
45    item->Rollback();
46    item.reset();
47    EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
48                                      KEY_READ));
49  }
50}
51
52// Test that deleting an empty key succeeds, and that rollback brings it back.
53TEST_F(DeleteRegKeyWorkItemTest, TestEmptyKey) {
54  RegKey key;
55  const std::wstring& key_path = test_data_.empty_key_path();
56  scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
57      test_data_.root_key(), key_path, WorkItem::kWow64Default));
58  EXPECT_TRUE(item->Do());
59  EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
60                                    KEY_READ));
61  item->Rollback();
62  item.reset();
63  EXPECT_EQ(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
64                                    KEY_READ));
65}
66
67// Test that deleting a key with subkeys and values succeeds, and that rollback
68// brings them all back.
69TEST_F(DeleteRegKeyWorkItemTest, TestNonEmptyKey) {
70  RegKey key;
71  const std::wstring& key_path = test_data_.non_empty_key_path();
72  scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
73      test_data_.root_key(), key_path, WorkItem::kWow64Default));
74  EXPECT_TRUE(item->Do());
75  EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
76                                    KEY_READ));
77  item->Rollback();
78  item.reset();
79  test_data_.ExpectMatchesNonEmptyKey(test_data_.root_key(), key_path.c_str());
80}
81
82// Test that deleting a key with subkeys we can't delete fails, and that
83// everything is there after rollback.
84// Showing as flaky on windows.
85// http://crbug.com/74654
86TEST_F(DeleteRegKeyWorkItemTest, DISABLED_TestUndeletableKey) {
87  RegKey key;
88  std::wstring key_name(test_data_.base_path() + L"\\UndeletableKey");
89  EXPECT_EQ(ERROR_SUCCESS, key.Create(test_data_.root_key(), key_name.c_str(),
90                                      KEY_WRITE));
91  EXPECT_EQ(ERROR_SUCCESS, key.WriteValue(NULL, key_name.c_str()));
92  DWORD dw_value = 1;
93  RegKey subkey;
94  RegKey subkey2;
95  EXPECT_EQ(ERROR_SUCCESS, subkey.Create(key.Handle(), L"Subkey",
96                                         KEY_WRITE | WRITE_DAC));
97  EXPECT_EQ(ERROR_SUCCESS, subkey.WriteValue(L"SomeValue", 1U));
98  EXPECT_EQ(ERROR_SUCCESS, subkey2.Create(subkey.Handle(), L"Subkey2",
99                                          KEY_WRITE | WRITE_DAC));
100  EXPECT_EQ(ERROR_SUCCESS, subkey2.WriteValue(L"", 2U));
101  CSecurityDesc sec_desc;
102  sec_desc.FromString(L"D:PAI(A;OICI;KR;;;BU)");  // builtin users read
103  EXPECT_EQ(ERROR_SUCCESS,
104            RegSetKeySecurity(subkey.Handle(), DACL_SECURITY_INFORMATION,
105                              const_cast<SECURITY_DESCRIPTOR*>(
106                                  sec_desc.GetPSECURITY_DESCRIPTOR())));
107  sec_desc.FromString(L"D:PAI(A;OICI;KA;;;BU)");  // builtin users all access
108  EXPECT_EQ(ERROR_SUCCESS,
109            RegSetKeySecurity(subkey2.Handle(), DACL_SECURITY_INFORMATION,
110                              const_cast<SECURITY_DESCRIPTOR*>(
111                                  sec_desc.GetPSECURITY_DESCRIPTOR())));
112  subkey2.Close();
113  subkey.Close();
114  key.Close();
115  scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
116      test_data_.root_key(), key_name, WorkItem::kWow64Default));
117  EXPECT_FALSE(item->Do());
118  EXPECT_EQ(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_name.c_str(),
119                                    KEY_QUERY_VALUE));
120  item->Rollback();
121  item.reset();
122  EXPECT_EQ(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_name.c_str(),
123                                    KEY_QUERY_VALUE));
124  std::wstring str_value;
125  EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(NULL, &str_value));
126  EXPECT_EQ(key_name, str_value);
127  EXPECT_EQ(ERROR_SUCCESS, key.OpenKey(L"Subkey", KEY_READ | WRITE_DAC));
128  dw_value = 0;
129  EXPECT_EQ(ERROR_SUCCESS, key.ReadValueDW(L"SomeValue", &dw_value));
130  EXPECT_EQ(1U, dw_value);
131  // Give users all access to the subkey so it can be deleted.
132  EXPECT_EQ(ERROR_SUCCESS,
133      RegSetKeySecurity(key.Handle(), DACL_SECURITY_INFORMATION,
134                        const_cast<SECURITY_DESCRIPTOR*>(
135                            sec_desc.GetPSECURITY_DESCRIPTOR())));
136  EXPECT_EQ(ERROR_SUCCESS, key.OpenKey(L"Subkey2", KEY_QUERY_VALUE));
137  EXPECT_EQ(ERROR_SUCCESS, key.ReadValueDW(L"", &dw_value));
138  EXPECT_EQ(2U, dw_value);
139}
140