| 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 |