VirtualBox

Changeset 26083 in vbox for trunk/src/VBox/Additions/common


Ignore:
Timestamp:
Jan 28, 2010 1:53:51 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
57036
Message:

VBoxService: Improved modularity for process information lookup; rewritten a couple of things.

Location:
trunk/src/VBox/Additions/common/VBoxService
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r26061 r26083  
    2727# include <Windows.h>
    2828# include <process.h> /* Needed for file version information. */
     29# include <Ntsecapi.h> /* Needed for process security information. */
    2930#endif
    3031
     
    115116    char *pszFileName;
    116117} VBOXSERVICEVMINFOFILE, *PVBOXSERVICEVMINFOFILE;
     118/** Structure for process information lookup. */
     119typedef struct
     120{
     121    DWORD id;
     122    LUID luid;
     123} VBOXSERVICEVMINFOPROC, *PVBOXSERVICEVMINFOPROC;
    117124/** Function prototypes for dynamic loading. */
    118125typedef DWORD (WINAPI* fnWTSGetActiveConsoleSessionId)();
     
    152159extern BOOL VBoxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint);
    153160# ifdef VBOX_WITH_GUEST_PROPS
     161/** Determines the total count of processes attach to a logon session. */
     162extern DWORD VBoxServiceVMInfoWinSessionGetProcessCount(PLUID pSession,
     163                                                        PVBOXSERVICEVMINFOPROC pProc, DWORD dwProcCount);
    154164/** Detects wheter a user is logged on based on the enumerated processes. */
    155 extern BOOL VBoxServiceVMInfoWinIsLoggedIn(VBOXSERVICEVMINFOUSER *a_pUserInfo,
    156                                            PLUID a_pSession,
    157                                            PLUID a_pLuid,
    158                                            DWORD a_dwNumOfProcLUIDs);
    159 /** Gets logon user IDs from enumerated processes. */
    160 extern DWORD VBoxServiceVMInfoWinGetLUIDsFromProcesses(PLUID *ppLuid);
     165extern BOOL VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER a_pUserInfo,
     166                                           PLUID a_pSession);
     167/** Gets logon user IDs from enumerated processes. ppProc needs to be freed with VBoxServiceVMInfoWinProcessesFree() afterwards. */
     168extern int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppProc, DWORD *pdwCount);
     169/** Frees the process structure allocated by VBoxServiceVMInfoWinProcessesEnumerate() before. */
     170extern void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC pProc);
    161171# endif /* VBOX_WITH_GUEST_PROPS */
    162172#endif /* RT_OS_WINDOWS */
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp

    r26073 r26083  
    2525*******************************************************************************/
    2626#include <windows.h>
    27 #include <Ntsecapi.h>
    2827#include <wtsapi32.h>       /* For WTS* calls. */
    2928#include <psapi.h>          /* EnumProcesses. */
     
    5352
    5453#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;
     54int 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             break;
     85         }
     86
     87         if (pvTokenInfo)
     88         {     
     89             DWORD dwRetLength;
     90             if (FALSE == GetTokenInformation(hToken, tkClass, pvTokenInfo, dwTokenInfoSize, &dwRetLength))
     91             {
     92                 rc = RTErrConvertFromWin32(GetLastError());
     93             }
     94             else
     95             {
     96                 switch (tkClass)
     97                 {
     98                 case TokenStatistics:
     99                     {
     100                         TOKEN_STATISTICS *pStats = (TOKEN_STATISTICS*)pvTokenInfo;
     101                         AssertPtr(pStats);
     102                         pProc->luid = pStats->AuthenticationId;
     103                         /* @todo Add more information of TOKEN_STATISTICS as needed. */
     104                         break;
     105                     }
     106
     107                 default:
     108                     /* Should never get here! */
     109                     break;               
     110                 }
     111                 rc = VINF_SUCCESS;
     112             }
     113             RTMemFree(pvTokenInfo);
     114         }
     115         CloseHandle(hToken);
     116    }   
     117    CloseHandle(h);
     118    return rc;
     119}
     120
     121int VBoxServiceVMInfoWinProcessesEnumerate(PVBOXSERVICEVMINFOPROC *ppProc, DWORD *pdwCount)
     122{
     123    AssertPtr(ppProc);
     124    AssertPtr(pdwCount);
     125
     126    DWORD dwSize = 256; /* Number of processes our array can hold */
     127    DWORD *pdwProcIDs = (DWORD*)RTMemAlloc(dwSize * sizeof(DWORD));
     128    if (pdwProcIDs == NULL)
     129        return VERR_NO_MEMORY;
     130
     131    int rc;
     132    DWORD dwNeeded;
    83133    do
    84134    {
    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))
     135        if (FALSE == EnumProcesses(pdwProcIDs, dwSize * sizeof(DWORD), &dwNeeded))
     136        {
     137            rc = RTErrConvertFromWin32(GetLastError());
     138            break;
     139        }
     140
     141        /* Was our array big enough? Or do we need more space? */
     142        if (dwNeeded >= dwSize)
     143        {
     144            /* Apparently not, so try next bigger size */
     145            dwSize += 256;
     146            pdwProcIDs = (DWORD*)RTMemRealloc(pdwProcIDs, dwSize * sizeof(DWORD));
     147            if (pdwProcIDs == NULL)
    133148            {
    134                 TOKEN_STATISTICS ts;
    135                 DWORD dwSize;
    136                 if (GetTokenInformation(hAccessToken, TokenStatistics, &ts, sizeof ts, &dwSize))
     149                rc = VERR_NO_MEMORY;
     150                break;
     151            }
     152        }
     153        else
     154        {
     155            rc = VINF_SUCCESS;
     156            break;
     157        }
     158    } while(dwNeeded >= dwSize);
     159
     160    if (RT_SUCCESS(rc))
     161    {
     162        /* Allocate our process structure */
     163        *ppProc = (PVBOXSERVICEVMINFOPROC)RTMemAlloc(dwNeeded * sizeof(VBOXSERVICEVMINFOPROC));
     164        if (ppProc == NULL)
     165            rc = VERR_NO_MEMORY;
     166
     167        if (RT_SUCCESS(rc))
     168        {
     169            /* We now have the PIDs, fill them into the struct and lookup their LUID's */
     170            PVBOXSERVICEVMINFOPROC pCur = *ppProc;
     171            DWORD *pCurProcID = pdwProcIDs;
     172            for (DWORD i=0; i<dwNeeded; i++)
     173            {
     174                RT_BZERO(pCur, sizeof(VBOXSERVICEVMINFOPROC));
     175                pCur->id = *pCurProcID;
     176                rc = VBoxServiceVMInfoWinProcessesGetTokenInfo(pCur, TokenStatistics);
     177                if (RT_FAILURE(rc))
    137178                {
    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;
     179                    /* Because some processes cannot be opened/parsed on Windows, we should not consider to
     180                       be this an error here. */
     181                    rc = VINF_SUCCESS;
    146182                }
    147                 CloseHandle(hAccessToken);
     183                pCur++;
     184                pCurProcID++;
    148185            }
    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 
    168 BOOL VBoxServiceVMInfoWinIsLoggedIn(VBOXSERVICEVMINFOUSER* a_pUserInfo,
    169                                     PLUID a_pSession,
    170                                     PLUID a_pLuid,
    171                                     DWORD a_dwNumOfProcLUIDs)
    172 {
    173     BOOL bLoggedIn = FALSE;
     186            /* Save number of processes */
     187            *pdwCount = dwNeeded;
     188        }
     189    }
     190
     191    RTMemFree(pdwProcIDs);
     192    if (RT_FAILURE(rc))
     193        VBoxServiceVMInfoWinProcessesFree(*ppProc);
     194    return rc;
     195}
     196
     197void VBoxServiceVMInfoWinProcessesFree(PVBOXSERVICEVMINFOPROC pProc)
     198{
     199    if (pProc != NULL)
     200    {
     201        RTMemFree(pProc);
     202        pProc = NULL;
     203    }
     204}
     205
     206DWORD VBoxServiceVMInfoWinSessionGetProcessCount(PLUID pSession,
     207                                                 PVBOXSERVICEVMINFOPROC pProc, DWORD dwProcCount)
     208{
     209    AssertPtr(pSession);
     210
     211    if (dwProcCount <= 0) /* To be on the safe side. */
     212        return 0;
     213    AssertPtr(pProc);
     214
     215    PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
     216    if (STATUS_SUCCESS != LsaGetLogonSessionData (pSession, &pSessionData))
     217    {
     218        VBoxServiceError("Could not get logon session data! rc=%Rrc", RTErrConvertFromWin32(GetLastError()));
     219        return 0;
     220    }
     221    AssertPtr(pSessionData);
     222
     223    /* Even if a user seems to be logged in, it could be a stale/orphaned logon session.
     224     * So check if we have some processes bound to it by comparing the session <-> process LUIDs. */
     225    PVBOXSERVICEVMINFOPROC pCur = pProc;
     226    for (DWORD i=0; i<dwProcCount; i++)
     227    {
     228        /*VBoxServiceVerbose(3, "%ld:%ld <-> %ld:%ld\n",
     229                           pCur->luid.HighPart, pCur->luid.LowPart,
     230                           pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);*/
     231        if (   pCur->luid.HighPart == pSessionData->LogonId.HighPart
     232            && pCur->luid.LowPart  == pSessionData->LogonId.LowPart)
     233        {
     234            VBoxServiceVerbose(3, "Users: Session %ld:%ld has active processes\n",
     235                               pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);
     236            LsaFreeReturnBuffer(pSessionData);
     237            return 1;
     238        }         
     239        pCur++;
     240    }
     241    LsaFreeReturnBuffer(pSessionData);
     242    return 0;
     243}
     244
     245BOOL VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER a_pUserInfo,
     246                                    PLUID a_pSession)
     247{
    174248    BOOL bFoundUser = FALSE;
    175249    PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
     
    181255        return FALSE;
    182256
    183     r = LsaGetLogonSessionData (a_pSession, &sessionData);
     257    r = LsaGetLogonSessionData(a_pSession, &sessionData);
    184258    if (r != STATUS_SUCCESS)
    185259    {
     
    199273
    200274    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);
     275        (sessionData->UserName).Buffer,
     276        (sessionData->UserName).Length,
     277        (sessionData->Sid != NULL) ? "1" : "0", sessionData->LogonId.HighPart, sessionData->LogonId.LowPart);
    202278
    203279    if ((sessionData->UserName.Buffer != NULL) &&
     
    305381                    if (pBuffer)
    306382                        WTSFreeMemory(pBuffer);
    307 
    308                     /* A user logged in, but it could be a stale/orphaned logon session. */
    309                     BOOL bFoundInLUIDs = FALSE;
    310                     for (DWORD dwIndex = 0; dwIndex < a_dwNumOfProcLUIDs; dwIndex++)
    311                     {
    312                         if (   (a_pLuid[dwIndex].HighPart == sessionData->LogonId.HighPart)
    313                             && (a_pLuid[dwIndex].LowPart == sessionData->LogonId.LowPart))
    314                         {
    315                             bLoggedIn = TRUE;
    316                             VBoxServiceVerbose(3, "User \"%ls\" is logged in!\n", a_pUserInfo->szUser);
    317                             break;
    318                         }
    319                     }
    320383                }
    321384            }
     
    324387
    325388    LsaFreeReturnBuffer(sessionData);
    326     return bLoggedIn;
    327 }
    328 
     389    return bFoundUser;
     390}
    329391#endif /* TARGET_NT4 */
    330392
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp

    r26070 r26083  
    221221        }
    222222
    223         PLUID pLuid = NULL;
    224         DWORD dwNumOfProcLUIDs = VBoxServiceVMInfoWinGetLUIDsFromProcesses(&pLuid);
    225 
    226         for (int i = 0; i<(int)ulCount; i++)
    227         {
    228             VBOXSERVICEVMINFOUSER userInfo;
    229             ZeroMemory (&userInfo, sizeof(VBOXSERVICEVMINFOUSER));
    230 
    231             if (VBoxServiceVMInfoWinIsLoggedIn(&userInfo, &pSessions[i], pLuid, dwNumOfProcLUIDs))
     223        PVBOXSERVICEVMINFOPROC pProcs;
     224        DWORD dwNumProcs;
     225        rc = VBoxServiceVMInfoWinProcessesEnumerate(&pProcs, &dwNumProcs);
     226
     227        VBOXSERVICEVMINFOUSER userInfo;
     228        ZeroMemory (&userInfo, sizeof(VBOXSERVICEVMINFOUSER));
     229
     230        for (ULONG i=0; i<ulCount; i++)
     231        {
     232            if (   VBoxServiceVMInfoWinIsLoggedIn(&userInfo, &pSessions[i])
     233                && VBoxServiceVMInfoWinSessionGetProcessCount(&pSessions[i], pProcs, dwNumProcs) > 0)
    232234            {
    233235                if (uiUserCount > 0)
     
    242244        }
    243245
    244         if (NULL != pLuid)
    245             ::LocalFree (pLuid);
    246 
     246        VBoxServiceVMInfoWinProcessesFree(pProcs);
    247247        ::LsaFreeReturnBuffer(pSessions);
    248248# endif /* TARGET_NT4 */
Note: See TracChangeset for help on using the changeset viewer.

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