Helper.cpp revision e55433cb7d930b803d6aff5794b20e5e202ba1fd
2N/A/** @file
2N/A *
2N/A * VBoxGINA -- Windows Logon DLL for VirtualBox Helper Functions
2N/A *
2N/A * Copyright (C) 2006-2007 Oracle Corporation
2N/A *
2N/A * This file is part of VirtualBox Open Source Edition (OSE), as
2N/A * available from http://www.virtualbox.org. This file is free software;
2N/A * you can redistribute it and/or modify it under the terms of the GNU
2N/A * General Public License (GPL) as published by the Free Software
2N/A * Foundation, in version 2 as it comes in the "COPYING" file of the
2N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2N/A */
2N/A
2N/A#include <windows.h>
2N/A#include "winwlx.h"
2N/A#include "Helper.h"
2N/A#include "VBoxGINA.h"
2N/A
2N/A#include <VBox/VBoxGuest.h>
2N/A#include <VBox/VMMDev.h>
2N/A#include <iprt/string.h>
2N/A
2N/A/* the credentials */
2N/Awchar_t g_Username[VMMDEV_CREDENTIALS_SZ_SIZE];
2N/Awchar_t g_Password[VMMDEV_CREDENTIALS_SZ_SIZE];
2N/Awchar_t g_Domain[VMMDEV_CREDENTIALS_SZ_SIZE];
2N/A
2N/A
2N/AHANDLE getVBoxDriver(void)
2N/A{
2N/A static HANDLE sVBoxDriver = INVALID_HANDLE_VALUE;
2N/A if (sVBoxDriver == INVALID_HANDLE_VALUE)
2N/A {
2N/A sVBoxDriver = CreateFile(L"\\\\.\\VBoxGuest", /** @todo use define */
2N/A GENERIC_READ | GENERIC_WRITE,
2N/A FILE_SHARE_READ | FILE_SHARE_WRITE,
2N/A NULL,
2N/A OPEN_EXISTING,
2N/A FILE_ATTRIBUTE_NORMAL,
2N/A NULL);
2N/A if (sVBoxDriver == INVALID_HANDLE_VALUE)
2N/A Log(("VBoxGINA::sVBoxDriver: failed to open VBoxGuest driver, last error = %d\n", GetLastError()));
2N/A }
2N/A return sVBoxDriver;
2N/A}
2N/A
void credentialsReset(void)
{
RT_ZERO(g_Username);
RT_ZERO(g_Password);
RT_ZERO(g_Domain);
}
bool credentialsAvailable(void)
{
HANDLE vboxDriver = getVBoxDriver();
if (vboxDriver == INVALID_HANDLE_VALUE)
return false;
/* query the VMMDev whether there are credentials */
VMMDevCredentials vmmreqCredentials = {0};
vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqCredentials, VMMDevReq_QueryCredentials);
vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_QUERYPRESENCE;
DWORD cbReturned;
if (!DeviceIoControl(vboxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqCredentials)), &vmmreqCredentials, sizeof(vmmreqCredentials),
&vmmreqCredentials, sizeof(vmmreqCredentials), &cbReturned, NULL))
{
Log(("VBoxGINA::credentialsAvailable: error doing IOCTL, last error: %d\n", GetLastError()));
return false;
}
bool fAvailable = ((vmmreqCredentials.u32Flags & VMMDEV_CREDENTIALS_PRESENT) != 0);
/*Log(("VBoxGINA::credentialsAvailable: fAvailable: %d\n", fAvailable));*/
return fAvailable;
}
bool credentialsRetrieve(void)
{
Log(("VBoxGINA::credentialsRetrieve\n"));
HANDLE vboxDriver = getVBoxDriver();
if (vboxDriver == INVALID_HANDLE_VALUE)
return false;
/* to be safe, reset the credentials */
credentialsReset();
/* query the credentials */
VMMDevCredentials vmmreqCredentials = {0};
vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqCredentials, VMMDevReq_QueryCredentials);
vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_READ;
vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_CLEAR;
DWORD cbReturned;
if (!DeviceIoControl(vboxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqCredentials)), &vmmreqCredentials, sizeof(vmmreqCredentials),
&vmmreqCredentials, sizeof(vmmreqCredentials), &cbReturned, NULL))
{
Log(("VBoxGINA::credentialsRetrieve: error doing IOCTL, last error: %d\n", GetLastError()));
return false;
}
/* convert from UTF-8 to UTF-16 and store in global variables */
PRTUTF16 ptr = NULL;
if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szUserName, &ptr)) && ptr)
{
wcscpy(g_Username, ptr);
RTUtf16Free(ptr);
}
ptr = NULL;
if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szPassword, &ptr)) && ptr)
{
wcscpy(g_Password, ptr);
RTUtf16Free(ptr);
}
ptr = NULL;
if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szDomain, &ptr)) && ptr)
{
wcscpy(g_Domain, ptr);
RTUtf16Free(ptr);
}
Log(("VBoxGINA::credentialsRetrieve: returning user '%s', password '%s', domain '%s'\n",
vmmreqCredentials.szUserName, vmmreqCredentials.szPassword, vmmreqCredentials.szDomain));
return true;
}
/* handle of the poller thread */
RTTHREAD gThreadPoller = NIL_RTTHREAD;
/**
* Poller thread. Checks periodically whether there are credentials.
*/
static DECLCALLBACK(int) credentialsPoller(RTTHREAD ThreadSelf, void *pvUser)
{
Log(("VBoxGINA::credentialsPoller\n"));
do
{
if (credentialsAvailable())
{
Log(("VBoxGINA::credentialsPoller: got credentials, simulating C-A-D\n"));
/* tell WinLogon to start the attestation process */
pWlxFuncs->WlxSasNotify(hGinaWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
/* time to say goodbye */
return 0;
}
/* wait a bit */
if (RTThreadUserWait(ThreadSelf, 500) == VINF_SUCCESS)
{
Log(("VBoxGINA::credentialsPoller: we were asked to terminate\n"));
/* we were asked to terminate, do that instantly! */
return 0;
}
}
while (1);
return 0;
}
bool credentialsPollerCreate(void)
{
Log(("VBoxGINA::credentialsPollerCreate\n"));
/* don't create more than one of them */
if (gThreadPoller != NIL_RTTHREAD)
{
Log(("VBoxGINA::credentialsPollerCreate: thread already running, returning!\n"));
return false;
}
/* create the poller thread */
int rc = RTThreadCreate(&gThreadPoller, credentialsPoller, NULL, 0, RTTHREADTYPE_INFREQUENT_POLLER,
RTTHREADFLAGS_WAITABLE, "creds");
if (RT_FAILURE(rc))
{
Log(("VBoxGINA::credentialsPollerCreate: failed to create thread, rc = %Rrc\n", rc));
return false;
}
return true;
}
bool credentialsPollerTerminate(void)
{
Log(("VBoxGINA::credentialsPollerTerminate\n"));
if (gThreadPoller == NIL_RTTHREAD)
{
Log(("VBoxGINA::credentialsPollerTerminate: either thread or exit sem is NULL!\n"));
return false;
}
/* post termination event semaphore */
int rc = RTThreadUserSignal(gThreadPoller);
if (RT_SUCCESS(rc))
{
Log(("VBoxGINA::credentialsPollerTerminate: waiting for thread to terminate\n"));
/* wait until the thread has terminated */
rc = RTThreadWait(gThreadPoller, RT_INDEFINITE_WAIT, NULL);
Log(("VBoxGINA::credentialsPollerTermiante: thread has (probably) terminated (rc = %Rrc)\n", rc));
}
else
{
/* failed to signal the thread - very unlikely - so no point in waiting long. */
Log(("VBoxGINA::credentialsPollerTermiante: failed to signal semaphore, rc = %Rrc\n", rc));
rc = RTThreadWait(gThreadPoller, 100, NULL);
Log(("VBoxGINA::credentialsPollerTermiante: thread has terminated? wait rc = %Rrc\n", rc));
}
/* now cleanup */
gThreadPoller = NIL_RTTHREAD;
return true;
}