OLD | NEW |
| (Empty) |
1 // Copyright 2004-2009 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/user_rights.h" | |
17 #include <lm.h> | |
18 #include <wtsapi32.h> | |
19 #include "base/scoped_ptr.h" | |
20 #include "omaha/base/debug.h" | |
21 #include "omaha/base/error.h" | |
22 #include "omaha/base/logging.h" | |
23 #include "omaha/base/reg_key.h" | |
24 #include "omaha/base/scope_guard.h" | |
25 #include "omaha/base/scoped_any.h" | |
26 #include "omaha/base/system_info.h" | |
27 #include "omaha/base/vistautil.h" | |
28 | |
29 namespace omaha { | |
30 | |
31 bool UserRights::TokenIsAdmin(HANDLE token) { | |
32 return BelongsToGroup(token, DOMAIN_ALIAS_RID_ADMINS); | |
33 } | |
34 | |
35 bool UserRights::UserIsAdmin() { | |
36 return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_ADMINS); | |
37 } | |
38 | |
39 bool UserRights::UserIsUser() { | |
40 return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_USERS); | |
41 } | |
42 | |
43 bool UserRights::UserIsPowerUser() { | |
44 return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_POWER_USERS); | |
45 } | |
46 | |
47 bool UserRights::UserIsGuest() { | |
48 return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_GUESTS); | |
49 } | |
50 | |
51 bool UserRights::BelongsToGroup(HANDLE token, int group_id) { | |
52 SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; | |
53 PSID group = NULL; | |
54 | |
55 BOOL check = ::AllocateAndInitializeSid(&nt_authority, | |
56 2, | |
57 SECURITY_BUILTIN_DOMAIN_RID, | |
58 group_id, | |
59 0, | |
60 0, | |
61 0, | |
62 0, | |
63 0, | |
64 0, | |
65 &group); | |
66 if (check) { | |
67 if (!::CheckTokenMembership(token, group, &check)) { | |
68 check = false; | |
69 } | |
70 ::FreeSid(group); | |
71 } | |
72 return !!check; | |
73 } | |
74 | |
75 bool UserRights::UserIsRestricted() { | |
76 scoped_handle token; | |
77 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, address(token))) { | |
78 UTIL_LOG(LE, (_T("[UserRights::UserIsRestricted - OpenProcessToken failed]") | |
79 _T("[0x%08x]"), HRESULTFromLastError())); | |
80 return true; | |
81 } | |
82 | |
83 return !!::IsTokenRestricted(get(token)); | |
84 } | |
85 | |
86 bool UserRights::UserIsLowOrUntrustedIntegrity() { | |
87 if (SystemInfo::IsRunningOnVistaOrLater()) { | |
88 MANDATORY_LEVEL integrity_level = MandatoryLevelUntrusted; | |
89 if (FAILED(vista_util::GetProcessIntegrityLevel(0, &integrity_level)) || | |
90 integrity_level == MandatoryLevelUntrusted || | |
91 integrity_level == MandatoryLevelLow) { | |
92 return true; | |
93 } | |
94 } | |
95 | |
96 return false; | |
97 } | |
98 | |
99 HRESULT UserRights::UserIsLoggedOnInteractively(bool* is_logged_on) { | |
100 ASSERT1(is_logged_on); | |
101 | |
102 *is_logged_on = false; | |
103 | |
104 HRESULT hr = S_OK; | |
105 | |
106 // Get the user associated with the current process. | |
107 WKSTA_USER_INFO_1* user_info = NULL; | |
108 NET_API_STATUS status = ::NetWkstaUserGetInfo( | |
109 NULL, | |
110 1, | |
111 reinterpret_cast<uint8**>(&user_info)); | |
112 if (status != NERR_Success || user_info == NULL) { | |
113 UTIL_LOG(LE, (_T("[NetWkstaUserGetInfo failed][%u]"), status)); | |
114 return HRESULT_FROM_WIN32(status); | |
115 } | |
116 ON_SCOPE_EXIT(::NetApiBufferFree, user_info); | |
117 | |
118 UTIL_LOG(L2, (_T("[wks domain=%s][wks user=%s]"), | |
119 user_info->wkui1_logon_domain, user_info->wkui1_username)); | |
120 | |
121 PWTS_SESSION_INFOW session_info = NULL; | |
122 const DWORD kVersion = 1; | |
123 DWORD num_sessions = 0; | |
124 if (!::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, | |
125 0, | |
126 kVersion, | |
127 &session_info, | |
128 &num_sessions)) { | |
129 hr = HRESULTFromLastError(); | |
130 UTIL_LOG(LE, (_T("[WTSEnumerateSessions failed][0x%08x]"), hr)); | |
131 return hr; | |
132 } | |
133 ON_SCOPE_EXIT(::WTSFreeMemory, session_info); | |
134 | |
135 // Loop through all active sessions to see whether one of the sessions | |
136 // belongs to current user. If so, regard this user as "logged-on". | |
137 for (DWORD i = 0; i < num_sessions; ++i) { | |
138 TCHAR* domain_name = NULL; | |
139 DWORD domain_name_len = 0; | |
140 if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, | |
141 session_info[i].SessionId, | |
142 WTSDomainName, | |
143 &domain_name, | |
144 &domain_name_len)) { | |
145 hr = HRESULTFromLastError(); | |
146 UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%08x]"), hr)); | |
147 continue; | |
148 } | |
149 ON_SCOPE_EXIT(::WTSFreeMemory, domain_name); | |
150 | |
151 TCHAR* user_name = NULL; | |
152 DWORD user_name_len = 0; | |
153 if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, | |
154 session_info[i].SessionId, | |
155 WTSUserName, | |
156 &user_name, | |
157 &user_name_len)) { | |
158 hr = HRESULTFromLastError(); | |
159 UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%08x]"), hr)); | |
160 continue; | |
161 } | |
162 ON_SCOPE_EXIT(::WTSFreeMemory, user_name); | |
163 | |
164 UTIL_LOG(L2, (_T("[ts domain=%s][ts user=%s][station=%s]"), | |
165 domain_name, | |
166 user_name, | |
167 session_info[i].pWinStationName)); | |
168 | |
169 // Occasionally, the domain name and user name could not be retrieved when | |
170 // the program is started just at logon time. | |
171 if (!(domain_name && *domain_name && user_name && *user_name)) { | |
172 hr = E_FAIL; | |
173 continue; | |
174 } | |
175 | |
176 if (_tcsicmp(user_info->wkui1_logon_domain, domain_name) == 0 && | |
177 _tcsicmp(user_info->wkui1_username, user_name) == 0) { | |
178 *is_logged_on = true; | |
179 return S_OK; | |
180 } | |
181 } | |
182 | |
183 return hr; | |
184 } | |
185 | |
186 // Returns a token with TOKEN_ALL_ACCESS rights. At the moment, we only require | |
187 // TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, but requirements may change in the | |
188 // future. | |
189 HRESULT UserRights::GetCallerToken(CAccessToken* token) { | |
190 ASSERT1(token); | |
191 | |
192 CComPtr<IUnknown> security_context; | |
193 HRESULT hr = ::CoGetCallContext(IID_PPV_ARGS(&security_context)); | |
194 if (SUCCEEDED(hr)) { | |
195 return token->OpenCOMClientToken(TOKEN_ALL_ACCESS) ? S_OK : | |
196 HRESULTFromLastError(); | |
197 } else if (hr != RPC_E_CALL_COMPLETE) { | |
198 UTIL_LOG(LE, (_T("[::CoGetCallContext failed][0x%x]"), hr)); | |
199 return hr; | |
200 } | |
201 | |
202 // RPC_E_CALL_COMPLETE indicates an in-proc intra-apartment call. Return the | |
203 // current process token. | |
204 return token->OpenThreadToken(TOKEN_ALL_ACCESS) ? S_OK : | |
205 HRESULTFromLastError(); | |
206 } | |
207 | |
208 bool UserRights::VerifyCallerIsAdmin() { | |
209 CAccessToken impersonated_token; | |
210 if (FAILED(GetCallerToken(&impersonated_token))) { | |
211 return false; | |
212 } | |
213 return TokenIsAdmin(impersonated_token.GetHandle()); | |
214 } | |
215 | |
216 bool UserRights::VerifyCallerIsSystem() { | |
217 CAccessToken impersonated_token; | |
218 if (FAILED(GetCallerToken(&impersonated_token))) { | |
219 return false; | |
220 } | |
221 | |
222 CSid sid; | |
223 if (!impersonated_token.GetUser(&sid)) { | |
224 return false; | |
225 } | |
226 | |
227 return sid == Sids::System(); | |
228 } | |
229 | |
230 } // namespace omaha | |
231 | |
OLD | NEW |