~ubuntu-branches/ubuntu/vivid/virtualbox-ose/vivid

« back to all changes in this revision

Viewing changes to src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2010-03-11 17:16:37 UTC
  • mfrom: (0.3.4 upstream) (0.4.8 sid)
  • Revision ID: james.westby@ubuntu.com-20100311171637-43z64ia3ccpj8vqn
Tags: 3.1.4-dfsg-2ubuntu1
* Merge from Debian unstable (LP: #528561), remaining changes:
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
  - Replace *-source packages with transitional packages for *-dkms
* Fix crash in vboxvideo_drm with kernel 2.6.33 / backported drm code
  (LP: #535297)
* Add a list of linux-headers packages to the apport hook
* Update debian/patches/u02-lp-integration.dpatch with a
  DEP-3 compliant header
* Add ${misc:Depends} to virtualbox-ose-source and virtualbox-ose-guest-source
  Depends

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
*   Header Files                                                               *
25
25
*******************************************************************************/
26
26
#include <windows.h>
27
 
#include <Ntsecapi.h>
28
27
#include <wtsapi32.h>       /* For WTS* calls. */
29
28
#include <psapi.h>          /* EnumProcesses. */
30
29
 
52
51
 
53
52
 
54
53
#ifndef TARGET_NT4
55
 
/* Function GetLUIDsFromProcesses() written by Stefan Kuhr. */
56
 
DWORD 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;
 
54
int VBoxServiceVMInfoWinProcessesGetTokenInfo(PVBOXSERVICEVMINFOPROC pProc, 
 
55
                                              TOKEN_INFORMATION_CLASS tkClass)
 
56
{
 
57
    AssertPtr(pProc);
 
58
    HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pProc->id);
 
59
    if (h == NULL)
 
60
        return RTErrConvertFromWin32(GetLastError());
 
61
 
 
62
     HANDLE hToken;
 
63
     int rc;
 
64
     if (FALSE == OpenProcessToken(h, TOKEN_QUERY, &hToken))
 
65
     {
 
66
         rc = RTErrConvertFromWin32(GetLastError());
 
67
     }
 
68
     else
 
69
     {
 
70
         void *pvTokenInfo = NULL;
 
71
         DWORD dwTokenInfoSize;
 
72
         switch (tkClass)
 
73
         {
 
74
         case TokenStatistics:
 
75
             dwTokenInfoSize = sizeof(TOKEN_STATISTICS);
 
76
             pvTokenInfo = (TOKEN_STATISTICS*)RTMemAlloc(dwTokenInfoSize);
 
77
             AssertPtr(pvTokenInfo);
 
78
             break;
 
79
 
 
80
         /** @todo Implement more token classes here. */
 
81
 
 
82
         default:
 
83
             VBoxServiceError("Token class not implemented: %ld", tkClass);
 
84
             rc = VERR_NOT_IMPLEMENTED;
 
85
             break;
 
86
         }
 
87
 
 
88
         if (pvTokenInfo)
 
89
         {     
 
90
             DWORD dwRetLength;
 
91
             if (FALSE == GetTokenInformation(hToken, tkClass, pvTokenInfo, dwTokenInfoSize, &dwRetLength))
 
92
             {
 
93
                 rc = RTErrConvertFromWin32(GetLastError());
 
94
             }
 
95
             else
 
96
             {
 
97
                 switch (tkClass)
 
98
                 {
 
99
                 case TokenStatistics:
 
100
                     {
 
101
                         TOKEN_STATISTICS *pStats = (TOKEN_STATISTICS*)pvTokenInfo;
 
102
                         AssertPtr(pStats);
 
103
                         pProc->luid = pStats->AuthenticationId;
 
104
                         /* @todo Add more information of TOKEN_STATISTICS as needed. */
 
105
                         break;
 
106
                     }
 
107
 
 
108
                 default:
 
109
                     /* Should never get here! */
 
110
                     break;                
 
111
                 }
 
112
                 rc = VINF_SUCCESS;
 
113
             }
 
114
             RTMemFree(pvTokenInfo);
 
115
         }
 
116
         CloseHandle(hToken);
 
117
    }   
 
118
    CloseHandle(h);
 
119
    return rc;
 
120
}
 
121
 
 
122
int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppProc, DWORD *pdwCount)
 
