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 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) 37 return E_FAIL; 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 if (!token_user_bytes.get()) 53 return E_OUTOFMEMORY; 54 55 if (!::GetTokenInformation(token, TokenUser, token_user_bytes.get(), 56 token_user_size, &token_user_size2)) { 57 return E_FAIL; 58 } 59 60 WCHAR user_name[UNLEN + 1]; // max username length 61 WCHAR domain_name[UNLEN + 1]; 62 DWORD user_name_size = UNLEN + 1; 63 DWORD domain_name_size = UNLEN + 1; 64 SID_NAME_USE sid_type; 65 TOKEN_USER* token_user = 66 reinterpret_cast<TOKEN_USER*>(token_user_bytes.get()); 67 if (!token_user) 68 return E_FAIL; 69 PSID user_sid = token_user->User.Sid; 70 if (!::LookupAccountSidW(NULL, user_sid, user_name, &user_name_size, 71 domain_name, &domain_name_size, &sid_type)) { 72 return E_FAIL; 73 } 74 75 if (name != NULL) { 76 *name = user_name; 77 } 78 if (domain != NULL) { 79 *domain = domain_name; 80 } 81 if (sid != NULL) { 82 LPWSTR string_sid; 83 ConvertSidToStringSidW(user_sid, &string_sid); 84 *sid = string_sid; // copy out to cstring 85 // free memory, as documented for ConvertSidToStringSid 86 LocalFree(string_sid); 87 } 88 89 return S_OK; 90 } 91 92 HRESULT GetElevationType(PTOKEN_ELEVATION_TYPE elevation) { 93 if (!elevation) 94 return E_POINTER; 95 96 *elevation = TokenElevationTypeDefault; 97 98 if (base::win::GetVersion() < base::win::VERSION_VISTA) 99 return E_FAIL; 100 101 HANDLE process_token; 102 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) 103 return HRESULT_FROM_WIN32(GetLastError()); 104 105 base::win::ScopedHandle scoped_process_token(process_token); 106 107 DWORD size; 108 TOKEN_ELEVATION_TYPE elevation_type; 109 if (!GetTokenInformation(process_token, TokenElevationType, &elevation_type, 110 sizeof(elevation_type), &size)) { 111 return HRESULT_FROM_WIN32(GetLastError()); 112 } 113 114 *elevation = elevation_type; 115 return S_OK; 116 } 117 118 // based on http://msdn2.microsoft.com/en-us/library/aa376389.aspx 119 bool GetUserGroup(long* group) { 120 if (!group) 121 return false; 122 123 *group = 0; 124 125 // groups are listed in DECREASING order of importance 126 // (eg. If a user is a member of both the admin group and 127 // the power user group, it is more useful to list the user 128 // as an admin) 129 DWORD user_groups[] = {DOMAIN_ALIAS_RID_ADMINS, 130 DOMAIN_ALIAS_RID_POWER_USERS}; 131 SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; 132 133 for (int i = 0; i < arraysize(user_groups) && *group == 0; ++i) { 134 PSID current_group; 135 if (AllocateAndInitializeSid(&nt_authority, 2, 136 SECURITY_BUILTIN_DOMAIN_RID, 137 user_groups[i], 0, 0, 0, 0, 138 0, 0, ¤t_group)) { 139 BOOL current_level; 140 if (CheckTokenMembership(NULL, current_group, ¤t_level) && 141 current_level) { 142 *group = user_groups[i]; 143 } 144 145 FreeSid(current_group); 146 } 147 } 148 149 return group != 0; 150 } 151 } //anonymous 152 153 154 namespace rlz_lib { 155 156 bool ProcessInfo::IsRunningAsSystem() { 157 static std::wstring name; 158 static std::wstring domain; 159 static std::wstring sid; 160 if (name.empty()) 161 CHECK(SUCCEEDED(GetCurrentUser(&name, &domain, &sid))); 162 163 return (name == L"SYSTEM"); 164 } 165 166 bool ProcessInfo::HasAdminRights() { 167 static bool evaluated = false; 168 static bool has_rights = false; 169 170 if (!evaluated) { 171 if (IsRunningAsSystem()) { 172 has_rights = true; 173 } else if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 174 TOKEN_ELEVATION_TYPE elevation; 175 base::IntegrityLevel level; 176 177 if (SUCCEEDED(GetElevationType(&elevation)) && 178 base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), &level)) 179 has_rights = (elevation == TokenElevationTypeFull) || 180 (level == HIGH_INTEGRITY); 181 } else { 182 long group = 0; 183 if (GetUserGroup(&group)) 184 has_rights = (group == DOMAIN_ALIAS_RID_ADMINS); 185 } 186 } 187 188 evaluated = true; 189 if (!has_rights) 190 ASSERT_STRING("ProcessInfo::HasAdminRights: Does not have admin rights."); 191 192 return has_rights; 193 } 194 195 }; // namespace 196