VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp@ 20484

Last change on this file since 20484 was 19374, checked in by vboxsync, 16 years ago

VBoxService/common: SVN props.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/* $Id: VBoxServiceVMInfo-win.cpp 19374 2009-05-05 13:23:32Z vboxsync $ */
2/** @file
3 * VBoxVMInfo-win - Virtual machine (guest) information for the host.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <windows.h>
28#include <Ntsecapi.h>
29#include <wtsapi32.h> /* For WTS* calls. */
30#include <psapi.h> /* EnumProcesses. */
31
32#include <iprt/assert.h>
33#include <iprt/mem.h>
34#include <iprt/thread.h>
35#include <iprt/string.h>
36#include <iprt/semaphore.h>
37#include <iprt/system.h>
38#include <iprt/time.h>
39#include <VBox/VBoxGuest.h>
40#include "VBoxServiceInternal.h"
41#include "VBoxServiceUtils.h"
42
43
44/*******************************************************************************
45* Global Variables *
46*******************************************************************************/
47/** Function prototypes for dynamic loading. */
48extern fnWTSGetActiveConsoleSessionId g_pfnWTSGetActiveConsoleSessionId;
49/** The vminfo interval (millseconds). */
50uint32_t g_VMInfoLoggedInUsersCount = 0;
51
52
53/* Function GetLUIDsFromProcesses() written by Stefan Kuhr. */
54DWORD VboxServiceVMInfoWinGetLUIDsFromProcesses(PLUID *ppLuid)
55{
56 DWORD dwSize, dwSize2, dwIndex ;
57 LPDWORD lpdwPIDs ;
58 DWORD dwLastError = ERROR_SUCCESS;
59
60 if (!ppLuid)
61 {
62 SetLastError(ERROR_INVALID_PARAMETER);
63 return 0L;
64 }
65
66 /* Call the PSAPI function EnumProcesses to get all of the
67 ProcID's currently in the system.
68 NOTE: In the documentation, the third parameter of
69 EnumProcesses is named cbNeeded, which implies that you
70 can call the function once to find out how much space to
71 allocate for a buffer and again to fill the buffer.
72 This is not the case. The cbNeeded parameter returns
73 the number of PIDs returned, so if your buffer size is
74 zero cbNeeded returns zero.
75 NOTE: The "HeapAlloc" loop here ensures that we
76 actually allocate a buffer large enough for all the
77 PIDs in the system. */
78 dwSize2 = 256 * sizeof(DWORD);
79
80 lpdwPIDs = NULL;
81 do
82 {
83 if (lpdwPIDs)
84 {
85 HeapFree(GetProcessHeap(), 0, lpdwPIDs) ;
86 dwSize2 *= 2;
87 }
88 lpdwPIDs = (unsigned long *)HeapAlloc(GetProcessHeap(), 0, dwSize2);
89 if (lpdwPIDs == NULL)
90 return 0L; // Last error will be that of HeapAlloc
91
92 if (!EnumProcesses( lpdwPIDs, dwSize2, &dwSize))
93 {
94 DWORD dw = GetLastError();
95 HeapFree(GetProcessHeap(), 0, lpdwPIDs);
96 SetLastError(dw);
97 return 0L;
98 }
99 }
100 while (dwSize == dwSize2);
101
102 /* At this point we have an array of the PIDs at the
103 time of the last EnumProcesses invocation. We will
104 allocate an array of LUIDs passed back via the out
105 param ppLuid of exactly the number of PIDs. We will
106 only fill the first n values of this array, with n
107 being the number of unique LUIDs found in these PIDs. */
108
109 /* How many ProcIDs did we get? */
110 dwSize /= sizeof(DWORD);
111 dwSize2 = 0L; /* Our return value of found luids. */
112
113 *ppLuid = (LUID *)LocalAlloc(LPTR, dwSize*sizeof(LUID));
114 if (!(*ppLuid))
115 {
116 dwLastError = GetLastError();
117 goto CLEANUP;
118 }
119 for (dwIndex = 0; dwIndex < dwSize; dwIndex++)
120 {
121 (*ppLuid)[dwIndex].LowPart =0L;
122 (*ppLuid)[dwIndex].HighPart=0;
123
124 /* Open the process (if we can... security does not
125 permit every process in the system). */
126 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE, lpdwPIDs[dwIndex]);
127 if ( hProcess != NULL )
128 {
129 HANDLE hAccessToken;
130 if (OpenProcessToken(hProcess, TOKEN_QUERY, &hAccessToken))
131 {
132 TOKEN_STATISTICS ts;
133 DWORD dwSize;
134 if (GetTokenInformation(hAccessToken, TokenStatistics, &ts, sizeof ts, &dwSize))
135 {
136 DWORD dwTmp = 0L;
137 BOOL bFound = FALSE;
138 for (;dwTmp<dwSize2 && !bFound;dwTmp++)
139 bFound = (*ppLuid)[dwTmp].HighPart == ts.AuthenticationId.HighPart &&
140 (*ppLuid)[dwTmp].LowPart == ts.AuthenticationId.LowPart;
141
142 if (!bFound)
143 (*ppLuid)[dwSize2++] = ts.AuthenticationId;
144 }
145 CloseHandle(hAccessToken);
146 }
147
148 CloseHandle(hProcess);
149 }
150
151 /* We don't really care if OpenProcess or OpenProcessToken fail or succeed, because
152 there are quite a number of system processes we cannot open anyway, not even as SYSTEM. */
153 }
154
155 CLEANUP:
156
157 if (lpdwPIDs)
158 HeapFree(GetProcessHeap(), 0, lpdwPIDs);
159
160 if (ERROR_SUCCESS !=dwLastError)
161 SetLastError(dwLastError);
162
163 return dwSize2;
164}
165
166BOOL VboxServiceVMInfoWinIsLoggedIn(VBOXSERVICEVMINFOUSER* a_pUserInfo,
167 PLUID a_pSession,
168 PLUID a_pLuid,
169 DWORD a_dwNumOfProcLUIDs)
170{
171 BOOL bLoggedIn = FALSE;
172 BOOL bFoundUser = FALSE;
173 PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
174 NTSTATUS r = 0;
175 WCHAR *usBuffer = NULL;
176 int iLength = 0;
177
178 if (!a_pSession)
179 return FALSE;
180
181 r = LsaGetLogonSessionData (a_pSession, &sessionData);
182 if (r != STATUS_SUCCESS)
183 {
184 VBoxServiceError("LsaGetLogonSessionData failed %lu\n", LsaNtStatusToWinError(r));
185
186 if (sessionData)
187 LsaFreeReturnBuffer(sessionData);
188
189 return FALSE;
190 }
191
192 if (!sessionData)
193 {
194 VBoxServiceError("Invalid logon session data.\n");
195 return FALSE;
196 }
197
198 VBoxServiceVerbose(3, "vboxVMInfoThread: Users: Session data: Name = %ls, Len = %d, SID = %s, LogonID = %d,%d\n",
199 (sessionData->UserName).Buffer, (sessionData->UserName).Length, (sessionData->Sid != NULL) ? "1" : "0", sessionData->LogonId.HighPart, sessionData->LogonId.LowPart);
200
201 if ((sessionData->UserName.Buffer != NULL) &&
202 (sessionData->Sid != NULL) &&
203 (sessionData->LogonId.LowPart != 0))
204 {
205 /* Get the user name. */
206 usBuffer = (sessionData->UserName).Buffer;
207 iLength = (sessionData->UserName).Length;
208 if (iLength > sizeof(a_pUserInfo->szUser) - sizeof(TCHAR)) /* -sizeof(TCHAR) because we have to add the terminating null char at the end later. */
209 {
210 VBoxServiceVerbose(0, "User name too long (%d bytes) for buffer! Name will be truncated.\n", iLength);
211 iLength = sizeof(a_pUserInfo->szUser) - sizeof(TCHAR);
212 }
213 wcsncpy (a_pUserInfo->szUser, usBuffer, iLength);
214 wcscat (a_pUserInfo->szUser, L""); /* Add terminating null char. */
215
216 /* Get authentication package. */
217 usBuffer = (sessionData->AuthenticationPackage).Buffer;
218 iLength = (sessionData->AuthenticationPackage).Length;
219 if (iLength > sizeof(a_pUserInfo->szAuthenticationPackage) - sizeof(TCHAR)) /* -sizeof(TCHAR) because we have to add the terminating null char at the end later. */
220 {
221 VBoxServiceVerbose(0, "Authentication pkg name too long (%d bytes) for buffer! Name will be truncated.\n", iLength);
222 iLength = sizeof(a_pUserInfo->szAuthenticationPackage) - sizeof(TCHAR);
223 }
224 wcsncpy (a_pUserInfo->szAuthenticationPackage, usBuffer, iLength);
225 wcscat (a_pUserInfo->szAuthenticationPackage, L""); /* Add terminating null char. */
226
227 /* Get logon domain. */
228 usBuffer = (sessionData->LogonDomain).Buffer;
229 iLength = (sessionData->LogonDomain).Length;
230 if (iLength > sizeof(a_pUserInfo->szLogonDomain) - sizeof(TCHAR)) /* -sizeof(TCHAR) because we have to add the terminating null char at the end later. */
231 {
232 VBoxServiceVerbose(0, "Logon domain name too long (%d bytes) for buffer! Name will be truncated.\n", iLength);
233 iLength = sizeof(a_pUserInfo->szLogonDomain) - sizeof(TCHAR);
234 }
235 wcsncpy (a_pUserInfo->szLogonDomain, usBuffer, iLength);
236 wcscat (a_pUserInfo->szLogonDomain, L""); /* Add terminating null char. */
237
238 /* Only handle users which can login interactively or logged in remotely over native RDP. */
239 if ( (((SECURITY_LOGON_TYPE)sessionData->LogonType == Interactive)
240 || ((SECURITY_LOGON_TYPE)sessionData->LogonType == RemoteInteractive))
241 && (sessionData->Sid != NULL))
242 {
243 TCHAR szOwnerName [_MAX_PATH] = { 0 };
244 DWORD dwOwnerNameSize = _MAX_PATH;
245
246 TCHAR szDomainName [_MAX_PATH] = { 0 };
247 DWORD dwDomainNameSize = _MAX_PATH;
248
249 SID_NAME_USE ownerType;
250
251 if (LookupAccountSid(NULL,
252 sessionData->Sid,
253 szOwnerName,
254 &dwOwnerNameSize,
255 szDomainName,
256 &dwDomainNameSize,
257 &ownerType))
258 {
259 VBoxServiceVerbose(3, "Account User=%ls, Session=%ld, LUID=%ld,%ld, AuthPkg=%ls, Domain=%ls\n",
260 a_pUserInfo->szUser, sessionData->Session, sessionData->LogonId.HighPart, sessionData->LogonId.LowPart, a_pUserInfo->szAuthenticationPackage, a_pUserInfo->szLogonDomain);
261
262 /* The session ID increments/decrements on Vista often! So don't compare
263 the session data SID with the current SID here. */
264 DWORD dwActiveSession = 0;
265 if (g_pfnWTSGetActiveConsoleSessionId != NULL) /* Check terminal session ID. */
266 dwActiveSession = g_pfnWTSGetActiveConsoleSessionId();
267
268 /*VBoxServiceVerbose(3, ("vboxVMInfoThread: Users: Current active session ID: %ld\n", dwActiveSession));*/
269
270 if (SidTypeUser == ownerType)
271 {
272 LPWSTR pBuffer = NULL;
273 DWORD dwBytesRet = 0;
274 int iState = 0;
275
276 if (WTSQuerySessionInformation( /* Detect RDP sessions as well. */
277 WTS_CURRENT_SERVER_HANDLE,
278 WTS_CURRENT_SESSION,
279 WTSConnectState,
280 &pBuffer,
281 &dwBytesRet))
282 {
283 /*VBoxServiceVerbose(3, ("vboxVMInfoThread: Users: WTSQuerySessionInformation returned %ld bytes, p=%p, state=%d\n", dwBytesRet, pBuffer, pBuffer != NULL ? (INT)*pBuffer : -1));*/
284 if(dwBytesRet)
285 iState = *pBuffer;
286
287 if ( (iState == WTSActive) /* User logged on to WinStation. */
288 || (iState == WTSShadow) /* Shadowing another WinStation. */
289 || (iState == WTSDisconnected)) /* WinStation logged on without client. */
290 {
291 /** @todo On Vista and W2K, always "old" user name are still
292 * there. Filter out the old one! */
293 VBoxServiceVerbose(3, "vboxVMInfoThread: Users: Account User=%ls is logged in via TCS/RDP. State=%d\n", a_pUserInfo->szUser, iState);
294 bFoundUser = TRUE;
295 }
296 }
297 else
298 {
299 /* Terminal services don't run (for example in W2K, nothing to worry about ...). */
300 /* ... or is on Vista fast user switching page! */
301 bFoundUser = TRUE;
302 }
303
304 if (pBuffer)
305 WTSFreeMemory(pBuffer);
306
307 /* A user logged in, but it could be a stale/orphaned logon session. */
308 BOOL bFoundInLUIDs = FALSE;
309 for (DWORD dwIndex = 0; dwIndex < a_dwNumOfProcLUIDs; dwIndex++)
310 {
311 if ( (a_pLuid[dwIndex].HighPart == sessionData->LogonId.HighPart)
312 && (a_pLuid[dwIndex].LowPart == sessionData->LogonId.LowPart))
313 {
314 bLoggedIn = TRUE;
315 VBoxServiceVerbose(3, "User \"%ls\" is logged in!\n", a_pUserInfo->szUser);
316 break;
317 }
318 }
319 }
320 }
321 }
322 }
323
324 LsaFreeReturnBuffer(sessionData);
325 return bLoggedIn;
326}
327
328int VboxServiceWinGetAddsVersion(uint32_t uiClientID)
329{
330 char szInstDir[_MAX_PATH] = {0};
331 char szRev[_MAX_PATH] = {0};
332 char szVer[_MAX_PATH] = {0};
333
334 HKEY hKey = NULL;
335 int rc = 0;
336 DWORD dwSize = 0;
337
338 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Sun\\xVM VirtualBox Guest Additions", 0, KEY_READ, &hKey);
339 if ((rc != ERROR_SUCCESS ) && (rc != ERROR_FILE_NOT_FOUND))
340 {
341 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Sun\\VirtualBox Guest Additions", 0, KEY_READ, &hKey);
342 if ((rc != ERROR_SUCCESS ) && (rc != ERROR_FILE_NOT_FOUND))
343 {
344 VBoxServiceError("Failed to open registry key (guest additions)! Error: %d\n", GetLastError());
345 return 1;
346 }
347 }
348
349 /* Installation directory. */
350 dwSize = sizeof(szInstDir);
351 rc = RegQueryValueExA (hKey, "InstallDir", 0, 0, (BYTE*)(LPCTSTR)szInstDir, &dwSize);
352 if ((rc != ERROR_SUCCESS ) && (rc != ERROR_FILE_NOT_FOUND))
353 {
354 RegCloseKey (hKey);
355 VBoxServiceError("Failed to query registry key (install directory)! Error: %d\n", GetLastError());
356 return 1;
357 }
358
359 /* Flip slashes. */
360 for (char* pszTmp = &szInstDir[0]; *pszTmp; ++pszTmp)
361 if (*pszTmp == '\\')
362 *pszTmp = '/';
363
364 /* Revision. */
365 dwSize = sizeof(szRev);
366 rc = RegQueryValueExA (hKey, "Revision", 0, 0, (BYTE*)(LPCTSTR)szRev, &dwSize);
367 if ((rc != ERROR_SUCCESS ) && (rc != ERROR_FILE_NOT_FOUND))
368 {
369 RegCloseKey (hKey);
370 VBoxServiceError("Failed to query registry key (revision)! Error: %d\n", GetLastError());
371 return 1;
372 }
373
374 /* Version. */
375 dwSize = sizeof(szVer);
376 rc = RegQueryValueExA (hKey, "Version", 0, 0, (BYTE*)(LPCTSTR)szVer, &dwSize);
377 if ((rc != ERROR_SUCCESS ) && (rc != ERROR_FILE_NOT_FOUND))
378 {
379 RegCloseKey (hKey);
380 VBoxServiceError("Failed to query registry key (version)! Error: %Rrc\n", GetLastError());
381 return 1;
382 }
383
384 /* Write information to host. */
385 VboxServiceWriteProp(uiClientID, "GuestAdd/InstallDir", szInstDir);
386 VboxServiceWriteProp(uiClientID, "GuestAdd/Revision", szRev);
387 VboxServiceWriteProp(uiClientID, "GuestAdd/Version", szVer);
388
389 RegCloseKey (hKey);
390
391 return VINF_SUCCESS;
392}
393
394int VboxServiceWinGetComponentVersions(uint32_t uiClientID)
395{
396 int rc;
397 char szVer[_MAX_PATH] = {0};
398 char szPropPath[_MAX_PATH] = {0};
399 TCHAR szSysDir[_MAX_PATH] = {0};
400 TCHAR szWinDir[_MAX_PATH] = {0};
401 TCHAR szDriversDir[_MAX_PATH + 32] = {0};
402
403 GetSystemDirectory(szSysDir, _MAX_PATH);
404 GetWindowsDirectory(szWinDir, _MAX_PATH);
405 swprintf(szDriversDir, (_MAX_PATH + 32), TEXT("%s\\drivers"), szSysDir);
406
407 /* The file information table. */
408 VBOXSERVICEVMINFOFILE vboxFileInfoTable[] =
409 {
410 { szSysDir, TEXT("VBoxControl.exe"), },
411 { szSysDir, TEXT("VBoxHook.dll"), },
412 { szSysDir, TEXT("VBoxDisp.dll"), },
413 { szSysDir, TEXT("VBoxMRXNP.dll"), },
414 { szSysDir, TEXT("VBoxService.exe"), },
415 { szSysDir, TEXT("VBoxTray.exe"), },
416 { szSysDir, TEXT("VBoxGINA.dll"), },
417
418 { szSysDir, TEXT("VBoxOGLarrayspu.dll"), },
419 { szSysDir, TEXT("VBoxOGLcrutil.dll"), },
420 { szSysDir, TEXT("VBoxOGLerrorspu.dll"), },
421 { szSysDir, TEXT("VBoxOGLpackspu.dll"), },
422 { szSysDir, TEXT("VBoxOGLpassthroughspu.dll"), },
423 { szSysDir, TEXT("VBoxOGLfeedbackspu.dll"), },
424 { szSysDir, TEXT("VBoxOGL.dll"), },
425
426 { szDriversDir, TEXT("VBoxGuest.sys"), },
427 { szDriversDir, TEXT("VBoxMouse.sys"), },
428 { szDriversDir, TEXT("VBoxSF.sys"), },
429 { szDriversDir, TEXT("VBoxVideo.sys"), },
430
431 {
432 NULL
433 }
434 };
435
436 PVBOXSERVICEVMINFOFILE pTable = vboxFileInfoTable;
437 Assert(pTable);
438 while (pTable->pszFileName)
439 {
440 rc = VboxServiceGetFileVersionString(pTable->pszFilePath, pTable->pszFileName, szVer, sizeof(szVer));
441 RTStrPrintf(szPropPath, sizeof(szPropPath), "GuestAdd/Components/%ls", pTable->pszFileName);
442 VboxServiceWriteProp(uiClientID, szPropPath, szVer);
443 pTable++;
444 }
445
446 return VINF_SUCCESS;
447}
448
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette