WinMain.cpp (9416B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #define NOMINMAX 4 #pragma warning( push ) 5 #pragma warning ( disable : 6001 6388 6553) 6 #include <wil/resource.h> 7 #include <wil/com.h> 8 #pragma warning( pop ) 9 #include <objidl.h> 10 #include <shellapi.h> 11 #include <sddl.h> 12 #include <WindowsPackageManager.h> 13 #include "WinGetServer.h" 14 #include "Utils.h" 15 16 #include <memory> 17 #include <string> 18 #include <string_view> 19 #include <vector> 20 21 // Holds the wwinmain open until COM tells us there are no more server connections 22 wil::unique_event _comServerExitEvent; 23 24 // Routine Description: 25 // - Called back when COM says there is nothing left for our server to do and we can tear down. 26 static void _releaseNotifier() noexcept 27 { 28 _comServerExitEvent.SetEvent(); 29 } 30 31 HRESULT WindowsPackageManagerServerInitializeRPCServer() 32 { 33 std::string userSID = GetUserSID(); 34 std::string endpoint = "\\pipe\\WinGetServerManualActivation_" + userSID; 35 RPC_STATUS status = RpcServerUseProtseqEpA(GetUCharString("ncacn_np"), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, GetUCharString(endpoint), nullptr); 36 RETURN_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK); 37 38 // The goal of this security descriptor is to restrict RPC server access only to the user in admin mode. 39 // (ML;;NW;;;HI) specifies a high mandatory integrity level (requires admin). 40 // (A;;GA;;;UserSID) specifies access only for the user with the user SID (i.e. self). 41 wil::unique_hlocal_security_descriptor securityDescriptor; 42 std::string securityDescriptorString = "S:(ML;;NW;;;HI)D:(A;;GA;;;" + userSID + ")"; 43 RETURN_LAST_ERROR_IF(!ConvertStringSecurityDescriptorToSecurityDescriptorA(securityDescriptorString.c_str(), SDDL_REVISION_1, &securityDescriptor, nullptr)); 44 45 status = RpcServerRegisterIf3(WinGetServerManualActivation_v1_0_s_ifspec, nullptr, nullptr, RPC_IF_ALLOW_LOCAL_ONLY | RPC_IF_AUTOLISTEN, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 0, nullptr, securityDescriptor.get()); 46 RETURN_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK); 47 48 return S_OK; 49 } 50 51 _Must_inspect_result_ 52 _Ret_maybenull_ _Post_writable_byte_size_(size) 53 void* __RPC_USER MIDL_user_allocate(_In_ size_t size) 54 { 55 return malloc(size); 56 } 57 58 void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr) 59 { 60 if (ptr) 61 { 62 free(ptr); 63 } 64 } 65 66 extern "C" HRESULT CreateInstance( 67 /* [in] */ GUID clsid, 68 /* [in] */ GUID iid, 69 /* [in] */ UINT32, 70 /* [ref][out] */ UINT32 * pcbBuffer, 71 /* [size_is][size_is][ref][out] */ BYTE * *ppBuffer) 72 { 73 RETURN_HR_IF_NULL(E_POINTER, pcbBuffer); 74 RETURN_HR_IF_NULL(E_POINTER, ppBuffer); 75 76 wil::com_ptr<IStream> stream; 77 RETURN_IF_FAILED(CreateStreamOnHGlobal(nullptr, TRUE, &stream)); 78 79 wil::com_ptr<IUnknown> instance; 80 RETURN_IF_FAILED(WindowsPackageManagerServerCreateInstance(clsid, iid, reinterpret_cast<void**>(&instance))); 81 82 RETURN_IF_FAILED(CoMarshalInterface(stream.get(), iid, instance.get(), MSHCTX_LOCAL, nullptr, MSHLFLAGS_NORMAL)); 83 84 ULARGE_INTEGER streamSize{}; 85 RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_CUR, &streamSize)); 86 RETURN_HR_IF(E_NOT_SUFFICIENT_BUFFER, streamSize.QuadPart > std::numeric_limits<UINT32>::max()); 87 88 UINT32 bufferSize = static_cast<UINT32>(streamSize.QuadPart); 89 90 struct DeleteWithMidlFree { void operator()(void* m) { MIDL_user_free(m); } }; 91 std::unique_ptr<BYTE, DeleteWithMidlFree> buffer{ reinterpret_cast<BYTE*>(MIDL_user_allocate(bufferSize)) }; 92 93 RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_SET, nullptr)); 94 ULONG bytesRead = 0; 95 RETURN_IF_FAILED(stream->Read(buffer.get(), bufferSize, &bytesRead)); 96 RETURN_HR_IF(E_UNEXPECTED, bytesRead != bufferSize); 97 98 *pcbBuffer = bufferSize; 99 *ppBuffer = buffer.release(); 100 101 return S_OK; 102 } 103 104 HRESULT InitializeComSecurity() 105 { 106 wil::unique_hlocal_security_descriptor securityDescriptor; 107 // Allow Self, System, Built-in Admin and App Container access. 3 is COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL 108 std::string securityDescriptorString = "O:SYG:SYD:(A;;3;;;PS)(A;;3;;;SY)(A;;3;;;BA)(A;;3;;;AC)"; 109 RETURN_LAST_ERROR_IF(!ConvertStringSecurityDescriptorToSecurityDescriptorA(securityDescriptorString.c_str(), SDDL_REVISION_1, &securityDescriptor, nullptr)); 110 111 // Make absolute security descriptor as CoInitializeSecurity required 112 SECURITY_DESCRIPTOR absoluteSecurityDescriptor; 113 DWORD securityDescriptorSize = sizeof(SECURITY_DESCRIPTOR); 114 115 DWORD daclSize = 0; 116 DWORD saclSize = 0; 117 DWORD ownerSize = 0; 118 DWORD groupSize = 0; 119 120 // Get required size 121 BOOL result = MakeAbsoluteSD(securityDescriptor.get(), &absoluteSecurityDescriptor, &securityDescriptorSize, nullptr, &daclSize, nullptr, &saclSize, nullptr, &ownerSize, nullptr, &groupSize); 122 RETURN_HR_IF_MSG(E_FAIL, result || GetLastError() != ERROR_INSUFFICIENT_BUFFER, "MakeAbsoluteSD failed to return buffer sizes"); 123 124 std::vector<BYTE> dacl(daclSize); 125 std::vector<BYTE> sacl(saclSize); 126 std::vector<BYTE> owner(ownerSize); 127 std::vector<BYTE> group(groupSize); 128 129 RETURN_LAST_ERROR_IF(!MakeAbsoluteSD(securityDescriptor.get(), &absoluteSecurityDescriptor, &securityDescriptorSize, (PACL)dacl.data(), &daclSize, (PACL)sacl.data(), &saclSize, (PACL)owner.data(), &ownerSize, (PACL)group.data(), &groupSize)); 130 131 // Initialize com security 132 RETURN_IF_FAILED(CoInitializeSecurity( 133 &absoluteSecurityDescriptor, // Security descriptor 134 -1, // Authentication services count. -1 is let com choose. 135 nullptr, // Authentication services array 136 nullptr, // Reserved 137 RPC_C_AUTHN_LEVEL_DEFAULT, // Authentication level. 138 RPC_C_IMP_LEVEL_IDENTIFY, // Impersonation level. Identify client. 139 nullptr, // Authentication list 140 EOAC_NONE, // Additional capabilities 141 nullptr // Reserved 142 )); 143 144 return S_OK; 145 } 146 147 int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLine, _In_ int) 148 { 149 wil::SetResultLoggingCallback(&WindowsPackageManagerServerWilResultLoggingCallback); 150 151 RETURN_IF_FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)); 152 153 // Enable fast rundown of objects so that the server exits faster when clients go away. 154 { 155 wil::com_ptr<IGlobalOptions> globalOptions; 156 RETURN_IF_FAILED(CoCreateInstance(CLSID_GlobalOptions, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&globalOptions))); 157 RETURN_IF_FAILED(globalOptions->Set(COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN)); 158 RETURN_IF_FAILED(globalOptions->Set(COMGLB_UNMARSHALING_POLICY, COMGLB_UNMARSHALING_POLICY_STRONG)); 159 RETURN_IF_FAILED(globalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE_ANY)); 160 } 161 162 // Command line parsing 163 int argc = 0; 164 LPWSTR* argv = CommandLineToArgvW(cmdLine, &argc); 165 RETURN_LAST_ERROR_IF(!argv); 166 167 bool manualActivation = false; 168 169 // If command line gets more complicated, consider more complex parsing 170 if (argc == 1 && std::wstring_view{ L"--manualActivation" } == argv[0]) 171 { 172 manualActivation = true; 173 } 174 175 // For packaged com activation, initialize com security. 176 // For manual activation, leave as default. We'll not register objects for manual activation. 177 if (!manualActivation) 178 { 179 // This must be called after IGlobalOptions (fast rundown setting cannot be changed after CoInitializeSecurity) 180 // This must be called before WindowsPackageManagerServerInitialize (when setting the logs 181 // to Windows.Storage folders, automatic CoInitializeSecurity is triggered) 182 RETURN_IF_FAILED(InitializeComSecurity()); 183 } 184 185 RETURN_IF_FAILED(WindowsPackageManagerServerInitialize()); 186 187 _comServerExitEvent.create(); 188 RETURN_IF_FAILED(WindowsPackageManagerServerModuleCreate(&_releaseNotifier)); 189 try 190 { 191 // Manual reset event to notify the client that the server is available. 192 wil::unique_event manualResetEvent; 193 194 if (manualActivation) 195 { 196 // For manual activation, do not register com objects 197 // so that only RPC channel can be used. 198 HANDLE hMutex = NULL; 199 hMutex = CreateMutex(NULL, FALSE, TEXT("WinGetServerMutex")); 200 RETURN_LAST_ERROR_IF_NULL(hMutex); 201 202 DWORD waitResult = WaitForSingleObject(hMutex, 0); 203 if (waitResult != WAIT_OBJECT_0 && waitResult != WAIT_ABANDONED) 204 { 205 return HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING); 206 } 207 208 RETURN_IF_FAILED(WindowsPackageManagerServerInitializeRPCServer()); 209 210 manualResetEvent = CreateOrOpenServerStartEvent(); 211 manualResetEvent.SetEvent(); 212 } 213 else 214 { 215 // Register all the CoCreatableClassWrlCreatorMapInclude classes 216 RETURN_IF_FAILED(WindowsPackageManagerServerModuleRegister()); 217 } 218 219 _comServerExitEvent.wait(); 220 221 if (manualResetEvent) 222 { 223 manualResetEvent.reset(); 224 } 225 226 if (!manualActivation) 227 { 228 RETURN_IF_FAILED(WindowsPackageManagerServerModuleUnregister()); 229 } 230 } 231 CATCH_RETURN() 232 233 return 0; 234 }