diff options
Diffstat (limited to 'rlz/win/lib/process_info.cc')
-rw-r--r-- | rlz/win/lib/process_info.cc | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/rlz/win/lib/process_info.cc b/rlz/win/lib/process_info.cc new file mode 100644 index 0000000..8d4a02f --- /dev/null +++ b/rlz/win/lib/process_info.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Information about the current process. + +#include "rlz/win/lib/process_info.h" + +#include <windows.h> +#include <Sddl.h> // For ConvertSidToStringSid. +#include <LMCons.h> // For UNLEN + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/process_util.h" +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" +#include "rlz/lib/assert.h" +#include "rlz/win/lib/vista_winnt.h" + +namespace { + +HRESULT GetCurrentUser(std::wstring* name, + std::wstring* domain, + std::wstring* sid) { + DWORD err; + + // Get the current username & domain the hard way. (GetUserNameEx would be + // nice, but unfortunately requires connectivity to a domain controller. + // Useless.) + + // (Following call doesn't work if running as a Service - because a Service + // runs under special accounts like LOCAL_SYSTEM, not as the logged in user. + // In which case, search for and use the process handle of a running + // Explorer.exe.) + HANDLE token; + if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) + return E_FAIL; + + base::win::ScopedHandle scoped_process_token(token); + + // (Following call will fail with ERROR_INSUFFICIENT_BUFFER and give us the + // required size.) + scoped_array<char> token_user_bytes; + DWORD token_user_size; + DWORD token_user_size2; + BOOL result = ::GetTokenInformation(token, TokenUser, NULL, 0, + &token_user_size); + err = ::GetLastError(); + CHECK(!result && err == ERROR_INSUFFICIENT_BUFFER); + + token_user_bytes.reset(new char[token_user_size]); + if (!token_user_bytes.get()) + return E_OUTOFMEMORY; + + if (!::GetTokenInformation(token, TokenUser, token_user_bytes.get(), + token_user_size, &token_user_size2)) { + return E_FAIL; + } + + WCHAR user_name[UNLEN + 1]; // max username length + WCHAR domain_name[UNLEN + 1]; + DWORD user_name_size = UNLEN + 1; + DWORD domain_name_size = UNLEN + 1; + SID_NAME_USE sid_type; + TOKEN_USER* token_user = + reinterpret_cast<TOKEN_USER*>(token_user_bytes.get()); + if (!token_user) + return E_FAIL; + PSID user_sid = token_user->User.Sid; + if (!::LookupAccountSidW(NULL, user_sid, user_name, &user_name_size, + domain_name, &domain_name_size, &sid_type)) { + return E_FAIL; + } + + if (name != NULL) { + *name = user_name; + } + if (domain != NULL) { + *domain = domain_name; + } + if (sid != NULL) { + LPWSTR string_sid; + ConvertSidToStringSidW(user_sid, &string_sid); + *sid = string_sid; // copy out to cstring + // free memory, as documented for ConvertSidToStringSid + LocalFree(string_sid); + } + + return S_OK; +} + +HRESULT GetElevationType(PTOKEN_ELEVATION_TYPE elevation) { + if (!elevation) + return E_POINTER; + + *elevation = TokenElevationTypeDefault; + + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return E_FAIL; + + HANDLE process_token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) + return HRESULT_FROM_WIN32(GetLastError()); + + base::win::ScopedHandle scoped_process_token(process_token); + + DWORD size; + TOKEN_ELEVATION_TYPE elevation_type; + if (!GetTokenInformation(process_token, TokenElevationType, &elevation_type, + sizeof(elevation_type), &size)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + *elevation = elevation_type; + return S_OK; +} + +// based on http://msdn2.microsoft.com/en-us/library/aa376389.aspx +bool GetUserGroup(long* group) { + if (!group) + return false; + + *group = 0; + + // groups are listed in DECREASING order of importance + // (eg. If a user is a member of both the admin group and + // the power user group, it is more useful to list the user + // as an admin) + DWORD user_groups[] = {DOMAIN_ALIAS_RID_ADMINS, + DOMAIN_ALIAS_RID_POWER_USERS}; + SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; + + for (int i = 0; i < arraysize(user_groups) && *group == 0; ++i) { + PSID current_group; + if (AllocateAndInitializeSid(&nt_authority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + user_groups[i], 0, 0, 0, 0, + 0, 0, ¤t_group)) { + BOOL current_level; + if (CheckTokenMembership(NULL, current_group, ¤t_level) && + current_level) { + *group = user_groups[i]; + } + + FreeSid(current_group); + } + } + + return group != 0; +} +} //anonymous + + +namespace rlz_lib { + +bool ProcessInfo::IsRunningAsSystem() { + static std::wstring name; + static std::wstring domain; + static std::wstring sid; + if (name.empty()) + CHECK(SUCCEEDED(GetCurrentUser(&name, &domain, &sid))); + + return (name == L"SYSTEM"); +} + +bool ProcessInfo::HasAdminRights() { + static bool evaluated = false; + static bool has_rights = false; + + if (!evaluated) { + if (IsRunningAsSystem()) { + has_rights = true; + } else if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + TOKEN_ELEVATION_TYPE elevation; + base::IntegrityLevel level; + + if (SUCCEEDED(GetElevationType(&elevation)) && + base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), &level)) + has_rights = (elevation == TokenElevationTypeFull) || + (level == HIGH_INTEGRITY); + } else { + long group = 0; + if (GetUserGroup(&group)) + has_rights = (group == DOMAIN_ALIAS_RID_ADMINS); + } + } + + evaluated = true; + if (!has_rights) + ASSERT_STRING("ProcessInfo::HasAdminRights: Does not have admin rights."); + + return has_rights; +} + +}; // namespace |