forked from microsoft/winget-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWinMain.cpp
More file actions
173 lines (137 loc) · 6.33 KB
/
Copy pathWinMain.cpp
File metadata and controls
173 lines (137 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#define NOMINMAX
#pragma warning( push )
#pragma warning ( disable : 6001 6388 6553)
#include <wil/resource.h>
#include <wil/com.h>
#pragma warning( pop )
#include <objidl.h>
#include <shellapi.h>
#include <sddl.h>
#include <WindowsPackageManager.h>
#include "WinGetServer.h"
#include "Utils.h"
#include <memory>
#include <string>
#include <string_view>
// Holds the wwinmain open until COM tells us there are no more server connections
wil::unique_event _comServerExitEvent;
// Routine Description:
// - Called back when COM says there is nothing left for our server to do and we can tear down.
static void _releaseNotifier() noexcept
{
_comServerExitEvent.SetEvent();
}
HRESULT WindowsPackageManagerServerInitializeRPCServer()
{
std::string userSID = GetUserSID();
std::string endpoint = "\\pipe\\WinGetServerManualActivation_" + userSID;
RPC_STATUS status = RpcServerUseProtseqEpA(GetUCharString("ncacn_np"), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, GetUCharString(endpoint), nullptr);
RETURN_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK);
// The goal of this security descriptor is to restrict RPC server access only to the user in admin mode.
// (ML;;NW;;;HI) specifies a high mandatory integrity level (requires admin).
// (A;;GA;;;UserSID) specifies access only for the user with the user SID (i.e. self).
wil::unique_hlocal_security_descriptor securityDescriptor;
std::string securityDescriptorString = "S:(ML;;NW;;;HI)D:(A;;GA;;;" + userSID + ")";
RETURN_LAST_ERROR_IF(!ConvertStringSecurityDescriptorToSecurityDescriptorA(securityDescriptorString.c_str(), SDDL_REVISION_1, &securityDescriptor, nullptr));
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());
RETURN_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK);
return S_OK;
}
_Must_inspect_result_
_Ret_maybenull_ _Post_writable_byte_size_(size)
void* __RPC_USER MIDL_user_allocate(_In_ size_t size)
{
return malloc(size);
}
void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr)
{
if (ptr)
{
free(ptr);
}
}
extern "C" HRESULT CreateInstance(
/* [in] */ GUID clsid,
/* [in] */ GUID iid,
/* [in] */ UINT32,
/* [ref][out] */ UINT32 * pcbBuffer,
/* [size_is][size_is][ref][out] */ BYTE * *ppBuffer)
{
RETURN_HR_IF_NULL(E_POINTER, pcbBuffer);
RETURN_HR_IF_NULL(E_POINTER, ppBuffer);
wil::com_ptr<IStream> stream;
RETURN_IF_FAILED(CreateStreamOnHGlobal(nullptr, TRUE, &stream));
wil::com_ptr<IUnknown> instance;
RETURN_IF_FAILED(WindowsPackageManagerServerCreateInstance(clsid, iid, reinterpret_cast<void**>(&instance)));
RETURN_IF_FAILED(CoMarshalInterface(stream.get(), iid, instance.get(), MSHCTX_LOCAL, nullptr, MSHLFLAGS_NORMAL));
ULARGE_INTEGER streamSize{};
RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_CUR, &streamSize));
RETURN_HR_IF(E_NOT_SUFFICIENT_BUFFER, streamSize.QuadPart > std::numeric_limits<UINT32>::max());
UINT32 bufferSize = static_cast<UINT32>(streamSize.QuadPart);
struct DeleteWithMidlFree { void operator()(void* m) { MIDL_user_free(m); } };
std::unique_ptr<BYTE, DeleteWithMidlFree> buffer{ reinterpret_cast<BYTE*>(MIDL_user_allocate(bufferSize)) };
RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_SET, nullptr));
ULONG bytesRead = 0;
RETURN_IF_FAILED(stream->Read(buffer.get(), bufferSize, &bytesRead));
RETURN_HR_IF(E_UNEXPECTED, bytesRead != bufferSize);
*pcbBuffer = bufferSize;
*ppBuffer = buffer.release();
return S_OK;
}
int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLine, _In_ int)
{
wil::SetResultLoggingCallback(&WindowsPackageManagerServerWilResultLoggingCallback);
RETURN_IF_FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED));
// Enable fast rundown of objects so that the server exits faster when clients go away.
{
wil::com_ptr<IGlobalOptions> globalOptions;
RETURN_IF_FAILED(CoCreateInstance(CLSID_GlobalOptions, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&globalOptions)));
RETURN_IF_FAILED(globalOptions->Set(COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN));
RETURN_IF_FAILED(globalOptions->Set(COMGLB_UNMARSHALING_POLICY, COMGLB_UNMARSHALING_POLICY_STRONG));
RETURN_IF_FAILED(globalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE_ANY));
}
RETURN_IF_FAILED(WindowsPackageManagerServerInitialize());
// Command line parsing
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(cmdLine, &argc);
RETURN_LAST_ERROR_IF(!argv);
bool manualActivation = false;
// If command line gets more complicated, consider more complex parsing
if (argc == 1 && std::wstring_view{ L"--manualActivation" } == argv[0])
{
manualActivation = true;
}
_comServerExitEvent.create();
RETURN_IF_FAILED(WindowsPackageManagerServerModuleCreate(&_releaseNotifier));
try
{
// Register all the CoCreatableClassWrlCreatorMapInclude classes
RETURN_IF_FAILED(WindowsPackageManagerServerModuleRegister());
// Manual reset event to notify the client that the server is available.
wil::unique_event manualResetEvent;
if (manualActivation)
{
HANDLE hMutex = NULL;
hMutex = CreateMutex(NULL, FALSE, TEXT("WinGetServerMutex"));
RETURN_LAST_ERROR_IF_NULL(hMutex);
DWORD waitResult = WaitForSingleObject(hMutex, 0);
if (waitResult != WAIT_OBJECT_0 && waitResult != WAIT_ABANDONED)
{
return HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING);
}
RETURN_IF_FAILED(WindowsPackageManagerServerInitializeRPCServer());
manualResetEvent = CreateOrOpenServerStartEvent();
manualResetEvent.SetEvent();
}
_comServerExitEvent.wait();
if (manualResetEvent)
{
manualResetEvent.reset();
}
RETURN_IF_FAILED(WindowsPackageManagerServerModuleUnregister());
}
CATCH_RETURN()
return 0;
}