| 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 |