1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/mscom/MainThreadRuntime.h"
8
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/Assertions.h"
11 #include "mozilla/RefPtr.h"
12 #include "mozilla/UniquePtr.h"
13 #include "mozilla/WindowsVersion.h"
14 #include "nsDebug.h"
15 #include "nsWindowsHelpers.h"
16
17 #include <accctrl.h>
18 #include <aclapi.h>
19 #include <objbase.h>
20 #include <objidl.h>
21
22 namespace {
23
24 struct LocalFreeDeleter
25 {
operator ()__anone3311c310111::LocalFreeDeleter26 void operator()(void* aPtr)
27 {
28 ::LocalFree(aPtr);
29 }
30 };
31
32 } // anonymous namespace
33
34 namespace mozilla {
35 namespace mscom {
36
MainThreadRuntime()37 MainThreadRuntime::MainThreadRuntime()
38 : mInitResult(E_UNEXPECTED)
39 {
40 // We must be the outermost COM initialization on this thread. The COM runtime
41 // cannot be configured once we start manipulating objects
42 MOZ_ASSERT(mStaRegion.IsValidOutermost());
43 if (NS_WARN_IF(!mStaRegion.IsValidOutermost())) {
44 return;
45 }
46
47 // Windows XP doesn't support setting of the COM exception policy, so we'll
48 // just stop here in that case.
49 if (!IsVistaOrLater()) {
50 mInitResult = S_OK;
51 return;
52 }
53
54 // We are required to initialize security in order to configure global options.
55 mInitResult = InitializeSecurity();
56 MOZ_ASSERT(SUCCEEDED(mInitResult));
57 if (FAILED(mInitResult)) {
58 return;
59 }
60
61 RefPtr<IGlobalOptions> globalOpts;
62 mInitResult = ::CoCreateInstance(CLSID_GlobalOptions, nullptr,
63 CLSCTX_INPROC_SERVER, IID_IGlobalOptions,
64 (void**)getter_AddRefs(globalOpts));
65 MOZ_ASSERT(SUCCEEDED(mInitResult));
66 if (FAILED(mInitResult)) {
67 return;
68 }
69
70 // Windows 7 has a policy that is even more strict. We should use that one
71 // whenever possible.
72 ULONG_PTR exceptionSetting = IsWin7OrLater() ?
73 COMGLB_EXCEPTION_DONOT_HANDLE_ANY :
74 COMGLB_EXCEPTION_DONOT_HANDLE;
75 mInitResult = globalOpts->Set(COMGLB_EXCEPTION_HANDLING, exceptionSetting);
76 MOZ_ASSERT(SUCCEEDED(mInitResult));
77 }
78
79 HRESULT
InitializeSecurity()80 MainThreadRuntime::InitializeSecurity()
81 {
82 HANDLE rawToken = nullptr;
83 BOOL ok = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken);
84 if (!ok) {
85 return HRESULT_FROM_WIN32(::GetLastError());
86 }
87 nsAutoHandle token(rawToken);
88
89 DWORD len = 0;
90 ok = ::GetTokenInformation(token, TokenUser, nullptr, len, &len);
91 DWORD win32Error = ::GetLastError();
92 if (!ok && win32Error != ERROR_INSUFFICIENT_BUFFER) {
93 return HRESULT_FROM_WIN32(win32Error);
94 }
95
96 auto tokenUserBuf = MakeUnique<BYTE[]>(len);
97 TOKEN_USER& tokenUser = *reinterpret_cast<TOKEN_USER*>(tokenUserBuf.get());
98 ok = ::GetTokenInformation(token, TokenUser, tokenUserBuf.get(), len, &len);
99 if (!ok) {
100 return HRESULT_FROM_WIN32(::GetLastError());
101 }
102
103 len = 0;
104 ok = ::GetTokenInformation(token, TokenPrimaryGroup, nullptr, len, &len);
105 win32Error = ::GetLastError();
106 if (!ok && win32Error != ERROR_INSUFFICIENT_BUFFER) {
107 return HRESULT_FROM_WIN32(win32Error);
108 }
109
110 auto tokenPrimaryGroupBuf = MakeUnique<BYTE[]>(len);
111 TOKEN_PRIMARY_GROUP& tokenPrimaryGroup =
112 *reinterpret_cast<TOKEN_PRIMARY_GROUP*>(tokenPrimaryGroupBuf.get());
113 ok = ::GetTokenInformation(token, TokenPrimaryGroup, tokenPrimaryGroupBuf.get(),
114 len, &len);
115 if (!ok) {
116 return HRESULT_FROM_WIN32(::GetLastError());
117 }
118
119 SECURITY_DESCRIPTOR sd;
120 if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
121 return HRESULT_FROM_WIN32(::GetLastError());
122 }
123
124 BYTE systemSid[SECURITY_MAX_SID_SIZE];
125 DWORD systemSidSize = sizeof(systemSid);
126 if (!::CreateWellKnownSid(WinLocalSystemSid, nullptr, systemSid,
127 &systemSidSize)) {
128 return HRESULT_FROM_WIN32(::GetLastError());
129 }
130
131 BYTE adminSid[SECURITY_MAX_SID_SIZE];
132 DWORD adminSidSize = sizeof(adminSid);
133 if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, nullptr, adminSid,
134 &adminSidSize)) {
135 return HRESULT_FROM_WIN32(::GetLastError());
136 }
137
138 // Grant access to SYSTEM, Administrators, and the user.
139 EXPLICIT_ACCESS entries[] = {
140 {COM_RIGHTS_EXECUTE, GRANT_ACCESS, NO_INHERITANCE,
141 {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_USER,
142 reinterpret_cast<LPWSTR>(systemSid)}},
143 {COM_RIGHTS_EXECUTE, GRANT_ACCESS, NO_INHERITANCE,
144 {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_WELL_KNOWN_GROUP,
145 reinterpret_cast<LPWSTR>(adminSid)}},
146 {COM_RIGHTS_EXECUTE, GRANT_ACCESS, NO_INHERITANCE,
147 {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_USER,
148 reinterpret_cast<LPWSTR>(tokenUser.User.Sid)}}
149 };
150
151 PACL rawDacl = nullptr;
152 win32Error = ::SetEntriesInAcl(ArrayLength(entries), entries, nullptr,
153 &rawDacl);
154 if (win32Error != ERROR_SUCCESS) {
155 return HRESULT_FROM_WIN32(win32Error);
156 }
157
158 UniquePtr<ACL, LocalFreeDeleter> dacl(rawDacl);
159
160 if (!::SetSecurityDescriptorDacl(&sd, TRUE, dacl.get(), FALSE)) {
161 return HRESULT_FROM_WIN32(::GetLastError());
162 }
163
164 if (!::SetSecurityDescriptorOwner(&sd, tokenUser.User.Sid, FALSE)) {
165 return HRESULT_FROM_WIN32(::GetLastError());
166 }
167
168 if (!::SetSecurityDescriptorGroup(&sd, tokenPrimaryGroup.PrimaryGroup, FALSE)) {
169 return HRESULT_FROM_WIN32(::GetLastError());
170 }
171
172 return ::CoInitializeSecurity(&sd, -1, nullptr, nullptr,
173 RPC_C_AUTHN_LEVEL_DEFAULT,
174 RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE,
175 nullptr);
176 }
177
178 } // namespace mscom
179 } // namespace mozilla
180
181