VirtualBox

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

Last change on this file since 39279 was 39279, checked in by vboxsync, 13 years ago

VBoxService/GuestCtrl: Overhauled internals, removed pipe double buffering, now using an IPC request/response system for communication (work in progress).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1/* $Id: VBoxServiceVMInfo-win.cpp 39279 2011-11-11 17:50:19Z vboxsync $ */
2/** @file
3 * VBoxService - Virtual Machine Information for the Host, Windows specifics.
4 */
5
6/*
7 * Copyright (C) 2009-2010 Oracle Corporation
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0502
23# undef _WIN32_WINNT
24# define _WIN32_WINNT 0x0502 /* CachedRemoteInteractive in recent SDKs. */
25#endif
26#include <Windows.h>
27#include <wtsapi32.h> /* For WTS* calls. */
28#include <psapi.h> /* EnumProcesses. */
29#include <Ntsecapi.h> /* Needed for process security information. */
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* Structures and Typedefs *
45*******************************************************************************/
46/** Structure for storing the looked up user information. */
47typedef struct
48{
49 WCHAR wszUser[_MAX_PATH];
50 WCHAR wszAuthenticationPackage[_MAX_PATH];
51 WCHAR wszLogonDomain[_MAX_PATH];
52 /** Number of assigned user processes. */
53 ULONG ulNumProcs;
54} VBOXSERVICEVMINFOUSER, *PVBOXSERVICEVMINFOUSER;
55
56/** Structure for the file information lookup. */
57typedef struct
58{
59 char *pszFilePath;
60 char *pszFileName;
61} VBOXSERVICEVMINFOFILE, *PVBOXSERVICEVMINFOFILE;
62
63/** Structure for process information lookup. */
64typedef struct
65{
66 DWORD id;
67 LUID luid;
68} VBOXSERVICEVMINFOPROC, *PVBOXSERVICEVMINFOPROC;
69
70
71/*******************************************************************************
72* Prototypes
73*******************************************************************************/
74uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession, VBOXSERVICEVMINFOPROC const *paProcs, DWORD cProcs);
75bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER a_pUserInfo, PLUID a_pSession);
76int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppProc, DWORD *pdwCount);
77void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC paProcs);
78
79
80
81#ifndef TARGET_NT4
82
83/**
84 * Fills in more data for a process.
85 *
86 * @returns VBox status code.
87 * @param pProc The process structure to fill data into.
88 * @param tkClass The kind of token information to get.
89 */
90static int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pProc,
91 TOKEN_INFORMATION_CLASS tkClass)
92{
93 AssertPtr(pProc);
94 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pProc->id);
95 if (h == NULL)
96 return RTErrConvertFromWin32(GetLastError());
97
98 int rc = VERR_NO_MEMORY;
99 HANDLE hToken;
100 if (OpenProcessToken(h, TOKEN_QUERY, &hToken))
101 {
102 void *pvTokenInfo = NULL;
103 DWORD dwTokenInfoSize;
104 switch (tkClass)
105 {
106 case TokenStatistics:
107 dwTokenInfoSize = sizeof(TOKEN_STATISTICS);
108 pvTokenInfo = RTMemAlloc(dwTokenInfoSize);
109 break;
110
111 /** @todo Implement more token classes here. */
112
113 default:
114 VBoxServiceError("Token class not implemented: %ld", tkClass);
115 rc = VERR_NOT_IMPLEMENTED;
116 break;
117 }
118
119 if (pvTokenInfo)
120 {
121 DWORD dwRetLength;
122 if (GetTokenInformation(hToken, tkClass, pvTokenInfo, dwTokenInfoSize, &dwRetLength))
123 {
124 switch (tkClass)
125 {
126 case TokenStatistics:
127 {
128 TOKEN_STATISTICS *pStats = (TOKEN_STATISTICS*)pvTokenInfo;
129 pProc->luid = pStats->AuthenticationId;
130 /** @todo Add more information of TOKEN_STATISTICS as needed. */
131 break;
132 }
133
134 default:
135 /* Should never get here! */
136 break;
137 }
138 rc = VINF_SUCCESS;
139 }
140 else
141 rc = RTErrConvertFromWin32(GetLastError());
142 RTMemFree(pvTokenInfo);
143 }
144 CloseHandle(hToken);
145 }
146 else
147 rc = RTErrConvertFromWin32(GetLastError());
148 CloseHandle(h);
149 return rc;
150}
151
152
153/**
154 * Enumerate all the processes in the system and get the logon user IDs for
155 * them.
156 *
157 * @returns VBox status code.
158 * @param ppaProcs Where to return the process snapshot. This must be
159 * freed by calling VBoxServiceVMInfoWinProcessesFree.
160 *
161 * @param pcProcs Where to store the returned process count.
162 */
163int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppaProcs, PDWORD pcProcs)
164{
165 AssertPtr(ppaProcs);
166 AssertPtr(pcProcs);
167
168 /*
169 * Call EnumProcesses with an increasingly larger buffer until it all fits
170 * or we think something is screwed up.
171 */
172 DWORD cProcesses = 64;
173 PDWORD paPids = NULL;
174 int rc = VINF_SUCCESS;
175 do
176 {
177 /* Allocate / grow the buffer first. */
178 cProcesses *= 2;
179 void *pvNew = RTMemRealloc(paPids, cProcesses * sizeof(DWORD));
180 if (!pvNew)
181 {
182 rc = VERR_NO_MEMORY;
183 break;
184 }
185 paPids = (PDWORD)pvNew;
186
187 /* Query the processes. Not the cbRet == buffer size means there could be more work to be done. */
188 DWORD cbRet;
189 if (!EnumProcesses(paPids, cProcesses * sizeof(DWORD), &cbRet))
190 {
191 rc = RTErrConvertFromWin32(GetLastError());
192 break;
193 }
194 if (cbRet < cProcesses * sizeof(DWORD))
195 {
196 cProcesses = cbRet / sizeof(DWORD);
197 break;
198 }
199 } while (cProcesses <= 32768); /* Should be enough; see: http://blogs.technet.com/markrussinovich/archive/2009/07/08/3261309.aspx */
200 if (RT_SUCCESS(rc))
201 {
202 /*
203 * Allocate out process structures and fill data into them.
204 * We currently only try lookup their LUID's.
205 */
206 PVBOXSERVICEVMINFOPROC paProcs;
207 paProcs = (PVBOXSERVICEVMINFOPROC)RTMemAllocZ(cProcesses * sizeof(VBOXSERVICEVMINFOPROC));
208 if (paProcs)
209 {
210 for (DWORD i = 0; i < cProcesses; i++)
211 {
212 paProcs[i].id = paPids[i];
213 rc = VBoxServiceVMInfoWinProcessesGetTokenInfo(&paProcs[i], TokenStatistics);
214 if (RT_FAILURE(rc))
215 {
216 /* Because some processes cannot be opened/parsed on
217 Windows, we should not consider to be this an error here. */
218 rc = VINF_SUCCESS;
219 }
220 }
221
222 /* Save number of processes */
223 if (RT_SUCCESS(rc))
224 {
225 *pcProcs = cProcesses;
226 *ppaProcs = paProcs;
227 }
228 else
229 RTMemFree(paProcs);
230 }
231 else
232 rc = VERR_NO_MEMORY;
233 }
234
235 RTMemFree(paPids);
236 return rc;
237}
238
239/**
240 * Frees the process structures returned by
241 * VBoxServiceVMInfoWinProcessesEnumerate() before.
242 *
243 * @param paProcs What
244 */
245void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC paProcs)
246{
247 RTMemFree(paProcs);
248}
249
250/**
251 * Determines whether the specified session has processes on the system.
252 *
253 * @returns Number of processes found for a specified session.
254 * @param pSession The session.
255 * @param paProcs The process snapshot.
256 * @param cProcs The number of processes in the snaphot.
257 */
258uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession, VBOXSERVICEVMINFOPROC const *paProcs, DWORD cProcs)
259{
260 if (!pSession)
261 {
262 VBoxServiceVerbose(1, "VMInfo/Users: Session became invalid while enumerating!\n");
263 return 0;
264 }
265
266 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
267 NTSTATUS rcNt = LsaGetLogonSessionData(pSession, &pSessionData);
268 if (rcNt != STATUS_SUCCESS)
269 {
270 VBoxServiceError("VMInfo/Users: Could not get logon session data! rcNt=%#x", rcNt);
271 return 0;
272 }
273
274 /*
275 * Even if a user seems to be logged in, it could be a stale/orphaned logon
276 * session. So check if we have some processes bound to it by comparing the
277 * session <-> process LUIDs.
278 */
279 uint32_t cNumProcs = 0;
280 for (DWORD i = 0; i < cProcs; i++)
281 {
282 /*VBoxServiceVerbose(3, "%ld:%ld <-> %ld:%ld\n",
283 paProcs[i].luid.HighPart, paProcs[i].luid.LowPart,
284 pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);*/
285 if ( paProcs[i].luid.HighPart == pSessionData->LogonId.HighPart
286 && paProcs[i].luid.LowPart == pSessionData->LogonId.LowPart)
287 {
288 cNumProcs++;
289 if (g_cVerbosity < 4) /* We want a bit more info on high verbosity. */
290 break;
291 }
292 }
293
294 if (g_cVerbosity >= 4)
295 VBoxServiceVerbose(3, "VMInfo/Users: Session %u has %u processes\n",
296 pSessionData->Session, cNumProcs);
297 else
298 VBoxServiceVerbose(3, "VMInfo/Users: Session %u has at least one process\n",
299 pSessionData->Session);
300
301 LsaFreeReturnBuffer(pSessionData);
302 return cNumProcs;
303}
304
305
306/**
307 * Save and noisy string copy.
308 *
309 * @param pwszDst Destination buffer.
310 * @param cbDst Size in bytes - not WCHAR count!
311 * @param pSrc Source string.
312 * @param pszWhat What this is. For the log.
313 */
314static void VBoxServiceVMInfoWinSafeCopy(PWCHAR pwszDst, size_t cbDst, LSA_UNICODE_STRING const *pSrc, const char *pszWhat)
315{
316 Assert(RT_ALIGN(cbDst, sizeof(WCHAR)) == cbDst);
317
318 size_t cbCopy = pSrc->Length;
319 if (cbCopy + sizeof(WCHAR) > cbDst)
320 {
321 VBoxServiceVerbose(0, "%s is too long - %u bytes, buffer %u bytes! It will be truncated.\n",
322 pszWhat, cbCopy, cbDst);
323 cbCopy = cbDst - sizeof(WCHAR);
324 }
325 if (cbCopy)
326 memcpy(pwszDst, pSrc->Buffer, cbCopy);
327 pwszDst[cbCopy / sizeof(WCHAR)] = '\0';
328}
329
330
331/**
332 * Detects whether a user is logged on.
333 *
334 * @returns true if logged in, false if not (or error).
335 * @param pUserInfo Where to return the user information.
336 * @param pSession The session to check.
337 */
338bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER pUserInfo, PLUID pSession)
339{
340 AssertPtr(pUserInfo);
341 if (!pSession)
342 return false;
343
344 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
345 NTSTATUS rcNt = LsaGetLogonSessionData(pSession, &pSessionData);
346 if (rcNt != STATUS_SUCCESS)
347 {
348 ULONG ulError = LsaNtStatusToWinError(rcNt);
349 switch (ulError)
350 {
351 case ERROR_NOT_ENOUGH_MEMORY:
352 /* If we don't have enough memory it's hard to judge whether the specified user
353 * is logged in or not, so just assume he/she's not. */
354 VBoxServiceVerbose(3, "VMInfo/Users: Not enough memory to retrieve logon session data!\n");
355 break;
356
357 case ERROR_NO_SUCH_LOGON_SESSION:
358 /* Skip session data which is not valid anymore because it may have been
359 * already terminated. */
360 break;
361
362 default:
363 VBoxServiceError("VMInfo/Users: LsaGetLogonSessionData failed with error %ul\n", ulError);
364 break;
365 }
366 if (pSessionData)
367 LsaFreeReturnBuffer(pSessionData);
368 return false;
369 }
370 if (!pSessionData)
371 {
372 VBoxServiceError("VMInfo/Users: Invalid logon session data!\n");
373 return false;
374 }
375
376 /*
377 * Only handle users which can login interactively or logged in
378 * remotely over native RDP.
379 */
380 bool fFoundUser = false;
381 DWORD dwErr = NO_ERROR;
382 if ( IsValidSid(pSessionData->Sid)
383 && ( (SECURITY_LOGON_TYPE)pSessionData->LogonType == Interactive
384 || (SECURITY_LOGON_TYPE)pSessionData->LogonType == RemoteInteractive
385 || (SECURITY_LOGON_TYPE)pSessionData->LogonType == CachedInteractive
386 || (SECURITY_LOGON_TYPE)pSessionData->LogonType == CachedRemoteInteractive))
387 {
388 VBoxServiceVerbose(3, "VMInfo/Users: Session data: Name=%ls, Len=%d, SID=%s, LogonID=%ld,%ld, LogonType=%ld\n",
389 pSessionData->UserName.Buffer,
390 pSessionData->UserName.Length,
391 pSessionData->Sid != NULL ? "1" : "0",
392 pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart,
393 pSessionData->LogonType);
394
395 /*
396 * Copy out relevant data.
397 */
398 VBoxServiceVMInfoWinSafeCopy(pUserInfo->wszUser, sizeof(pUserInfo->wszUser),
399 &pSessionData->UserName, "User name");
400 VBoxServiceVMInfoWinSafeCopy(pUserInfo->wszAuthenticationPackage, sizeof(pUserInfo->wszAuthenticationPackage),
401 &pSessionData->AuthenticationPackage, "Authentication pkg name");
402 VBoxServiceVMInfoWinSafeCopy(pUserInfo->wszLogonDomain, sizeof(pUserInfo->wszLogonDomain),
403 &pSessionData->LogonDomain, "Logon domain name");
404
405 TCHAR szOwnerName[_MAX_PATH] = { 0 };
406 DWORD dwOwnerNameSize = sizeof(szOwnerName);
407 TCHAR szDomainName[_MAX_PATH] = { 0 };
408 DWORD dwDomainNameSize = sizeof(szDomainName);
409 SID_NAME_USE enmOwnerType = SidTypeInvalid;
410 if (!LookupAccountSid(NULL,
411 pSessionData->Sid,
412 szOwnerName,
413 &dwOwnerNameSize,
414 szDomainName,
415 &dwDomainNameSize,
416 &enmOwnerType))
417 {
418 DWORD dwErr = GetLastError();
419 /*
420 * If a network time-out prevents the function from finding the name or
421 * if a SID that does not have a corresponding account name (such as a
422 * logon SID that identifies a logon session), we get ERROR_NONE_MAPPED
423 * here that we just skip.
424 */
425 if (dwErr != ERROR_NONE_MAPPED)
426 VBoxServiceError("VMInfo/Users: Failed looking up account info for user=%ls, error=$ld!\n",
427 pUserInfo->wszUser, dwErr);
428 }
429 else
430 {
431 if (enmOwnerType == SidTypeUser) /* Only recognize users; we don't care about the rest! */
432 {
433 VBoxServiceVerbose(3, "VMInfo/Users: Account User=%ls, Session=%ld, LUID=%ld,%ld, AuthPkg=%ls, Domain=%ls\n",
434 pUserInfo->wszUser, pSessionData->Session, pSessionData->LogonId.HighPart,
435 pSessionData->LogonId.LowPart, pUserInfo->wszAuthenticationPackage,
436 pUserInfo->wszLogonDomain);
437
438 /* Detect RDP sessions as well. */
439 LPTSTR pBuffer = NULL;
440 DWORD cbRet = 0;
441 int iState = 0;
442 if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
443 pSessionData->Session,
444 WTSConnectState,
445 &pBuffer,
446 &cbRet))
447 {
448 if (cbRet)
449 iState = *pBuffer;
450 VBoxServiceVerbose(3, "VMInfo/Users: Account User=%ls, WTSConnectState=%d\n",
451 pUserInfo->wszUser, iState);
452 if ( iState == WTSActive /* User logged on to WinStation. */
453 || iState == WTSShadow /* Shadowing another WinStation. */
454 || iState == WTSDisconnected) /* WinStation logged on without client. */
455 {
456 /** @todo On Vista and W2K, always "old" user name are still
457 * there. Filter out the old one! */
458 VBoxServiceVerbose(3, "VMInfo/Users: Account User=%ls using TCS/RDP, state=%d\n",
459 pUserInfo->wszUser, iState);
460 fFoundUser = true;
461 }
462 if (pBuffer)
463 WTSFreeMemory(pBuffer);
464 }
465 else
466 {
467 DWORD dwLastErr = GetLastError();
468 switch (dwLastErr)
469 {
470 /*
471 * Terminal services don't run (for example in W2K,
472 * nothing to worry about ...). ... or is on the Vista
473 * fast user switching page!
474 */
475 case ERROR_CTX_WINSTATION_NOT_FOUND:
476 VBoxServiceVerbose(3, "VMInfo/Users: Account User=%ls, no WinSta found\n",
477 pUserInfo->wszUser);
478 break;
479
480 default:
481 VBoxServiceVerbose(3, "VMInfo/Users: Account User=%ls, error=%ld\n",
482 pUserInfo->wszUser, dwLastErr);
483 break;
484 }
485
486 fFoundUser = true;
487 }
488 }
489 }
490
491 VBoxServiceVerbose(3, "VMInfo/Users: Account User=%ls %s logged in\n",
492 pUserInfo->wszUser, fFoundUser ? "is" : "is not");
493 }
494
495 LsaFreeReturnBuffer(pSessionData);
496 return fFoundUser;
497}
498
499
500/**
501 * Retrieves the currently logged in users and stores their names along with the
502 * user count.
503 *
504 * @returns VBox status code.
505 * @param ppszUserList Where to store the user list (separated by commas).
506 * Must be freed with RTStrFree().
507 * @param pcUsersInList Where to store the number of users in the list.
508 */
509int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList)
510{
511 PLUID paSessions = NULL;
512 ULONG cSessions = 0;
513
514 /* This function can report stale or orphaned interactive logon sessions
515 of already logged off users (especially in Windows 2000). */
516 NTSTATUS rcNt = LsaEnumerateLogonSessions(&cSessions, &paSessions);
517 if (rcNt != STATUS_SUCCESS)
518 {
519 ULONG ulError = LsaNtStatusToWinError(rcNt);
520 switch (ulError)
521 {
522 case ERROR_NOT_ENOUGH_MEMORY:
523 VBoxServiceError("VMInfo/Users: Not enough memory to enumerate logon sessions!\n");
524 break;
525
526 case ERROR_SHUTDOWN_IN_PROGRESS:
527 /* If we're about to shutdown when we were in the middle of enumerating the logon
528 * sessions, skip the error to not confuse the user with an unnecessary log message. */
529 VBoxServiceVerbose(3, "VMInfo/Users: Shutdown in progress ...\n");
530 ulError = ERROR_SUCCESS;
531 break;
532
533 default:
534 VBoxServiceError("VMInfo/Users: LsaEnumerate failed with error %ul\n", ulError);
535 break;
536 }
537
538 return RTErrConvertFromWin32(ulError);
539 }
540 VBoxServiceVerbose(3, "VMInfo/Users: Found %ld sessions\n", cSessions);
541
542 PVBOXSERVICEVMINFOPROC paProcs;
543 DWORD cProcs;
544 int rc = VBoxServiceVMInfoWinProcessesEnumerate(&paProcs, &cProcs);
545 if (RT_FAILURE(rc))
546 {
547 if (rc == VERR_NO_MEMORY)
548 VBoxServiceError("VMInfo/Users: Not enough memory to enumerate processes for a session!\n");
549 else
550 VBoxServiceError("VMInfo/Users: Failed to enumerate processes for a session, rc=%Rrc\n", rc);
551 }
552 else
553 {
554 PVBOXSERVICEVMINFOUSER pUserInfo;
555 pUserInfo = (PVBOXSERVICEVMINFOUSER)RTMemAllocZ(cSessions * sizeof(VBOXSERVICEVMINFOUSER) + 1);
556 if (!pUserInfo)
557 VBoxServiceError("VMInfo/Users: Not enough memory to store enumerated users!\n");
558 else
559 {
560 ULONG cUniqueUsers = 0;
561 for (ULONG i = 0; i < cSessions; i++)
562 {
563 VBOXSERVICEVMINFOUSER UserInfo;
564 if (VBoxServiceVMInfoWinIsLoggedIn(&UserInfo, &paSessions[i]))
565 {
566 uint32_t cSessionProcs = VBoxServiceVMInfoWinSessionHasProcesses(&paSessions[i], paProcs, cProcs);
567 if (!cSessionProcs)
568 continue;
569
570 bool fFoundUser = false;
571 for (ULONG i = 0; i < cUniqueUsers; i++)
572 {
573 if ( !wcscmp(UserInfo.wszUser, pUserInfo[i].wszUser)
574 && !wcscmp(UserInfo.wszLogonDomain, pUserInfo[i].wszLogonDomain)
575 && !wcscmp(UserInfo.wszAuthenticationPackage, pUserInfo[i].wszAuthenticationPackage))
576 {
577 /* If the process-per-user count was higher than 0 before but another session was
578 * was detected which also belongs to this user but has no assigned processes anymore,
579 * we detected a stale session. */
580 if ( pUserInfo[i].ulNumProcs > 0
581 && !cSessionProcs)
582 {
583 VBoxServiceVerbose(3, "VMInfo/Users: Stale session for user=%ls detected! Old processes: %u, new: %u\n",
584 pUserInfo[i].wszUser, pUserInfo[i].ulNumProcs, cSessionProcs);
585 }
586
587 VBoxServiceVerbose(4, "VMInfo/Users: Updating user=%ls to %u processes\n",
588 UserInfo.wszUser, cSessionProcs);
589
590 pUserInfo[i].ulNumProcs = cSessionProcs;
591 fFoundUser = true;
592 break;
593 }
594 }
595
596 if (!fFoundUser)
597 {
598 VBoxServiceVerbose(4, "VMInfo/Users: Adding new user=%ls with %u processes\n",
599 UserInfo.wszUser, cSessionProcs);
600
601 memcpy(&pUserInfo[cUniqueUsers], &UserInfo, sizeof(VBOXSERVICEVMINFOUSER));
602 pUserInfo[cUniqueUsers++].ulNumProcs = cSessionProcs;
603 Assert(cUniqueUsers <= cSessions);
604 }
605 }
606 }
607
608 VBoxServiceVerbose(3, "VMInfo/Users: Found %u unique logged-in user(s) with processes\n",
609 cUniqueUsers);
610
611 *pcUsersInList = 0;
612 for (ULONG i = 0; i < cUniqueUsers; i++)
613 {
614 if (pUserInfo[i].ulNumProcs)
615 {
616 if (*pcUsersInList > 0)
617 {
618 rc = RTStrAAppend(ppszUserList, ",");
619 AssertRCBreakStmt(rc, RTStrFree(*ppszUserList));
620 }
621
622 *pcUsersInList += 1;
623
624 char *pszTemp;
625 int rc2 = RTUtf16ToUtf8(pUserInfo[i].wszUser, &pszTemp);
626 if (RT_SUCCESS(rc2))
627 {
628 rc = RTStrAAppend(ppszUserList, pszTemp);
629 RTMemFree(pszTemp);
630 }
631 else
632 rc = RTStrAAppend(ppszUserList, "<string-conversion-error>");
633 AssertRCBreakStmt(rc, RTStrFree(*ppszUserList));
634 }
635 }
636
637 RTMemFree(pUserInfo);
638 }
639 VBoxServiceVMInfoWinProcessesFree(paProcs);
640 }
641 LsaFreeReturnBuffer(paSessions);
642 return rc;
643}
644
645#endif /* TARGET_NT4 */
646
647int VBoxServiceWinGetComponentVersions(uint32_t uClientID)
648{
649 int rc;
650 char szSysDir[_MAX_PATH] = {0};
651 char szWinDir[_MAX_PATH] = {0};
652 char szDriversDir[_MAX_PATH + 32] = {0};
653
654 /* ASSUME: szSysDir and szWinDir and derivatives are always ASCII compatible. */
655 GetSystemDirectory(szSysDir, _MAX_PATH);
656 GetWindowsDirectory(szWinDir, _MAX_PATH);
657 RTStrPrintf(szDriversDir, sizeof(szDriversDir), "%s\\drivers", szSysDir);
658#ifdef RT_ARCH_AMD64
659 char szSysWowDir[_MAX_PATH + 32] = {0};
660 RTStrPrintf(szSysWowDir, sizeof(szSysWowDir), "%s\\SysWow64", szWinDir);
661#endif
662
663 /* The file information table. */
664#ifndef TARGET_NT4
665 const VBOXSERVICEVMINFOFILE aVBoxFiles[] =
666 {
667 { szSysDir, "VBoxControl.exe" },
668 { szSysDir, "VBoxHook.dll" },
669 { szSysDir, "VBoxDisp.dll" },
670 { szSysDir, "VBoxMRXNP.dll" },
671 { szSysDir, "VBoxService.exe" },
672 { szSysDir, "VBoxTray.exe" },
673 { szSysDir, "VBoxGINA.dll" },
674 { szSysDir, "VBoxCredProv.dll" },
675
676 /* Handy-to-know stuff, mostly patched stuff. */
677 { szSysDir, "libWine.dll" },
678 { szSysDir, "wined3d.dll" },
679 { szSysDir, "d3d8.dll" },
680 { szSysDir, "d3d9.dll" },
681
682 /* Direct3D. */
683 { szSysDir, "VBoxDispD3D.dll" },
684 { szSysDir, "VBoxD3D8.dll" },
685 { szSysDir, "VBoxD3D9.dll" },
686
687 /* OpenGL. */
688 { szSysDir, "VBoxOGLarrayspu.dll" },
689 { szSysDir, "VBoxOGLcrutil.dll" },
690 { szSysDir, "VBoxOGLerrorspu.dll" },
691 { szSysDir, "VBoxOGLpackspu.dll" },
692 { szSysDir, "VBoxOGLpassthroughspu.dll" },
693 { szSysDir, "VBoxOGLfeedbackspu.dll" },
694 { szSysDir, "VBoxOGL.dll" },
695
696 /* On 64-bit OSes we also have our OpenGL + D3D DLLs in 32-bit,
697 so enumerate these files in the SYSWOW directory. */
698# ifdef RT_ARCH_AMD64
699 { szSysWowDir, "VBoxOGLarrayspu.dll" },
700 { szSysWowDir, "VBoxOGLcrutil.dll" },
701 { szSysWowDir, "VBoxOGLerrorspu.dll" },
702 { szSysWowDir, "VBoxOGLpackspu.dll" },
703 { szSysWowDir, "VBoxOGLpassthroughspu.dll" },
704 { szSysWowDir, "VBoxOGLfeedbackspu.dll" },
705 { szSysWowDir, "VBoxOGL.dll" },
706
707 { szSysWowDir, "VBoxDispD3D.dll" },
708# endif /* RT_ARCH_AMD64 */
709
710 /* Installed drivers. */
711 { szDriversDir, "VBoxGuest.sys" },
712 { szDriversDir, "VBoxMouse.sys" },
713 { szDriversDir, "VBoxSF.sys" },
714 { szDriversDir, "VBoxVideo.sys" },
715 { szDriversDir, "VBoxVideoWddm.sys" },
716 };
717
718#else /* TARGET_NT4 */
719 const VBOXSERVICEVMINFOFILE aVBoxFiles[] =
720 {
721 { szSysDir, "VBoxControl.exe" },
722 { szSysDir, "VBoxHook.dll" },
723 { szSysDir, "VBoxDisp.dll" },
724 { szSysDir, "VBoxServiceNT.exe" },
725 { szSysDir, "VBoxTray.exe" },
726
727 { szDriversDir, "VBoxGuestNT.sys" },
728 { szDriversDir, "VBoxMouseNT.sys" },
729 { szDriversDir, "VBoxVideo.sys" },
730 };
731#endif /* TARGET_NT4 */
732
733 for (unsigned i = 0; i < RT_ELEMENTS(aVBoxFiles); i++)
734 {
735 char szVer[128];
736 VBoxServiceGetFileVersionString(aVBoxFiles[i].pszFilePath, aVBoxFiles[i].pszFileName, szVer, sizeof(szVer));
737 char szPropPath[256];
738 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestAdd/Components/%s", aVBoxFiles[i].pszFileName);
739 rc = VBoxServiceWritePropF(uClientID, szPropPath, "%s", szVer);
740 }
741
742 return VINF_SUCCESS;
743}
744
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