Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Side by Side Diff: base/vistautil.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/vistautil.h ('k') | base/vistautil_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 &current_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
OLDNEW
« no previous file with comments | « base/vistautil.h ('k') | base/vistautil_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698