1 /*
2 * PROJECT: ReactOS Service Host
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: base/services/svchost/security.cxx
5 * PURPOSE: Initializes the COM Object Security Model and Parameters
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 extern "C"
12 {
13 #include "svchost.h"
14
15 #include <aclapi.h>
16 #include <objidl.h>
17 }
18
19 /* GLOBALS *******************************************************************/
20
21 SID NtSid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } };
22
23 /* FUNCTIONS *****************************************************************/
24
25 DWORD
26 WINAPI
DwInitializeSdFromThreadToken(_Out_ PVOID * ppSecurityDescriptor,_Out_ PACL * ppAcl)27 DwInitializeSdFromThreadToken (
28 _Out_ PVOID *ppSecurityDescriptor,
29 _Out_ PACL *ppAcl
30 )
31 {
32 HANDLE hToken;
33 DWORD dwGroupLength, dwUserLength, dwError, dwAlignLength;
34 PTOKEN_PRIMARY_GROUP pTokenGroup;
35 PTOKEN_USER pTokenUser;
36 EXPLICIT_ACCESS_W pListOfExplicitEntries;
37 PACL pAcl = NULL;
38 PISECURITY_DESCRIPTOR pSd;
39
40 /* Assume failure */
41 *ppSecurityDescriptor = NULL;
42 *ppAcl = NULL;
43
44 /* Open the token of the current thread */
45 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, 0, &hToken) == FALSE)
46 {
47 /* The thread is not impersonating, use the process token */
48 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == FALSE)
49 {
50 /* No token could be queried, fail */
51 return GetLastError();
52 }
53 }
54
55 /* Get the size of the token's user */
56 if ((GetTokenInformation(hToken, TokenUser, NULL, 0, &dwUserLength) != FALSE) ||
57 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
58 {
59 return GetLastError();
60 }
61
62 /* Get the size of the token's primary group */
63 if ((GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwGroupLength) != FALSE) ||
64 (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
65 {
66 return GetLastError();
67 }
68
69 /* Allocate an SD large enough to hold the SIDs for the above */
70 dwAlignLength = ALIGN_UP(dwUserLength, ULONG);
71 pSd = (PISECURITY_DESCRIPTOR)MemAlloc(0,
72 dwAlignLength +
73 dwGroupLength +
74 sizeof(*pSd));
75 if (pSd == NULL) return ERROR_OUTOFMEMORY;
76
77 /* Assume success for now */
78 dwError = ERROR_SUCCESS;
79
80 /* We'll put them right after the SD itself */
81 pTokenUser = (PTOKEN_USER)(pSd + 1);
82 pTokenGroup = (PTOKEN_PRIMARY_GROUP)((ULONG_PTR)pTokenUser + dwAlignLength);
83
84 /* Now initialize it */
85 if (InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION) == FALSE)
86 {
87 dwError = GetLastError();
88 }
89
90 /* And do the actual query for the user */
91 if (GetTokenInformation(hToken,
92 TokenUser,
93 pTokenUser,
94 dwUserLength,
95 &dwUserLength) == FALSE)
96 {
97 dwError = GetLastError();
98 }
99
100 /* And then the actual query for the primary group */
101 if (GetTokenInformation(hToken,
102 TokenPrimaryGroup,
103 pTokenGroup,
104 dwGroupLength,
105 &dwGroupLength) == FALSE)
106 {
107 dwError = GetLastError();
108 }
109
110 /* Set the user as owner */
111 if (SetSecurityDescriptorOwner(pSd, pTokenUser->User.Sid, FALSE) == FALSE)
112 {
113 dwError = GetLastError();
114 }
115
116 /* Set the group as primary */
117 if (SetSecurityDescriptorGroup(pSd, pTokenGroup->PrimaryGroup, FALSE) == FALSE)
118 {
119 dwError = GetLastError();
120 }
121
122 /* Did everything so far work out? */
123 if (dwError == ERROR_SUCCESS)
124 {
125 /* Yes, create an ACL granting the SYSTEM account access */
126 pListOfExplicitEntries.grfAccessMode = SET_ACCESS;
127 pListOfExplicitEntries.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
128 pListOfExplicitEntries.grfAccessPermissions = 1;
129 pListOfExplicitEntries.grfInheritance = 0;
130 pListOfExplicitEntries.Trustee.pMultipleTrustee = 0;
131 pListOfExplicitEntries.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
132 pListOfExplicitEntries.Trustee.TrusteeForm = TRUSTEE_IS_SID;
133 pListOfExplicitEntries.Trustee.ptstrName = (LPWSTR)&NtSid;
134 dwError = SetEntriesInAclW(1, &pListOfExplicitEntries, NULL, &pAcl);
135 if (dwError == ERROR_SUCCESS)
136 {
137 /* Make that ACL the DACL of the SD we just built */
138 if (SetSecurityDescriptorDacl(pSd, 1, pAcl, FALSE) == FALSE)
139 {
140 /* We failed, bail out */
141 LocalFree(pAcl);
142 dwError = GetLastError();
143 }
144 else
145 {
146 /* Now we have the SD and the ACL all ready to go */
147 *ppSecurityDescriptor = pSd;
148 *ppAcl = pAcl;
149 return ERROR_SUCCESS;
150 }
151 }
152 }
153
154 /* Failure path, we'll free the SD since the caller can't use it */
155 MemFree(pSd);
156 return dwError;
157 }
158
159 BOOL
160 WINAPI
InitializeSecurity(_In_ DWORD dwParam,_In_ DWORD dwAuthnLevel,_In_ DWORD dwImpLevel,_In_ DWORD dwCapabilities)161 InitializeSecurity (
162 _In_ DWORD dwParam,
163 _In_ DWORD dwAuthnLevel,
164 _In_ DWORD dwImpLevel,
165 _In_ DWORD dwCapabilities
166 )
167 {
168 HRESULT hr;
169 PACL pAcl;
170 PSECURITY_DESCRIPTOR pSecurityDescriptor;
171 IGlobalOptions *pGlobalOptions;
172 ASSERT(dwParam != 0);
173
174 /* Create a valid SD and ACL based on the current thread's token */
175 if (DwInitializeSdFromThreadToken(&pSecurityDescriptor, &pAcl) == ERROR_SUCCESS)
176 {
177 /* It worked -- initialize COM without DDE support */
178 hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
179 }
180 else
181 {
182 /* Don't keep going if we don't have an SD */
183 hr = E_FAIL;
184 }
185
186 /* Did we make it? */
187 if (SUCCEEDED(hr))
188 {
189 /* Indeed, initialize COM security now */
190 DBG_TRACE("Calling CoInitializeSecurity (dwAuthCapabilities = 0x%08x)\n",
191 dwCapabilities);
192 hr = CoInitializeSecurity(pSecurityDescriptor,
193 -1,
194 NULL,
195 NULL,
196 dwAuthnLevel,
197 dwImpLevel,
198 NULL,
199 dwCapabilities,
200 NULL);
201 if (FAILED(hr)) DBG_ERR("CoInitializeSecurity returned hr=0x%08x\n", hr);
202 }
203
204 /* Free the SD and ACL since we no longer need it */
205 MemFree(pSecurityDescriptor);
206 LocalFree(pAcl);
207
208 /* Did we initialize COM correctly? */
209 if (SUCCEEDED(hr))
210 {
211 /* Get the COM Global Options Interface */
212 hr = CoCreateInstance(CLSID_GlobalOptions,
213 NULL,
214 CLSCTX_INPROC_SERVER,
215 IID_IGlobalOptions,
216 (LPVOID*)&pGlobalOptions);
217 if (SUCCEEDED(hr))
218 {
219 /* Use it to disable COM exception handling */
220 hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING,
221 COMGLB_EXCEPTION_DONOT_HANDLE);
222 pGlobalOptions->Release();
223 ASSERT(SUCCEEDED(hr));
224 }
225 }
226
227 /* Return whether all COM calls were successful or not */
228 return SUCCEEDED(hr);
229 }
230