123
{
 
124
    AssertPtr(ppProc);
 
125
    AssertPtr(pdwCount);
 
126
 
 
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;
 
131
 
 
132
    int rc;
 
133
    DWORD cbRet; /* Returned size in bytes */
83
134
    do
84
135
    {
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))
 
136
        if (FALSE == EnumProcesses(pdwProcIDs, dwNumProcs * sizeof(DWORD), &cbRet))
 
137
        {
 
138
            rc = RTErrConvertFromWin32(GetLastError());
 
139
            break;
 
140
        }
 
141
 
 
142
        /* Was our array big enough? Or do we need more space? */
 
143
        if (cbRet >= dwNumProcs * sizeof(DWORD))
 
144
        {
 
145
            /* Apparently not, so try next bigger size */
 
146
            dwNumProcs += 128;
 
147
            pdwProcIDs = (DWORD*)RTMemRealloc(pdwProcIDs, dwNumProcs * sizeof(DWORD));
 
148
            if (pdwProcIDs == NULL)
 
149
            {
 
150
                rc = VERR_NO_MEMORY;
 
151
                break;
 
152
            }
 
153
        }
 
154
        else
 
155
        {
 
156
            rc = VINF_SUCCESS;
 
157
            dwNumProcs = cbRet / sizeof(DWORD); /* Set the current, real size of the number of processes we retrieved */
 
158
            break;
 
159
        }
 
160
    } while(dwNumProcs < 32768); /* Should be enough; see: http://blogs.technet.com/markrussinovich/archive/2009/07/08/3261309.aspx */
 
161
 
 
162
    if (RT_SUCCESS(rc))
 
163
    {
 
164
        /* Allocate our process structure */
 
165
        *ppProc = (PVBOXSERVICEVMINFOPROC)RTMemAlloc(dwNumProcs * sizeof(VBOXSERVICEVMINFOPROC));
 
166
        if (ppProc == NULL)
 
167
            rc = VERR_NO_MEMORY;
 
168
 
 
169
        if (RT_SUCCESS(rc))
 
170
        {
 
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++)
 
175
            {
 
176
                RT_BZERO(pCur, sizeof(VBOXSERVICEVMINFOPROC));
 
177
                pCur->id = *pCurProcID;
 
178
                rc = VBoxServiceVMInfoWinProcessesGetTokenInfo(pCur, TokenStatistics);
 
179
                if (RT_FAILURE(rc))
137
180
                {
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;
 
181
                    /* Because some processes cannot be opened/parsed on Windows, we should not consider to
 
182
                       be this an error here. */
 
183
                    rc = VINF_SUCCESS;
146
184
                }
147
 
                CloseHandle(hAccessToken);
 
185
                pCur++;
 
186
                pCurProcID++;
148
187
            }
149
 
 
150
 
            CloseHandle(hProcess);
 
188
            /* Save number of processes */
 
189
            *pdwCount = dwNumProcs;
151
190
        }
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
 
 
168
 
BOOL VBoxServiceVMInfoWinIsLoggedIn(VBOXSERVICEVMINFOUSER* a_pUserInfo,
169
 
                                    PLUID a_pSession,
170
 
                                    PLUID a_pLuid,
171
 
                                    DWORD a_dwNumOfProcLUIDs)
172
 
{
173
 
    BOOL bLoggedIn = FALSE;
 
191
    }
 
192
 
 
193
    RTMemFree(pdwProcIDs);
 
194
    if (RT_FAILURE(rc))
 
195
        VBoxServiceVMInfoWinProcessesFree(*ppProc);
 
196
    return rc;
 
197
}
 
198
 
 
199
void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC pProc)
 
200
{
 
201
    if (pProc != NULL)
 
202
    {
 
203
        RTMemFree(pProc);
 
204
        pProc = NULL;
 
205
    }
 
206
}
 
