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