1// Copyright (c) 2012 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 "sandbox/win/src/app_container.h"
6
7#include <Sddl.h>
8#include <vector>
9
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/win/startup_information.h"
13#include "sandbox/win/src/internal_types.h"
14
15namespace {
16
17// Converts the passed in sid string to a PSID that must be relased with
18// LocalFree.
19PSID ConvertSid(const base::string16& sid) {
20  PSID local_sid;
21  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
22    return NULL;
23  return local_sid;
24}
25
26template <typename T>
27T BindFunction(const char* name) {
28  HMODULE module = GetModuleHandle(sandbox::kKerneldllName);
29  void* function = GetProcAddress(module, name);
30  if (!function) {
31    module = GetModuleHandle(sandbox::kKernelBasedllName);
32    function = GetProcAddress(module, name);
33  }
34  return reinterpret_cast<T>(function);
35}
36
37}  // namespace
38
39namespace sandbox {
40
41AppContainerAttributes::AppContainerAttributes() {
42  memset(&capabilities_, 0, sizeof(capabilities_));
43}
44
45AppContainerAttributes::~AppContainerAttributes() {
46  for (size_t i = 0; i < attributes_.size(); i++)
47    LocalFree(attributes_[i].Sid);
48  LocalFree(capabilities_.AppContainerSid);
49}
50
51ResultCode AppContainerAttributes::SetAppContainer(
52    const base::string16& app_container_sid,
53    const std::vector<base::string16>& capabilities) {
54  DCHECK(!capabilities_.AppContainerSid);
55  DCHECK(attributes_.empty());
56  capabilities_.AppContainerSid = ConvertSid(app_container_sid);
57  if (!capabilities_.AppContainerSid)
58    return SBOX_ERROR_INVALID_APP_CONTAINER;
59
60  for (size_t i = 0; i < capabilities.size(); i++)  {
61    SID_AND_ATTRIBUTES sid_and_attributes;
62    sid_and_attributes.Sid = ConvertSid(capabilities[i]);
63    if (!sid_and_attributes.Sid)
64      return SBOX_ERROR_INVALID_CAPABILITY;
65
66    sid_and_attributes.Attributes = SE_GROUP_ENABLED;
67    attributes_.push_back(sid_and_attributes);
68  }
69
70  if (capabilities.size()) {
71    capabilities_.CapabilityCount = static_cast<DWORD>(capabilities.size());
72    capabilities_.Capabilities = &attributes_[0];
73  }
74  return SBOX_ALL_OK;
75}
76
77ResultCode AppContainerAttributes::ShareForStartup(
78      base::win::StartupInformation* startup_information) const {
79  // The only thing we support so far is an AppContainer.
80  if (!capabilities_.AppContainerSid)
81    return SBOX_ERROR_INVALID_APP_CONTAINER;
82
83  if (!startup_information->UpdateProcThreadAttribute(
84           PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
85           const_cast<SECURITY_CAPABILITIES*>(&capabilities_),
86           sizeof(capabilities_)))  {
87    DPLOG(ERROR) << "Failed UpdateProcThreadAttribute";
88    return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
89  }
90  return SBOX_ALL_OK;
91}
92
93bool AppContainerAttributes::HasAppContainer() const {
94  return (capabilities_.AppContainerSid != NULL);
95}
96
97ResultCode CreateAppContainer(const base::string16& sid,
98                              const base::string16& name) {
99  PSID local_sid;
100  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
101    return SBOX_ERROR_INVALID_APP_CONTAINER;
102
103  typedef HRESULT (WINAPI* AppContainerRegisterSidPtr)(PSID sid,
104                                                       LPCWSTR moniker,
105                                                       LPCWSTR display_name);
106  static AppContainerRegisterSidPtr AppContainerRegisterSid = NULL;
107
108  if (!AppContainerRegisterSid) {
109    AppContainerRegisterSid =
110        BindFunction<AppContainerRegisterSidPtr>("AppContainerRegisterSid");
111  }
112
113  ResultCode operation_result = SBOX_ERROR_GENERIC;
114  if (AppContainerRegisterSid) {
115    HRESULT rv = AppContainerRegisterSid(local_sid, name.c_str(), name.c_str());
116    if (SUCCEEDED(rv))
117      operation_result = SBOX_ALL_OK;
118    else
119      DLOG(ERROR) << "AppContainerRegisterSid error:" << std::hex << rv;
120  }
121  LocalFree(local_sid);
122  return operation_result;
123}
124
125ResultCode DeleteAppContainer(const base::string16& sid) {
126  PSID local_sid;
127  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
128    return SBOX_ERROR_INVALID_APP_CONTAINER;
129
130  typedef HRESULT (WINAPI* AppContainerUnregisterSidPtr)(PSID sid);
131  static AppContainerUnregisterSidPtr AppContainerUnregisterSid = NULL;
132
133  if (!AppContainerUnregisterSid) {
134    AppContainerUnregisterSid =
135        BindFunction<AppContainerUnregisterSidPtr>("AppContainerUnregisterSid");
136  }
137
138  ResultCode operation_result = SBOX_ERROR_GENERIC;
139  if (AppContainerUnregisterSid) {
140    HRESULT rv = AppContainerUnregisterSid(local_sid);
141    if (SUCCEEDED(rv))
142      operation_result = SBOX_ALL_OK;
143    else
144      DLOG(ERROR) << "AppContainerUnregisterSid error:" << std::hex << rv;
145  }
146  LocalFree(local_sid);
147  return operation_result;
148}
149
150base::string16 LookupAppContainer(const base::string16& sid) {
151  PSID local_sid;
152  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
153    return base::string16();
154
155  typedef HRESULT (WINAPI* AppContainerLookupMonikerPtr)(PSID sid,
156                                                         LPWSTR* moniker);
157  typedef BOOLEAN (WINAPI* AppContainerFreeMemoryPtr)(void* ptr);
158
159  static AppContainerLookupMonikerPtr AppContainerLookupMoniker = NULL;
160  static AppContainerFreeMemoryPtr AppContainerFreeMemory = NULL;
161
162  if (!AppContainerLookupMoniker || !AppContainerFreeMemory) {
163    AppContainerLookupMoniker =
164        BindFunction<AppContainerLookupMonikerPtr>("AppContainerLookupMoniker");
165    AppContainerFreeMemory =
166        BindFunction<AppContainerFreeMemoryPtr>("AppContainerFreeMemory");
167  }
168
169  if (!AppContainerLookupMoniker || !AppContainerFreeMemory)
170    return base::string16();
171
172  wchar_t* buffer = NULL;
173  HRESULT rv = AppContainerLookupMoniker(local_sid, &buffer);
174  if (FAILED(rv))
175    return base::string16();
176
177  base::string16 name(buffer);
178  if (!AppContainerFreeMemory(buffer))
179    NOTREACHED();
180  return name;
181}
182
183}  // namespace sandbox
184