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 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 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