55
/* Function GetLUIDsFromProcesses() written by Stefan Kuhr. */
56
DWORD VBoxServiceVMInfoWinGetLUIDsFromProcesses(PLUID *ppLuid)
58
DWORD dwSize, dwSize2, dwIndex ;
60
DWORD dwLastError = ERROR_SUCCESS;
64
SetLastError(ERROR_INVALID_PARAMETER);
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);
54
int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pProc,
55
TOKEN_INFORMATION_CLASS tkClass)
58
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pProc->id);
60
return RTErrConvertFromWin32(GetLastError());
64
if (FALSE == OpenProcessToken(h, TOKEN_QUERY, &hToken))
66
rc = RTErrConvertFromWin32(GetLastError());
70
void *pvTokenInfo = NULL;
71
DWORD dwTokenInfoSize;
75
dwTokenInfoSize = sizeof(TOKEN_STATISTICS);
76
pvTokenInfo = (TOKEN_STATISTICS*)RTMemAlloc(dwTokenInfoSize);
77
AssertPtr(pvTokenInfo);
80
/** @todo Implement more token classes here. */
83
VBoxServiceError("Token class not implemented: %ld", tkClass);
84
rc = VERR_NOT_IMPLEMENTED;
91
if (FALSE == GetTokenInformation(hToken, tkClass, pvTokenInfo, dwTokenInfoSize, &dwRetLength))
93
rc = RTErrConvertFromWin32(GetLastError());
101
TOKEN_STATISTICS *pStats = (TOKEN_STATISTICS*)pvTokenInfo;
103
pProc->luid = pStats->AuthenticationId;
104
/* @todo Add more information of TOKEN_STATISTICS as needed. */
109
/* Should never get here! */
114
RTMemFree(pvTokenInfo);
122
int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppProc, DWORD *pdwCount)
127
DWORD dwNumProcs = 128; /* Number of processes our array can hold */
128
DWORD *pdwProcIDs = (DWORD*)RTMemAlloc(dwNumProcs * sizeof(DWORD));
129
if (pdwProcIDs == NULL)
130
return VERR_NO_MEMORY;
133
DWORD cbRet; /* Returned size in bytes */
87
HeapFree(GetProcessHeap(), 0, lpdwPIDs) ;
90
lpdwPIDs = (unsigned long *)HeapAlloc(GetProcessHeap(), 0, dwSize2);
92
return 0L; // Last error will be that of HeapAlloc
94
if (!EnumProcesses( lpdwPIDs, dwSize2, &dwSize))
96
DWORD dw = GetLastError();
97
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
102
while (dwSize == dwSize2);
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. */
111
/* How many ProcIDs did we get? */
112
dwSize /= sizeof(DWORD);
113
dwSize2 = 0L; /* Our return value of found luids. */
115
*ppLuid = (LUID *)LocalAlloc(LPTR, dwSize*sizeof(LUID));
118
dwLastError = GetLastError();
121
for (dwIndex = 0; dwIndex < dwSize; dwIndex++)
123
(*ppLuid)[dwIndex].LowPart =0L;
124
(*ppLuid)[dwIndex].HighPart=0;
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 )
132
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hAccessToken))
136
if (GetTokenInformation(hAccessToken, TokenStatistics, &ts, sizeof ts, &dwSize))
136
if (FALSE == EnumProcesses(pdwProcIDs, dwNumProcs * sizeof(DWORD), &cbRet))
138
rc = RTErrConvertFromWin32(GetLastError());
142
/* Was our array big enough? Or do we need more space? */
143
if (cbRet >= dwNumProcs * sizeof(DWORD))
145
/* Apparently not, so try next bigger size */
147
pdwProcIDs = (DWORD*)RTMemRealloc(pdwProcIDs, dwNumProcs * sizeof(DWORD));
148
if (pdwProcIDs == NULL)
157
dwNumProcs = cbRet / sizeof(DWORD); /* Set the current, real size of the number of processes we retrieved */
160
} while(dwNumProcs < 32768); /* Should be enough; see: http://blogs.technet.com/markrussinovich/archive/2009/07/08/3261309.aspx */
164
/* Allocate our process structure */
165
*ppProc = (PVBOXSERVICEVMINFOPROC)RTMemAlloc(dwNumProcs * sizeof(VBOXSERVICEVMINFOPROC));
171
/* We now have the PIDs, fill them into the struct and lookup their LUID's */
172
PVBOXSERVICEVMINFOPROC pCur = *ppProc;
173
DWORD *pCurProcID = pdwProcIDs;
174
for (DWORD i=0; i<dwNumProcs; i++)
176
RT_BZERO(pCur, sizeof(VBOXSERVICEVMINFOPROC));
177
pCur->id = *pCurProcID;
178
rc = VBoxServiceVMInfoWinProcessesGetTokenInfo(pCur, TokenStatistics);
140
for (;dwTmp<dwSize2 && !bFound;dwTmp++)
141
bFound = (*ppLuid)[dwTmp].HighPart == ts.AuthenticationId.HighPart &&
142
(*ppLuid)[dwTmp].LowPart == ts.AuthenticationId.LowPart;
145
(*ppLuid)[dwSize2++] = ts.AuthenticationId;
181
/* Because some processes cannot be opened/parsed on Windows, we should not consider to
182
be this an error here. */
147
CloseHandle(hAccessToken);
150
CloseHandle(hProcess);
188
/* Save number of processes */
189
*pdwCount = dwNumProcs;
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. */
160
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
162
if (ERROR_SUCCESS !=dwLastError)
163
SetLastError(dwLastError);
168
BOOL VBoxServiceVMInfoWinIsLoggedIn(VBOXSERVICEVMINFOUSER* a_pUserInfo,
171
DWORD a_dwNumOfProcLUIDs)
173
BOOL bLoggedIn = FALSE;
193
RTMemFree(pdwProcIDs);
195
VBoxServiceVMInfoWinProcessesFree(*ppProc);
199
void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC pProc)
208
DWORD VBoxServiceVMInfoWinSessionGetProcessCount(PLUID pSession,
209
PVBOXSERVICEVMINFOPROC pProc, DWORD dwProcCount)
213
if (dwProcCount <= 0) /* To be on the safe side. */
217
PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
218
if (STATUS_SUCCESS != LsaGetLogonSessionData (pSession, &pSessionData))
220
VBoxServiceError("Could not get logon session data! rc=%Rrc", RTErrConvertFromWin32(GetLastError()));
223
AssertPtr(pSessionData);
225
/* Even if a user seems to be logged in, it could be a stale/orphaned logon session.
226
* So check if we have some processes bound to it by comparing the session <-> process LUIDs. */
227
PVBOXSERVICEVMINFOPROC pCur = pProc;
228
for (DWORD i=0; i<dwProcCount; i++)
230
/*VBoxServiceVerbose(3, "%ld:%ld <-> %ld:%ld\n",
231
pCur->luid.HighPart, pCur->luid.LowPart,
232
pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);*/
233
if ( pCur->luid.HighPart == pSessionData->LogonId.HighPart
234
&& pCur->luid.LowPart == pSessionData->LogonId.LowPart)
236
VBoxServiceVerbose(3, "Users: Session %ld:%ld has active processes\n",
237
pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);
238
LsaFreeReturnBuffer(pSessionData);
243
LsaFreeReturnBuffer(pSessionData);
247
BOOL VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER a_pUserInfo,
174
250
BOOL bFoundUser = FALSE;
175
251
PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
207
285
/* Get the user name. */
208
286
usBuffer = (sessionData->UserName).Buffer;
209
287
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. */
288
if (iLength > sizeof(a_pUserInfo->szUser) - sizeof(WCHAR)) /* -sizeof(WCHAR) because we have to add the terminating null char at the end later. */
212
290
VBoxServiceVerbose(0, "User name too long (%d bytes) for buffer! Name will be truncated.\n", iLength);
213
iLength = sizeof(a_pUserInfo->szUser) - sizeof(TCHAR);
291
iLength = sizeof(a_pUserInfo->szUser) - sizeof(WCHAR);
215
293
wcsncpy (a_pUserInfo->szUser, usBuffer, iLength);
216
wcscat (a_pUserInfo->szUser, L""); /* Add terminating null char. */
218
295
/* Get authentication package. */
219
296
usBuffer = (sessionData->AuthenticationPackage).Buffer;
220
297
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. */
298
if (iLength > sizeof(a_pUserInfo->szAuthenticationPackage) - sizeof(WCHAR)) /* -sizeof(WCHAR) because we have to add the terminating null char at the end later. */
223
300
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);
301
iLength = sizeof(a_pUserInfo->szAuthenticationPackage) - sizeof(WCHAR);
226
wcsncpy (a_pUserInfo->szAuthenticationPackage, usBuffer, iLength);
227
wcscat (a_pUserInfo->szAuthenticationPackage, L""); /* Add terminating null char. */
304
wcsncpy (a_pUserInfo->szAuthenticationPackage, usBuffer, iLength);
229
306
/* Get logon domain. */
230
307
usBuffer = (sessionData->LogonDomain).Buffer;
231
308
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. */
309
if (iLength > sizeof(a_pUserInfo->szLogonDomain) - sizeof(WCHAR)) /* -sizeof(WCHAR) because we have to add the terminating null char at the end later. */
234
311
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);
312
iLength = sizeof(a_pUserInfo->szLogonDomain) - sizeof(WCHAR);
237
wcsncpy (a_pUserInfo->szLogonDomain, usBuffer, iLength);
238
wcscat (a_pUserInfo->szLogonDomain, L""); /* Add terminating null char. */
315
wcsncpy (a_pUserInfo->szLogonDomain, usBuffer, iLength);
240
317
/* Only handle users which can login interactively or logged in remotely over native RDP. */
241
318
if ( (((SECURITY_LOGON_TYPE)sessionData->LogonType == Interactive)