OLD | NEW |
| (Empty) |
1 // Copyright 2006-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 #include "omaha/base/vistautil.h" | |
17 #include <accctrl.h> | |
18 #include <Aclapi.h> | |
19 #include <Sddl.h> | |
20 #include <ShellAPI.h> | |
21 #include <shlobj.h> | |
22 #include "base/scoped_ptr.h" | |
23 #include "omaha/base/debug.h" | |
24 #include "omaha/base/error.h" | |
25 #include "omaha/base/logging.h" | |
26 #include "omaha/base/process.h" | |
27 #include "omaha/base/reg_key.h" | |
28 #include "omaha/base/utils.h" | |
29 #include "omaha/base/vista_utils.h" | |
30 #include "omaha/third_party/smartany/scoped_any.h" | |
31 | |
32 namespace omaha { | |
33 | |
34 namespace vista_util { | |
35 | |
36 static SID_IDENTIFIER_AUTHORITY mandatory_label_auth = | |
37 SECURITY_MANDATORY_LABEL_AUTHORITY; | |
38 | |
39 | |
40 static HRESULT GetSidIntegrityLevel(PSID sid, MANDATORY_LEVEL* level) { | |
41 if (!IsValidSid(sid)) | |
42 return E_FAIL; | |
43 | |
44 SID_IDENTIFIER_AUTHORITY* authority = GetSidIdentifierAuthority(sid); | |
45 if (!authority) | |
46 return E_FAIL; | |
47 | |
48 if (memcmp(authority, &mandatory_label_auth, | |
49 sizeof(SID_IDENTIFIER_AUTHORITY))) | |
50 return E_FAIL; | |
51 | |
52 PUCHAR count = GetSidSubAuthorityCount(sid); | |
53 if (!count || *count != 1) | |
54 return E_FAIL; | |
55 | |
56 DWORD* rid = GetSidSubAuthority(sid, 0); | |
57 if (!rid) | |
58 return E_FAIL; | |
59 | |
60 if ((*rid & 0xFFF) != 0 || *rid > SECURITY_MANDATORY_PROTECTED_PROCESS_RID) | |
61 return E_FAIL; | |
62 | |
63 *level = static_cast<MANDATORY_LEVEL>(*rid >> 12); | |
64 return S_OK; | |
65 } | |
66 | |
67 // Will return S_FALSE and MandatoryLevelMedium if the acl is NULL | |
68 static HRESULT GetAclIntegrityLevel(PACL acl, MANDATORY_LEVEL* level, | |
69 bool* and_children) { | |
70 *level = MandatoryLevelMedium; | |
71 if (and_children) | |
72 *and_children = false; | |
73 if (!acl) { | |
74 // This is the default label value if the acl was empty | |
75 return S_FALSE; | |
76 } | |
77 | |
78 SYSTEM_MANDATORY_LABEL_ACE* mandatory_label_ace; | |
79 if (!GetAce(acl, 0, reinterpret_cast<void**>(&mandatory_label_ace))) | |
80 return S_FALSE; | |
81 | |
82 if (mandatory_label_ace->Header.AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE) | |
83 return S_FALSE; | |
84 | |
85 if (!(mandatory_label_ace->Mask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP)) { | |
86 // I have found that if this flag is not set, a low integrity label doesn't | |
87 // prevent writes from being virtualized. MS provides zero documentation. | |
88 // I just did an MSDN search, a Google search, and a search of the Beta | |
89 // Vista SDKs, and no docs. TODO(omaha): Check docs again periodically. | |
90 // For now, act as if no label was set, and default to medium. | |
91 return S_FALSE; | |
92 } | |
93 | |
94 if (and_children) { | |
95 *and_children = ((mandatory_label_ace->Header.AceFlags & | |
96 (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)) | |
97 == (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)); | |
98 } | |
99 | |
100 return GetSidIntegrityLevel(reinterpret_cast<SID*>(&mandatory_label_ace-> | |
101 SidStart), level); | |
102 } | |
103 | |
104 // If successful, the caller needs to free the ACL using LocalFree() | |
105 // on failure, returns NULL | |
106 static ACL* CreateMandatoryLabelAcl(MANDATORY_LEVEL level, bool and_children) { | |
107 int ace_size = sizeof(SYSTEM_MANDATORY_LABEL_ACE) | |
108 - sizeof(DWORD) + GetSidLengthRequired(1); | |
109 int acl_size = sizeof(ACL) + ace_size; | |
110 | |
111 ACL* acl = reinterpret_cast<ACL*>(LocalAlloc(LPTR, acl_size)); | |
112 if (!acl) | |
113 return NULL; | |
114 | |
115 bool failed = true; | |
116 if (InitializeAcl(acl, acl_size, ACL_REVISION)) { | |
117 if (level > 0) { | |
118 SYSTEM_MANDATORY_LABEL_ACE* ace = reinterpret_cast< | |
119 SYSTEM_MANDATORY_LABEL_ACE*>(LocalAlloc(LPTR, ace_size)); | |
120 if (ace) { | |
121 ace->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE; | |
122 ace->Header.AceFlags = and_children ? | |
123 (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) : 0; | |
124 ace->Header.AceSize = static_cast<WORD>(ace_size); | |
125 ace->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; | |
126 | |
127 SID* sid = reinterpret_cast<SID*>(&ace->SidStart); | |
128 | |
129 if (InitializeSid(sid, &mandatory_label_auth, 1)) { | |
130 *GetSidSubAuthority(sid, 0) = static_cast<DWORD>(level) << 12; | |
131 failed = !AddAce(acl, ACL_REVISION, 0, ace, ace_size); | |
132 } | |
133 LocalFree(ace); | |
134 } | |
135 } | |
136 } | |
137 if (failed) { | |
138 LocalFree(acl); | |
139 acl = NULL; | |
140 } | |
141 return acl; | |
142 } | |
143 | |
144 | |
145 TCHAR* AllocFullRegPath(HKEY root, const TCHAR* subkey) { | |
146 if (!subkey) | |
147 return NULL; | |
148 | |
149 const TCHAR* root_string; | |
150 | |
151 if (root == HKEY_CURRENT_USER) | |
152 root_string = _T("CURRENT_USER\\"); | |
153 else if (root == HKEY_LOCAL_MACHINE) | |
154 root_string = _T("MACHINE\\"); | |
155 else if (root == HKEY_CLASSES_ROOT) | |
156 root_string = _T("CLASSES_ROOT\\"); | |
157 else if (root == HKEY_USERS) | |
158 root_string = _T("USERS\\"); | |
159 else | |
160 return NULL; | |
161 | |
162 size_t root_size = _tcslen(root_string); | |
163 size_t size = root_size + _tcslen(subkey) + 1; | |
164 TCHAR* result = reinterpret_cast<TCHAR*>(LocalAlloc(LPTR, | |
165 size * sizeof(TCHAR))); | |
166 if (!result) | |
167 return NULL; | |
168 | |
169 memcpy(result, root_string, size * sizeof(TCHAR)); | |
170 memcpy(result + root_size, subkey, (1 + size - root_size) * sizeof(TCHAR)); | |
171 return result; | |
172 } | |
173 | |
174 | |
175 bool IsUserNonElevatedAdmin() { | |
176 // If pre-Vista return false; | |
177 if (!IsVistaOrLater()) { | |
178 return false; | |
179 } | |
180 | |
181 bool non_elevated_admin = false; | |
182 scoped_handle token; | |
183 if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_READ, address(token))) { | |
184 TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault; | |
185 DWORD infoLen = 0; | |
186 if (::GetTokenInformation(get(token), | |
187 TokenElevationType, | |
188 reinterpret_cast<void*>(&elevation_type), | |
189 sizeof(elevation_type), | |
190 &infoLen)) { | |
191 if (elevation_type == TokenElevationTypeLimited) { | |
192 non_elevated_admin = true; | |
193 } | |
194 } | |
195 } | |
196 | |
197 return non_elevated_admin; | |
198 } | |
199 | |
200 bool IsUserAdmin() { | |
201 // Determine if the user is part of the adminstators group. This will return | |
202 // true in case of XP and 2K if the user belongs to admin group. In case of | |
203 // Vista, it only returns true if the admin is running elevated. | |
204 SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; | |
205 PSID administrators_group = NULL; | |
206 BOOL result = ::AllocateAndInitializeSid(&nt_authority, | |
207 2, | |
208 SECURITY_BUILTIN_DOMAIN_RID, | |
209 DOMAIN_ALIAS_RID_ADMINS, | |
210 0, 0, 0, 0, 0, 0, | |
211 &administrators_group); | |
212 if (result) { | |
213 if (!::CheckTokenMembership(NULL, administrators_group, &result)) { | |
214 result = false; | |
215 } | |
216 ::FreeSid(administrators_group); | |
217 } | |
218 return !!result; | |
219 } | |
220 | |
221 bool IsVistaOrLater() { | |
222 static bool known = false; | |
223 static bool is_vista = false; | |
224 if (!known) { | |
225 OSVERSIONINFOEX osvi = { 0 }; | |
226 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
227 osvi.dwMajorVersion = 6; | |
228 DWORDLONG conditional = 0; | |
229 VER_SET_CONDITION(conditional, VER_MAJORVERSION, VER_GREATER_EQUAL); | |
230 is_vista = !!VerifyVersionInfo(&osvi, VER_MAJORVERSION, conditional); | |
231 // If the Win32 API failed for some other reason, callers may incorrectly | |
232 // perform non-Vista operations. Assert we don't see any other failures. | |
233 ASSERT1(is_vista || ERROR_OLD_WIN_VERSION == ::GetLastError()); | |
234 known = true; | |
235 } | |
236 return is_vista; | |
237 } | |
238 | |
239 HRESULT IsUserRunningSplitToken(bool* is_split_token) { | |
240 ASSERT1(is_split_token); | |
241 | |
242 if (!IsVistaOrLater()) { | |
243 *is_split_token = false; | |
244 return S_OK; | |
245 } | |
246 | |
247 scoped_handle process_token; | |
248 if (!::OpenProcessToken(::GetCurrentProcess(), | |
249 TOKEN_QUERY, | |
250 address(process_token))) { | |
251 HRESULT hr = HRESULTFromLastError(); | |
252 UTIL_LOG(L1, (_T("[OpenProcessToken failed][0x%x]"), hr)); | |
253 return hr; | |
254 } | |
255 | |
256 TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault; | |
257 DWORD size_returned = 0; | |
258 if (!::GetTokenInformation(get(process_token), | |
259 TokenElevationType, | |
260 &elevation_type, | |
261 sizeof(elevation_type), | |
262 &size_returned)) { | |
263 HRESULT hr = HRESULTFromLastError(); | |
264 UTIL_LOG(L1, (_T("[GetTokenInformation failed][0x%x]"), hr)); | |
265 return hr; | |
266 } | |
267 | |
268 *is_split_token = elevation_type == TokenElevationTypeFull || | |
269 elevation_type == TokenElevationTypeLimited; | |
270 ASSERT1(*is_split_token || elevation_type == TokenElevationTypeDefault); | |
271 | |
272 return S_OK; | |
273 } | |
274 | |
275 bool IsUACMaybeOn() { | |
276 ASSERT1(vista_util::IsVistaOrLater()); | |
277 | |
278 // The presence of a split token definitively indicates that UAC is on. But | |
279 // the absence does not necessarily indicate that UAC is off. | |
280 bool is_split_token = false; | |
281 if (SUCCEEDED(IsUserRunningSplitToken(&is_split_token)) && is_split_token) { | |
282 return true; | |
283 } | |
284 | |
285 const TCHAR* key_name = _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\") | |
286 _T("CurrentVersion\\Policies\\System"); | |
287 | |
288 DWORD enable_lua = 0; | |
289 return FAILED(RegKey::GetValue(key_name, _T("EnableLUA"), &enable_lua)) || | |
290 enable_lua; | |
291 } | |
292 | |
293 bool IsElevatedWithUACMaybeOn() { | |
294 return IsUserAdmin() && IsVistaOrLater() && IsUACMaybeOn(); | |
295 } | |
296 | |
297 HRESULT RunElevated(const TCHAR* file_path, | |
298 const TCHAR* parameters, | |
299 int show_window, | |
300 DWORD* exit_code) { | |
301 UTIL_LOG(L1, (_T("[Running elevated][%s][%s]"), file_path, parameters)); | |
302 | |
303 ASSERT1(vista_util::IsVistaOrLater()); | |
304 ASSERT1(!vista_util::IsUserAdmin()); | |
305 | |
306 SHELLEXECUTEINFO shell_execute_info; | |
307 shell_execute_info.cbSize = sizeof(SHELLEXECUTEINFO); | |
308 shell_execute_info.fMask = SEE_MASK_FLAG_NO_UI | | |
309 SEE_MASK_NOZONECHECKS | | |
310 SEE_MASK_NOASYNC; | |
311 if (exit_code != NULL) { | |
312 shell_execute_info.fMask |= SEE_MASK_NOCLOSEPROCESS; | |
313 } | |
314 shell_execute_info.hProcess = NULL; | |
315 shell_execute_info.hwnd = NULL; | |
316 shell_execute_info.lpVerb = L"runas"; | |
317 shell_execute_info.lpFile = file_path; | |
318 shell_execute_info.lpParameters = parameters; | |
319 shell_execute_info.lpDirectory = NULL; | |
320 shell_execute_info.nShow = show_window; | |
321 shell_execute_info.hInstApp = NULL; | |
322 | |
323 if (!ShellExecuteExEnsureParent(&shell_execute_info)) { | |
324 return AtlHresultFromLastError(); | |
325 } | |
326 | |
327 scoped_process process(shell_execute_info.hProcess); | |
328 | |
329 // Wait for the end of the spawned process, if needed | |
330 if (exit_code) { | |
331 WaitForSingleObject(get(process), INFINITE); | |
332 VERIFY1(GetExitCodeProcess(get(process), exit_code)); | |
333 UTIL_LOG(L1, (_T("[Elevated process exited][PID: %u][exit code: %u]"), | |
334 Process::GetProcessIdFromHandle(get(process)), *exit_code)); | |
335 } else { | |
336 UTIL_LOG(L1, (_T("[Elevated process exited][PID: %u]"), | |
337 Process::GetProcessIdFromHandle(get(process)))); | |
338 } | |
339 | |
340 return S_OK; | |
341 } | |
342 | |
343 | |
344 HRESULT GetProcessIntegrityLevel(DWORD process_id, MANDATORY_LEVEL* level) { | |
345 if (!IsVistaOrLater()) | |
346 return E_NOTIMPL; | |
347 | |
348 if (process_id == 0) | |
349 process_id = ::GetCurrentProcessId(); | |
350 | |
351 HRESULT result = E_FAIL; | |
352 HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id); | |
353 if (process != NULL) { | |
354 HANDLE current_token; | |
355 if (OpenProcessToken(process, | |
356 TOKEN_QUERY | TOKEN_QUERY_SOURCE, | |
357 ¤t_token)) { | |
358 DWORD label_size = 0; | |
359 TOKEN_MANDATORY_LABEL* label; | |
360 GetTokenInformation(current_token, TokenIntegrityLevel, | |
361 NULL, 0, &label_size); | |
362 if (label_size && (label = reinterpret_cast<TOKEN_MANDATORY_LABEL*> | |
363 (LocalAlloc(LPTR, label_size))) != NULL) { | |
364 if (GetTokenInformation(current_token, TokenIntegrityLevel, | |
365 label, label_size, &label_size)) { | |
366 result = GetSidIntegrityLevel(label->Label.Sid, level); | |
367 } | |
368 LocalFree(label); | |
369 } | |
370 CloseHandle(current_token); | |
371 } | |
372 CloseHandle(process); | |
373 } | |
374 return result; | |
375 } | |
376 | |
377 | |
378 HRESULT GetFileOrFolderIntegrityLevel(const TCHAR* file, | |
379 MANDATORY_LEVEL* level, bool* and_children) { | |
380 if (!IsVistaOrLater()) | |
381 return E_NOTIMPL; | |
382 | |
383 PSECURITY_DESCRIPTOR descriptor; | |
384 PACL acl = NULL; | |
385 | |
386 DWORD result = GetNamedSecurityInfo(const_cast<TCHAR*>(file), SE_FILE_OBJECT, | |
387 LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &acl, &descriptor); | |
388 if (result != ERROR_SUCCESS) | |
389 return HRESULT_FROM_WIN32(result); | |
390 | |
391 HRESULT hr = GetAclIntegrityLevel(acl, level, and_children); | |
392 LocalFree(descriptor); | |
393 return hr; | |
394 } | |
395 | |
396 | |
397 HRESULT SetFileOrFolderIntegrityLevel(const TCHAR* file, | |
398 MANDATORY_LEVEL level, bool and_children) { | |
399 if (!IsVistaOrLater()) | |
400 return E_NOTIMPL; | |
401 | |
402 ACL* acl = CreateMandatoryLabelAcl(level, and_children); | |
403 if (!acl) | |
404 return E_FAIL; | |
405 | |
406 DWORD result = SetNamedSecurityInfo(const_cast<TCHAR*>(file), SE_FILE_OBJECT, | |
407 LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, acl); | |
408 LocalFree(acl); | |
409 return HRESULT_FROM_WIN32(result); | |
410 } | |
411 | |
412 | |
413 HRESULT GetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey, | |
414 MANDATORY_LEVEL* level, bool* and_children) { | |
415 if (!IsVistaOrLater()) | |
416 return E_NOTIMPL; | |
417 | |
418 TCHAR* reg_path = AllocFullRegPath(root, subkey); | |
419 if (!reg_path) | |
420 return E_FAIL; | |
421 | |
422 PSECURITY_DESCRIPTOR descriptor; | |
423 PACL acl = NULL; | |
424 | |
425 DWORD result = GetNamedSecurityInfo(reg_path, SE_REGISTRY_KEY, | |
426 LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &acl, &descriptor); | |
427 if (result != ERROR_SUCCESS) { | |
428 LocalFree(reg_path); | |
429 return HRESULT_FROM_WIN32(result); | |
430 } | |
431 | |
432 HRESULT hr = GetAclIntegrityLevel(acl, level, and_children); | |
433 LocalFree(descriptor); | |
434 LocalFree(reg_path); | |
435 return hr; | |
436 } | |
437 | |
438 | |
439 HRESULT SetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey, | |
440 MANDATORY_LEVEL level, bool and_children) { | |
441 if (!IsVistaOrLater()) | |
442 return E_NOTIMPL; | |
443 | |
444 TCHAR* reg_path = AllocFullRegPath(root, subkey); | |
445 if (!reg_path) | |
446 return E_FAIL; | |
447 | |
448 ACL* acl = CreateMandatoryLabelAcl(level, and_children); | |
449 if (!acl) { | |
450 LocalFree(reg_path); | |
451 return E_FAIL; | |
452 } | |
453 | |
454 DWORD result = SetNamedSecurityInfo(reg_path, SE_REGISTRY_KEY, | |
455 LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, acl); | |
456 LocalFree(acl); | |
457 LocalFree(reg_path); | |
458 return HRESULT_FROM_WIN32(result); | |
459 } | |
460 | |
461 | |
462 CSecurityDesc* BuildSecurityDescriptor(const TCHAR* sddl_sacl, | |
463 ACCESS_MASK mask) { | |
464 if (!IsVistaOrLater()) { | |
465 return NULL; | |
466 } | |
467 | |
468 scoped_ptr<CSecurityDesc> security_descriptor(new CSecurityDesc); | |
469 security_descriptor->FromString(sddl_sacl); | |
470 | |
471 // Fill out the rest of the security descriptor from the process token. | |
472 CAccessToken token; | |
473 if (!token.GetProcessToken(TOKEN_QUERY)) { | |
474 return NULL; | |
475 } | |
476 | |
477 // The owner. | |
478 CSid sid_owner; | |
479 if (!token.GetOwner(&sid_owner)) { | |
480 return NULL; | |
481 } | |
482 security_descriptor->SetOwner(sid_owner); | |
483 | |
484 // The group. | |
485 CSid sid_group; | |
486 if (!token.GetPrimaryGroup(&sid_group)) { | |
487 return NULL; | |
488 } | |
489 security_descriptor->SetGroup(sid_group); | |
490 | |
491 // The discretionary access control list. | |
492 CDacl dacl; | |
493 if (!token.GetDefaultDacl(&dacl)) { | |
494 return NULL; | |
495 } | |
496 | |
497 // Add an access control entry mask for the current user. | |
498 // This is what grants this user access from lower integrity levels. | |
499 CSid sid_user; | |
500 if (!token.GetUser(&sid_user)) { | |
501 return NULL; | |
502 } | |
503 | |
504 if (!dacl.AddAllowedAce(sid_user, mask)) { | |
505 return NULL; | |
506 } | |
507 | |
508 // Lastly, save the dacl to this descriptor. | |
509 security_descriptor->SetDacl(dacl); | |
510 return security_descriptor.release(); | |
511 }; | |
512 | |
513 CSecurityDesc* CreateLowIntegritySecurityDesc(ACCESS_MASK mask) { | |
514 return BuildSecurityDescriptor(LOW_INTEGRITY_SDDL_SACL, mask); | |
515 } | |
516 | |
517 CSecurityDesc* CreateMediumIntegritySecurityDesc(ACCESS_MASK mask) { | |
518 return BuildSecurityDescriptor(MEDIUM_INTEGRITY_SDDL_SACL, mask); | |
519 } | |
520 | |
521 HRESULT AddLowIntegritySaclToExistingDesc(CSecurityDesc* sd) { | |
522 ASSERT1(sd); | |
523 ASSERT1(sd->GetPSECURITY_DESCRIPTOR()); | |
524 | |
525 if (!IsVistaOrLater()) { | |
526 return S_FALSE; | |
527 } | |
528 | |
529 CSecurityDesc sd_low; | |
530 if (!sd_low.FromString(LOW_INTEGRITY_SDDL_SACL)) { | |
531 HRESULT hr = HRESULTFromLastError(); | |
532 UTIL_LOG(LE, (_T("[Failed to parse LOW_INTEGRITY_SDDL_SACL][0x%x]"), hr)); | |
533 return hr; | |
534 } | |
535 | |
536 // Atl::CSacl does not support SYSTEM_MANDATORY_LABEL_ACE_TYPE. | |
537 BOOL sacl_present = FALSE; | |
538 BOOL sacl_defaulted = FALSE; | |
539 PACL sacl = NULL; | |
540 if (!::GetSecurityDescriptorSacl( | |
541 const_cast<SECURITY_DESCRIPTOR*>(sd_low.GetPSECURITY_DESCRIPTOR()), | |
542 &sacl_present, | |
543 &sacl, | |
544 &sacl_defaulted) || | |
545 !sacl) { | |
546 HRESULT hr = HRESULTFromLastError(); | |
547 UTIL_LOG(LE, (_T("[Failed to get the low integrity SACL][0x%x]"), hr)); | |
548 return hr; | |
549 } | |
550 | |
551 ACL_SIZE_INFORMATION acl_size = {0}; | |
552 if (!::GetAclInformation(sacl, | |
553 &acl_size, | |
554 sizeof(acl_size), | |
555 AclSizeInformation)) { | |
556 HRESULT hr = HRESULTFromLastError(); | |
557 UTIL_LOG(LE, (_T("[Failed to get AclSizeInformation][0x%x]"), hr)); | |
558 return hr; | |
559 } | |
560 | |
561 // The CSecurityDesc destructor expects the memory to have been malloced. | |
562 PACL new_sacl = static_cast<PACL>(malloc(acl_size.AclBytesInUse)); | |
563 ::CopyMemory(new_sacl, sacl, acl_size.AclBytesInUse); | |
564 | |
565 CSacl sacl_empty; | |
566 sd->SetSacl(sacl_empty); | |
567 | |
568 if (!::SetSecurityDescriptorSacl( | |
569 const_cast<SECURITY_DESCRIPTOR*>(sd->GetPSECURITY_DESCRIPTOR()), | |
570 sacl_present, | |
571 new_sacl, | |
572 sacl_defaulted)) { | |
573 HRESULT hr = HRESULTFromLastError(); | |
574 UTIL_LOG(LE, (_T("[Failed to set the low integrity SACL][0x%x]"), hr)); | |
575 free(new_sacl); | |
576 return hr; | |
577 } | |
578 | |
579 return S_OK; | |
580 } | |
581 | |
582 } // namespace vista_util | |
583 | |
584 } // namespace omaha | |
585 | |
OLD | NEW |