VirtualBox

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

Last change on this file since 25776 was 24686, checked in by vboxsync, 15 years ago

VbglR3/VBoxService: Split up and removed redundant code.

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