installed pty
[VSoRC/.git] / node_modules / node-pty / deps / winpty / src / shared / WindowsSecurity.cc
1 // Copyright (c) 2016 Ryan Prichard
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to
5 // deal in the Software without restriction, including without limitation the
6 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 // sell copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 // IN THE SOFTWARE.
20
21 #include "WindowsSecurity.h"
22
23 #include <array>
24
25 #include "DebugClient.h"
26 #include "OsModule.h"
27 #include "OwnedHandle.h"
28 #include "StringBuilder.h"
29 #include "WindowsVersion.h"
30 #include "WinptyAssert.h"
31 #include "WinptyException.h"
32
33 namespace {
34
35 struct LocalFreer {
36     void operator()(void *ptr) {
37         if (ptr != nullptr) {
38             LocalFree(reinterpret_cast<HLOCAL>(ptr));
39         }
40     }
41 };
42
43 typedef std::unique_ptr<void, LocalFreer> PointerLocal;
44
45 template <typename T>
46 SecurityItem<T> localItem(typename T::type v) {
47     typedef typename T::type P;
48     struct Impl : SecurityItem<T>::Impl {
49         P m_v;
50         Impl(P v) : m_v(v) {}
51         virtual ~Impl() {
52             LocalFree(reinterpret_cast<HLOCAL>(m_v));
53         }
54     };
55     return SecurityItem<T>(v, std::unique_ptr<Impl>(new Impl { v }));
56 }
57
58 Sid allocatedSid(PSID v) {
59     struct Impl : Sid::Impl {
60         PSID m_v;
61         Impl(PSID v) : m_v(v) {}
62         virtual ~Impl() {
63             if (m_v != nullptr) {
64                 FreeSid(m_v);
65             }
66         }
67     };
68     return Sid(v, std::unique_ptr<Impl>(new Impl { v }));
69 }
70
71 } // anonymous namespace
72
73 // Returns a handle to the thread's effective security token.  If the thread
74 // is impersonating another user, its token is returned, and otherwise, the
75 // process' security token is opened.  The handle is opened with TOKEN_QUERY.
76 static OwnedHandle openSecurityTokenForQuery() {
77     HANDLE token = nullptr;
78     // It is unclear to me whether OpenAsSelf matters for winpty, or what the
79     // most appropriate value is.
80     if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY,
81                          /*OpenAsSelf=*/FALSE, &token)) {
82         if (GetLastError() != ERROR_NO_TOKEN) {
83             throwWindowsError(L"OpenThreadToken failed");
84         }
85         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
86             throwWindowsError(L"OpenProcessToken failed");
87         }
88     }
89     ASSERT(token != nullptr &&
90         "OpenThreadToken/OpenProcessToken token is NULL");
91     return OwnedHandle(token);
92 }
93
94 // Returns the TokenOwner of the thread's effective security token.
95 Sid getOwnerSid() {
96     struct Impl : Sid::Impl {
97         std::unique_ptr<char[]> buffer;
98     };
99
100     OwnedHandle token = openSecurityTokenForQuery();
101     DWORD actual = 0;
102     BOOL success;
103     success = GetTokenInformation(token.get(), TokenOwner,
104         nullptr, 0, &actual);
105     if (success) {
106         throwWinptyException(L"getOwnerSid: GetTokenInformation: "
107             L"expected ERROR_INSUFFICIENT_BUFFER");
108     } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
109         throwWindowsError(L"getOwnerSid: GetTokenInformation: "
110             L"expected ERROR_INSUFFICIENT_BUFFER");
111     }
112     std::unique_ptr<Impl> impl(new Impl);
113     impl->buffer = std::unique_ptr<char[]>(new char[actual]);
114     success = GetTokenInformation(token.get(), TokenOwner,
115                                   impl->buffer.get(), actual, &actual);
116     if (!success) {
117         throwWindowsError(L"getOwnerSid: GetTokenInformation");
118     }
119     TOKEN_OWNER tmp;
120     ASSERT(actual >= sizeof(tmp));
121     std::copy(
122         impl->buffer.get(),
123         impl->buffer.get() + sizeof(tmp),
124         reinterpret_cast<char*>(&tmp));
125     return Sid(tmp.Owner, std::move(impl));
126 }
127
128 Sid wellKnownSid(
129         const wchar_t *debuggingName,
130         SID_IDENTIFIER_AUTHORITY authority,
131         BYTE authorityCount,
132         DWORD subAuthority0/*=0*/,
133         DWORD subAuthority1/*=0*/) {
134     PSID psid = nullptr;
135     if (!AllocateAndInitializeSid(&authority, authorityCount,
136             subAuthority0,
137             subAuthority1,
138             0, 0, 0, 0, 0, 0,
139             &psid)) {
140         const auto err = GetLastError();
141         const auto msg =
142             std::wstring(L"wellKnownSid: error getting ") +
143             debuggingName + L" SID";
144         throwWindowsError(msg.c_str(), err);
145     }
146     return allocatedSid(psid);
147 }
148
149 Sid builtinAdminsSid() {
150     // S-1-5-32-544
151     SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
152     return wellKnownSid(L"BUILTIN\\Administrators group",
153             authority, 2,
154             SECURITY_BUILTIN_DOMAIN_RID,    // 32
155             DOMAIN_ALIAS_RID_ADMINS);       // 544
156 }
157
158 Sid localSystemSid() {
159     // S-1-5-18
160     SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
161     return wellKnownSid(L"LocalSystem account",
162             authority, 1,
163             SECURITY_LOCAL_SYSTEM_RID);     // 18
164 }
165
166 Sid everyoneSid() {
167     // S-1-1-0
168     SID_IDENTIFIER_AUTHORITY authority = { SECURITY_WORLD_SID_AUTHORITY };
169     return wellKnownSid(L"Everyone account",
170             authority, 1,
171             SECURITY_WORLD_RID);            // 0
172 }
173
174 static SecurityDescriptor finishSecurityDescriptor(
175         size_t daclEntryCount,
176         EXPLICIT_ACCESSW *daclEntries,
177         Acl &outAcl) {
178     {
179         PACL aclRaw = nullptr;
180         DWORD aclError =
181             SetEntriesInAclW(daclEntryCount,
182                              daclEntries,
183                              nullptr, &aclRaw);
184         if (aclError != ERROR_SUCCESS) {
185             WStringBuilder sb(64);
186             sb << L"finishSecurityDescriptor: "
187                << L"SetEntriesInAcl failed: " << aclError;
188             throwWinptyException(sb.c_str());
189         }
190         outAcl = localItem<AclTag>(aclRaw);
191     }
192
193     const PSECURITY_DESCRIPTOR sdRaw =
194         reinterpret_cast<PSECURITY_DESCRIPTOR>(
195             LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
196     if (sdRaw == nullptr) {
197         throwWinptyException(L"finishSecurityDescriptor: LocalAlloc failed");
198     }
199     SecurityDescriptor sd = localItem<SecurityDescriptorTag>(sdRaw);
200     if (!InitializeSecurityDescriptor(sdRaw, SECURITY_DESCRIPTOR_REVISION)) {
201         throwWindowsError(
202             L"finishSecurityDescriptor: InitializeSecurityDescriptor");
203     }
204     if (!SetSecurityDescriptorDacl(sdRaw, TRUE, outAcl.get(), FALSE)) {
205         throwWindowsError(
206             L"finishSecurityDescriptor: SetSecurityDescriptorDacl");
207     }
208
209     return std::move(sd);
210 }
211
212 // Create a security descriptor that grants full control to the local system
213 // account, built-in administrators, and the owner.
214 SecurityDescriptor
215 createPipeSecurityDescriptorOwnerFullControl() {
216
217     struct Impl : SecurityDescriptor::Impl {
218         Sid localSystem;
219         Sid builtinAdmins;
220         Sid owner;
221         std::array<EXPLICIT_ACCESSW, 3> daclEntries = {};
222         Acl dacl;
223         SecurityDescriptor value;
224     };
225
226     std::unique_ptr<Impl> impl(new Impl);
227     impl->localSystem = localSystemSid();
228     impl->builtinAdmins = builtinAdminsSid();
229     impl->owner = getOwnerSid();
230
231     for (auto &ea : impl->daclEntries) {
232         ea.grfAccessPermissions = GENERIC_ALL;
233         ea.grfAccessMode = SET_ACCESS;
234         ea.grfInheritance = NO_INHERITANCE;
235         ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
236     }
237     impl->daclEntries[0].Trustee.ptstrName =
238         reinterpret_cast<LPWSTR>(impl->localSystem.get());
239     impl->daclEntries[1].Trustee.ptstrName =
240         reinterpret_cast<LPWSTR>(impl->builtinAdmins.get());
241     impl->daclEntries[2].Trustee.ptstrName =
242         reinterpret_cast<LPWSTR>(impl->owner.get());
243
244     impl->value = finishSecurityDescriptor(
245         impl->daclEntries.size(),
246         impl->daclEntries.data(),
247         impl->dacl);
248
249     const auto retValue = impl->value.get();
250     return SecurityDescriptor(retValue, std::move(impl));
251 }
252
253 SecurityDescriptor
254 createPipeSecurityDescriptorOwnerFullControlEveryoneWrite() {
255
256     struct Impl : SecurityDescriptor::Impl {
257         Sid localSystem;
258         Sid builtinAdmins;
259         Sid owner;
260         Sid everyone;
261         std::array<EXPLICIT_ACCESSW, 4> daclEntries = {};
262         Acl dacl;
263         SecurityDescriptor value;
264     };
265
266     std::unique_ptr<Impl> impl(new Impl);
267     impl->localSystem = localSystemSid();
268     impl->builtinAdmins = builtinAdminsSid();
269     impl->owner = getOwnerSid();
270     impl->everyone = everyoneSid();
271
272     for (auto &ea : impl->daclEntries) {
273         ea.grfAccessPermissions = GENERIC_ALL;
274         ea.grfAccessMode = SET_ACCESS;
275         ea.grfInheritance = NO_INHERITANCE;
276         ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
277     }
278     impl->daclEntries[0].Trustee.ptstrName =
279         reinterpret_cast<LPWSTR>(impl->localSystem.get());
280     impl->daclEntries[1].Trustee.ptstrName =
281         reinterpret_cast<LPWSTR>(impl->builtinAdmins.get());
282     impl->daclEntries[2].Trustee.ptstrName =
283         reinterpret_cast<LPWSTR>(impl->owner.get());
284     impl->daclEntries[3].Trustee.ptstrName =
285         reinterpret_cast<LPWSTR>(impl->everyone.get());
286     // Avoid using FILE_GENERIC_WRITE because it includes FILE_APPEND_DATA,
287     // which is equal to FILE_CREATE_PIPE_INSTANCE.  Instead, include all the
288     // flags that comprise FILE_GENERIC_WRITE, except for the one.
289     impl->daclEntries[3].grfAccessPermissions =
290         FILE_GENERIC_READ |
291         FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA |
292         STANDARD_RIGHTS_WRITE | SYNCHRONIZE;
293
294     impl->value = finishSecurityDescriptor(
295         impl->daclEntries.size(),
296         impl->daclEntries.data(),
297         impl->dacl);
298
299     const auto retValue = impl->value.get();
300     return SecurityDescriptor(retValue, std::move(impl));
301 }
302
303 SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle) {
304     PACL dacl = nullptr;
305     PSECURITY_DESCRIPTOR sd = nullptr;
306     const DWORD errCode = GetSecurityInfo(handle, SE_KERNEL_OBJECT,
307         OWNER_SECURITY_INFORMATION |
308             GROUP_SECURITY_INFORMATION |
309             DACL_SECURITY_INFORMATION,
310         nullptr, nullptr, &dacl, nullptr, &sd);
311     if (errCode != ERROR_SUCCESS) {
312         throwWindowsError(L"GetSecurityInfo failed");
313     }
314     return localItem<SecurityDescriptorTag>(sd);
315 }
316
317 // The (SID/SD)<->string conversion APIs are useful for testing/debugging, so
318 // create convenient accessor functions for them.  They're too slow for
319 // ordinary use.  The APIs exist in XP and up, but the MinGW headers only
320 // declare the SID<->string APIs, not the SD APIs.  MinGW also gets the
321 // prototype wrong for ConvertStringSidToSidW (LPWSTR instead of LPCWSTR) and
322 // requires WINVER to be defined.  MSVC and MinGW-w64 get everything right, but
323 // for consistency, use LoadLibrary/GetProcAddress for all four APIs.
324
325 typedef BOOL WINAPI ConvertStringSidToSidW_t(
326     LPCWSTR StringSid,
327     PSID *Sid);
328
329 typedef BOOL WINAPI ConvertSidToStringSidW_t(
330     PSID Sid,
331     LPWSTR *StringSid);
332
333 typedef BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW_t(
334     LPCWSTR StringSecurityDescriptor,
335     DWORD StringSDRevision,
336     PSECURITY_DESCRIPTOR *SecurityDescriptor,
337     PULONG SecurityDescriptorSize);
338
339 typedef BOOL WINAPI ConvertSecurityDescriptorToStringSecurityDescriptorW_t(
340     PSECURITY_DESCRIPTOR SecurityDescriptor,
341     DWORD RequestedStringSDRevision,
342     SECURITY_INFORMATION SecurityInformation,
343     LPWSTR *StringSecurityDescriptor,
344     PULONG StringSecurityDescriptorLen);
345
346 #define GET_MODULE_PROC(mod, funcName)                                      \
347     const auto p##funcName =                                                \
348         reinterpret_cast<funcName##_t*>(                                    \
349             mod.proc(#funcName));                                           \
350     if (p##funcName == nullptr) {                                           \
351         throwWinptyException(                                               \
352             L"" L ## #funcName L" API is missing from ADVAPI32.DLL");     \
353     }
354
355 const DWORD kSDDL_REVISION_1 = 1;
356
357 std::wstring sidToString(PSID sid) {
358     OsModule advapi32(L"advapi32.dll");
359     GET_MODULE_PROC(advapi32, ConvertSidToStringSidW);
360     wchar_t *sidString = NULL;
361     BOOL success = pConvertSidToStringSidW(sid, &sidString);
362     if (!success) {
363         throwWindowsError(L"ConvertSidToStringSidW failed");
364     }
365     PointerLocal freer(sidString);
366     return std::wstring(sidString);
367 }
368
369 Sid stringToSid(const std::wstring &str) {
370     // Cast the string from const wchar_t* to LPWSTR because the function is
371     // incorrectly prototyped in the MinGW sddl.h header.  The API does not
372     // modify the string -- it is correctly prototyped as taking LPCWSTR in
373     // MinGW-w64, MSVC, and MSDN.
374     OsModule advapi32(L"advapi32.dll");
375     GET_MODULE_PROC(advapi32, ConvertStringSidToSidW);
376     PSID psid = nullptr;
377     BOOL success = pConvertStringSidToSidW(const_cast<LPWSTR>(str.c_str()),
378                                            &psid);
379     if (!success) {
380         const auto err = GetLastError();
381         throwWindowsError(
382             (std::wstring(L"ConvertStringSidToSidW failed on \"") +
383                 str + L'"').c_str(),
384             err);
385     }
386     return localItem<SidTag>(psid);
387 }
388
389 SecurityDescriptor stringToSd(const std::wstring &str) {
390     OsModule advapi32(L"advapi32.dll");
391     GET_MODULE_PROC(advapi32, ConvertStringSecurityDescriptorToSecurityDescriptorW);
392     PSECURITY_DESCRIPTOR desc = nullptr;
393     if (!pConvertStringSecurityDescriptorToSecurityDescriptorW(
394             str.c_str(), kSDDL_REVISION_1, &desc, nullptr)) {
395         const auto err = GetLastError();
396         throwWindowsError(
397             (std::wstring(L"ConvertStringSecurityDescriptorToSecurityDescriptorW failed on \"") +
398                 str + L'"').c_str(),
399             err);
400     }
401     return localItem<SecurityDescriptorTag>(desc);
402 }
403
404 std::wstring sdToString(PSECURITY_DESCRIPTOR sd) {
405     OsModule advapi32(L"advapi32.dll");
406     GET_MODULE_PROC(advapi32, ConvertSecurityDescriptorToStringSecurityDescriptorW);
407     wchar_t *sdString = nullptr;
408     if (!pConvertSecurityDescriptorToStringSecurityDescriptorW(
409             sd,
410             kSDDL_REVISION_1,
411             OWNER_SECURITY_INFORMATION |
412                 GROUP_SECURITY_INFORMATION |
413                 DACL_SECURITY_INFORMATION,
414             &sdString,
415             nullptr)) {
416         throwWindowsError(
417             L"ConvertSecurityDescriptorToStringSecurityDescriptor failed");
418     }
419     PointerLocal freer(sdString);
420     return std::wstring(sdString);
421 }
422
423 // Vista added a useful flag to CreateNamedPipe, PIPE_REJECT_REMOTE_CLIENTS,
424 // that rejects remote connections.  Return this flag on Vista, or return 0
425 // otherwise.
426 DWORD rejectRemoteClientsPipeFlag() {
427     if (isAtLeastWindowsVista()) {
428         // MinGW lacks this flag; MinGW-w64 has it.
429         const DWORD kPIPE_REJECT_REMOTE_CLIENTS = 8;
430         return kPIPE_REJECT_REMOTE_CLIENTS;
431     } else {
432         trace("Omitting PIPE_REJECT_REMOTE_CLIENTS on pre-Vista OS");
433         return 0;
434     }
435 }
436
437 typedef BOOL WINAPI GetNamedPipeClientProcessId_t(
438     HANDLE Pipe,
439     PULONG ClientProcessId);
440
441 std::tuple<GetNamedPipeClientProcessId_Result, DWORD, DWORD>
442 getNamedPipeClientProcessId(HANDLE serverPipe) {
443     OsModule kernel32(L"kernel32.dll");
444     const auto pGetNamedPipeClientProcessId =
445         reinterpret_cast<GetNamedPipeClientProcessId_t*>(
446             kernel32.proc("GetNamedPipeClientProcessId"));
447     if (pGetNamedPipeClientProcessId == nullptr) {
448         return std::make_tuple(
449             GetNamedPipeClientProcessId_Result::UnsupportedOs, 0, 0);
450     }
451     ULONG pid = 0;
452     if (!pGetNamedPipeClientProcessId(serverPipe, &pid)) {
453         return std::make_tuple(
454             GetNamedPipeClientProcessId_Result::Failure, 0, GetLastError());
455     }
456     return std::make_tuple(
457         GetNamedPipeClientProcessId_Result::Success,
458         static_cast<DWORD>(pid),
459         0);
460 }