1 // Copyright (c) 2012 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 // Information about the current process. 6 7 #include "rlz/win/lib/process_info.h" 8 9 #include <windows.h> 10 #include <Sddl.h> // For ConvertSidToStringSid. 11 #include <LMCons.h> // For UNLEN 12 13 #include "base/logging.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/process/process_handle.h" 16 #include "base/win/scoped_handle.h" 17 #include "base/win/windows_version.h" 18 #include "rlz/lib/assert.h" 19 20 namespace { 21 22 HRESULT GetCurrentUser(std::wstring* name, 23 std::wstring* domain, 24 std::wstring* sid) { 25 DWORD err; 26 27 // Get the current username & domain the hard way. (GetUserNameEx would be 28 // nice, but unfortunately requires connectivity to a domain controller. 29 // Useless.) 30 31 // (Following call doesn't work if running as a Service - because a Service 32 // runs under special accounts like LOCAL_SYSTEM, not as the logged in user. 33 // In which case, search for and use the process handle of a running 34 // Explorer.exe.) 35 HANDLE token; 36 37 CHECK(::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)); 38 39 base::win::ScopedHandle scoped_process_token(token); 40 41 // (Following call will fail with ERROR_INSUFFICIENT_BUFFER and give us the 42 // required size.) 43 scoped_ptr<char[]> token_user_bytes; 44 DWORD token_user_size; 45 DWORD token_user_size2; 46 BOOL result = ::GetTokenInformation(token, TokenUser, NULL, 0, 47 &token_user_size); 48 err = ::GetLastError(); 49 CHECK(!result && err == ERROR_INSUFFICIENT_BUFFER); 50 51 token_user_bytes.reset(new char[token_user_size]); 52 CHECK(token_user_bytes.get()); 53 54 CHECK(::GetTokenInformation(token, TokenUser, token_user_bytes.get(), 55 token_user_size, &token_user_size2)); 56 57 WCHAR user_name[UNLEN + 1]; // max username length 58 WCHAR domain_name[UNLEN + 1]; 59 DWORD user_name_size = UNLEN + 1; 60 DWORD domain_name_size = UNLEN + 1; 61 SID_NAME_USE sid_type; 62 TOKEN_USER* token_user = 63 reinterpret_cast<TOKEN_USER*>(token_user_bytes.get()); 64 CHECK(token_user); 65 66 PSID user_sid = token_user->User.Sid; 67 CHECK(::LookupAccountSidW(NULL, user_sid, user_name, &user_name_size, 68 domain_name, &domain_name_size, &sid_type)); 69 70 if (name != NULL) { 71 *name = user_name; 72 } 73 if (domain != NULL) { 74 *domain = domain_name; 75 } 76 if (sid != NULL) { 77 LPWSTR string_sid; 78 ConvertSidToStringSidW(user_sid, &string_sid); 79 *sid = string_sid; // copy out to cstring 80 // free memory, as documented for ConvertSidToStringSid 81 LocalFree(string_sid); 82 } 83 84 return S_OK; 85 } 86 87 HRESULT GetElevationType(PTOKEN_ELEVATION_TYPE elevation) { 88 if (!elevation) 89 return E_POINTER; 90 91 *elevation = TokenElevationTypeDefault; 92 93 if (base::win::GetVersion() < base::win::VERSION_VISTA) 94 return E_FAIL; 95 96 HANDLE process_token; 97 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) 98 return HRESULT_FROM_WIN32(GetLastError()); 99 100 base::win::ScopedHandle scoped_process_token(process_token); 101 102 DWORD size; 103 TOKEN_ELEVATION_TYPE elevation_type; 104 if (!GetTokenInformation(process_token, TokenElevationType, &elevation_type, 105 sizeof(elevation_type), &size)) { 106 return HRESULT_FROM_WIN32(GetLastError()); 107 } 108 109 *elevation = elevation_type; 110 return S_OK; 111 } 112 113 // based on http://msdn2.microsoft.com/en-us/library/aa376389.aspx 114 bool GetUserGroup(long* group) { 115 if (!group) 116 return false; 117 118 *group = 0; 119 120 // groups are listed in DECREASING order of importance 121 // (eg. If a user is a member of both the admin group and 122 // the power user group, it is more useful to list the user 123 // as an admin) 124 DWORD user_groups[] = {DOMAIN_ALIAS_RID_ADMINS, 125 DOMAIN_ALIAS_RID_POWER_USERS}; 126 SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; 127 128 for (int i = 0; i < arraysize(user_groups) && *group == 0; ++i) { 129 PSID current_group; 130 if (AllocateAndInitializeSid(&nt_authority, 2, 131 SECURITY_BUILTIN_DOMAIN_RID, 132 user_groups[i], 0, 0, 0, 0, 133 0, 0, ¤t_group)) { 134 BOOL current_level; 135 if (CheckTokenMembership(NULL, current_group, ¤t_level) && 136 current_level) { 137 *group = user_groups[i]; 138 } 139 140 FreeSid(current_group); 141 } 142 } 143 144 return group != 0; 145 } 146 } //anonymous 147 148 149 namespace rlz_lib { 150 151 bool ProcessInfo::IsRunningAsSystem() { 152 static std::wstring name; 153 static std::wstring domain; 154 static std::wstring sid; 155 if (name.empty()) 156 CHECK(SUCCEEDED(GetCurrentUser(&name, &domain, &sid))); 157 158 return (name == L"SYSTEM"); 159 } 160 161 bool ProcessInfo::HasAdminRights() { 162 static bool evaluated = false; 163 static bool has_rights = false; 164 165 if (!evaluated) { 166 if (IsRunningAsSystem()) { 167 has_rights = true; 168 } else if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 169 TOKEN_ELEVATION_TYPE elevation; 170 base::IntegrityLevel level; 171 172 if (SUCCEEDED(GetElevationType(&elevation)) && 173 base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), &level)) 174 has_rights = (elevation == TokenElevationTypeFull) || 175 (level == HIGH_INTEGRITY); 176 } else { 177 long group = 0; 178 if (GetUserGroup(&group)) 179 has_rights = (group == DOMAIN_ALIAS_RID_ADMINS); 180 } 181 } 182 183 evaluated = true; 184 if (!has_rights) 185 ASSERT_STRING("ProcessInfo::HasAdminRights: Does not have admin rights."); 186 187 return has_rights; 188 } 189 190 }; // namespace 191