207
 
 
208
DWORD VBoxServiceVMInfoWinSessionGetProcessCount(PLUID pSession,
 
209
                                                 PVBOXSERVICEVMINFOPROC pProc, DWORD dwProcCount)
 
210
{
 
211
    AssertPtr(pSession);
 
212
 
 
213
    if (dwProcCount <= 0) /* To be on the safe side. */
 
214
        return 0;
 
215
    AssertPtr(pProc);
 
216
 
 
217
    PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
 
218
    if (STATUS_SUCCESS != LsaGetLogonSessionData (pSession, &pSessionData))
 
219
    {
 
220
        VBoxServiceError("Could not get logon session data! rc=%Rrc", RTErrConvertFromWin32(GetLastError()));
 
221
        return 0;
 
222
    }
 
223
    AssertPtr(pSessionData);
 
224
 
 
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++)
 
229
    {
 
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)
 
235
        {
 
236
            VBoxServiceVerbose(3, "Users: Session %ld:%ld has active processes\n",
 
237
                               pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);
 
238
            LsaFreeReturnBuffer(pSessionData);
 
239
            return 1;
 
240
        }          
 
241
        pCur++;
 
242
    }
 
243
    LsaFreeReturnBuffer(pSessionData);
 
244
    return 0;
 
245
}
 
246
 
 
247
BOOL VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER a_pUserInfo,
 
248
                                    PLUID a_pSession)
 
249
{
174
250
    BOOL bFoundUser = FALSE;
175
251
    PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
176
252
    NTSTATUS r = 0;
180
256
    if (!a_pSession)
181
257
        return FALSE;
182
258
 
183
 
    r = LsaGetLogonSessionData (a_pSession, &sessionData);
 
259
    r = LsaGetLogonSessionData(a_pSession, &sessionData);
184
260
    if (r != STATUS_SUCCESS)
185
261
    {
186
262
        VBoxServiceError("LsaGetLogonSessionData failed, LSA error %lu\n", LsaNtStatusToWinError(r));
198
274
    }
199
275
 
200
276
    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);
 
277
        (sessionData->UserName).Buffer, 
 
278
        (sessionData->UserName).Length, 
 
279
        (sessionData->Sid != NULL) ? "1" : "0", sessionData->LogonId.HighPart, sessionData->LogonId.LowPart);
202
280
 
203
281
    if ((sessionData->UserName.Buffer != NULL) &&
204
282
        (sessionData->Sid != 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. */
211
289
        {
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);
214
292
        }
215
293
        wcsncpy (a_pUserInfo->szUser, usBuffer, iLength);
216
 
        wcscat (a_pUserInfo->szUser, L"");      /* Add terminating null char. */
217
294
 
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. */
222
299
        {
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);
225
302
        }
226
 
        wcsncpy (a_pUserInfo->szAuthenticationPackage, usBuffer, iLength);
227
 
        wcscat (a_pUserInfo->szAuthenticationPackage, L"");     /* Add terminating null char. */
 
303
        if (iLength)
 
304
            wcsncpy (a_pUserInfo->szAuthenticationPackage, usBuffer, iLength);
228
305
 
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. */
233
310
        {
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);
236
313
        }
237
 
        wcsncpy (a_pUserInfo->szLogonDomain, usBuffer, iLength);
238
 
        wcscat (a_pUserInfo->szLogonDomain, L"");       /* Add terminating null char. */
 
314
        if (iLength)
 
315
            wcsncpy (a_pUserInfo->szLogonDomain, usBuffer, iLength);
239
316
 
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)
305
382
 
306
383
                    if (pBuffer)
307
384
                        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
385
                }
322
386
            }
323
387
        }
324
388
    }
325
389
 
326
390
    LsaFreeReturnBuffer(sessionData);
327
 
    return bLoggedIn;
 
391
    return bFoundUser;
328
392
}
329
 
 
330
393
#endif /* TARGET_NT4 */
331
394
 
332
395
int VBoxServiceWinGetComponentVersions(uint32_t uiClientID)