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