1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "sandbox/win/tests/common/test_utils.h"
6 
7 #include <stddef.h>
8 #include <winioctl.h>
9 
10 #include "base/numerics/safe_conversions.h"
11 
12 namespace sandbox {
13 
14 typedef struct _REPARSE_DATA_BUFFER {
15   ULONG  ReparseTag;
16   USHORT  ReparseDataLength;
17   USHORT  Reserved;
18   union {
19     struct {
20       USHORT SubstituteNameOffset;
21       USHORT SubstituteNameLength;
22       USHORT PrintNameOffset;
23       USHORT PrintNameLength;
24       ULONG Flags;
25       WCHAR PathBuffer[1];
26       } SymbolicLinkReparseBuffer;
27     struct {
28       USHORT SubstituteNameOffset;
29       USHORT SubstituteNameLength;
30       USHORT PrintNameOffset;
31       USHORT PrintNameLength;
32       WCHAR PathBuffer[1];
33       } MountPointReparseBuffer;
34     struct {
35       UCHAR DataBuffer[1];
36     } GenericReparseBuffer;
37   };
38 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
39 
40 // Sets a reparse point. |source| will now point to |target|. Returns true if
41 // the call succeeds, false otherwise.
SetReparsePoint(HANDLE source,const wchar_t * target)42 bool SetReparsePoint(HANDLE source, const wchar_t* target) {
43   USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]);
44 
45   char buffer[2000] = {0};
46   DWORD returned;
47 
48   REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
49 
50   data->ReparseTag = 0xa0000003;
51   memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2);
52   data->MountPointReparseBuffer.SubstituteNameLength = size_target;
53   data->MountPointReparseBuffer.PrintNameOffset = size_target + 2;
54   data->ReparseDataLength = size_target + 4 + 8;
55 
56   int data_size = data->ReparseDataLength + 8;
57 
58   if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size,
59                        NULL, 0, &returned, NULL)) {
60     return false;
61   }
62   return true;
63 }
64 
65 // Delete the reparse point referenced by |source|. Returns true if the call
66 // succeeds, false otherwise.
DeleteReparsePoint(HANDLE source)67 bool DeleteReparsePoint(HANDLE source) {
68   DWORD returned;
69   REPARSE_DATA_BUFFER data = {0};
70   data.ReparseTag = 0xa0000003;
71   if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0,
72                        &returned, NULL)) {
73     return false;
74   }
75 
76   return true;
77 }
78 
SidAndAttributes(const SID_AND_ATTRIBUTES & sid_and_attributes)79 SidAndAttributes::SidAndAttributes(const SID_AND_ATTRIBUTES& sid_and_attributes)
80     : attributes_(sid_and_attributes.Attributes),
81       sid_(sid_and_attributes.Sid) {}
82 
GetPSID() const83 PSID SidAndAttributes::GetPSID() const {
84   return sid_.GetPSID();
85 }
86 
GetAttributes() const87 DWORD SidAndAttributes::GetAttributes() const {
88   return attributes_;
89 }
90 
GetTokenAppContainerSid(HANDLE token,std::unique_ptr<sandbox::Sid> * app_container_sid)91 bool GetTokenAppContainerSid(HANDLE token,
92                              std::unique_ptr<sandbox::Sid>* app_container_sid) {
93   std::vector<char> app_container_info(sizeof(TOKEN_APPCONTAINER_INFORMATION) +
94                                        SECURITY_MAX_SID_SIZE);
95   DWORD return_length;
96 
97   if (!::GetTokenInformation(
98           token, TokenAppContainerSid, app_container_info.data(),
99           base::checked_cast<DWORD>(app_container_info.size()),
100           &return_length)) {
101     return false;
102   }
103 
104   PTOKEN_APPCONTAINER_INFORMATION info =
105       reinterpret_cast<PTOKEN_APPCONTAINER_INFORMATION>(
106           app_container_info.data());
107   if (!info->TokenAppContainer)
108     return false;
109   *app_container_sid = std::make_unique<sandbox::Sid>(info->TokenAppContainer);
110   return true;
111 }
112 
GetTokenGroups(HANDLE token,TOKEN_INFORMATION_CLASS information_class,std::vector<SidAndAttributes> * token_groups)113 bool GetTokenGroups(HANDLE token,
114                     TOKEN_INFORMATION_CLASS information_class,
115                     std::vector<SidAndAttributes>* token_groups) {
116   if (information_class != ::TokenCapabilities &&
117       information_class != ::TokenGroups &&
118       information_class != ::TokenRestrictedSids) {
119     return false;
120   }
121 
122   std::vector<char> groups_buf;
123   if (!GetVariableTokenInformation(token, information_class, &groups_buf))
124     return false;
125 
126   PTOKEN_GROUPS groups = reinterpret_cast<PTOKEN_GROUPS>(groups_buf.data());
127 
128   if (groups->GroupCount > 0) {
129     token_groups->insert(token_groups->begin(), groups->Groups,
130                          groups->Groups + groups->GroupCount);
131   }
132 
133   return true;
134 }
135 
GetVariableTokenInformation(HANDLE token,TOKEN_INFORMATION_CLASS information_class,std::vector<char> * information)136 bool GetVariableTokenInformation(HANDLE token,
137                                  TOKEN_INFORMATION_CLASS information_class,
138                                  std::vector<char>* information) {
139   DWORD return_length;
140   if (!::GetTokenInformation(token, information_class, nullptr, 0,
141                              &return_length)) {
142     if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
143       return false;
144   }
145 
146   information->resize(return_length);
147   return !!::GetTokenInformation(token, information_class, information->data(),
148                                  return_length, &return_length);
149 }
150 
151 }  // namespace sandbox
152