VBoxGINA.cpp revision be603ce3cb13b5ee7f4c3d85ea27ff41ac294535
/** @file
*
* VBoxGINA -- Windows Logon DLL for VirtualBox
*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <iprt/buildconfig.h>
#include <iprt/initterm.h>
#include <VBox/VBoxGuestLib.h>
#include "winwlx.h"
#include "VBoxGINA.h"
#include "Helper.h"
#include "Dialog.h"
/*
* Global variables.
*/
/** DLL instance handle. */
/** Version of Winlogon. */
/** Handle to Winlogon service. */
/** Winlog function dispatch table. */
/**
* Function pointers to MSGINA entry points.
*/
/* GINA 1.1. */
/* GINA 1.3. */
/* GINA 1.4. */
/**
* DLL entry point.
*/
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
RTR3InitDll(0 /* Flags */);
VbglR3Init();
VBoxGINAVerbose(0, "VBoxGINA: v%s r%s (%s %s) loaded\n",
break;
}
case DLL_PROCESS_DETACH:
{
VBoxGINAVerbose(0, "VBoxGINA: Unloaded\n");
VbglR3Term();
/// @todo RTR3Term();
break;
}
default:
break;
}
return TRUE;
}
{
/* Load the standard Microsoft GINA DLL. */
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed loading MSGINA! Last error=%ld\n", GetLastError());
return FALSE;
}
/*
* Now get the entry points of the MSGINA
*/
if (!GWlxNegotiate)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxNegotiate\n");
return FALSE;
}
if (!GWlxInitialize)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxInitialize\n");
return FALSE;
}
if (!GWlxDisplaySASNotice)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxDisplaySASNotice\n");
return FALSE;
}
if (!GWlxLoggedOutSAS)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxLoggedOutSAS\n");
return FALSE;
}
if (!GWlxActivateUserShell)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxActivateUserShell\n");
return FALSE;
}
if (!GWlxLoggedOnSAS)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxLoggedOnSAS\n");
return FALSE;
}
if (!GWlxDisplayLockedNotice)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxDisplayLockedNotice\n");
return FALSE;
}
if (!GWlxIsLockOk)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxIsLockOk\n");
return FALSE;
}
if (!GWlxWkstaLockedSAS)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxWkstaLockedSAS\n");
return FALSE;
}
if (!GWlxIsLogoffOk)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxIsLogoffOk\n");
return FALSE;
}
if (!GWlxLogoff)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxLogoff\n");
return FALSE;
}
if (!GWlxShutdown)
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: failed resolving WlxShutdown\n");
return FALSE;
}
/* GINA 1.1, optional */
/* GINA 1.3, optional */
GWlxNetworkProviderLoad = (PGWLXNETWORKPROVIDERLOAD)GetProcAddress( hDll, "WlxNetworkProviderLoad");
GWlxDisplayStatusMessage = (PGWLXDISPLAYSTATUSMESSAGE)GetProcAddress( hDll, "WlxDisplayStatusMessage");
GWlxRemoveStatusMessage = (PGWLXREMOVESTATUSMESSAGE)GetProcAddress( hDll, "WlxRemoveStatusMessage");
/* GINA 1.4, optional */
VBoxGINAVerbose(0, "VBoxGINA::WlxNegotiate: optional function pointers:\n"
" WlxStartApplication: %p\n"
" WlxScreenSaverNotify: %p\n"
" WlxNetworkProviderLoad: %p\n"
" WlxDisplayStatusMessage: %p\n"
" WlxGetStatusMessage: %p\n"
" WlxRemoveStatusMessage: %p\n"
" WlxGetConsoleSwitchCredentials: %p\n"
" WlxReconnectNotify: %p\n"
" WlxDisconnectNotify: %p\n",
/* Acknowledge interface version. */
if (pdwDllVersion)
return TRUE; /* We're ready to rumble! */
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxInitialize\n");
/* Store Winlogon function table */
/* Store handle to Winlogon service*/
/* Hook the dialogs */
/* Forward call */
if (GWlxInitialize)
return TRUE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplaySASNotice\n");
/* Check if there are credentials for us, if so simulate C-A-D */
int rc = VbglR3CredentialsQueryAvailability();
if (RT_SUCCESS(rc))
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplaySASNotice: simulating C-A-D\n");
/* Wutomatic C-A-D */
}
else
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplaySASNotice: starting credentials poller\n");
/* start the credentials poller thread */
/* Forward call to MSGINA. */
if (GWlxDisplaySASNotice)
}
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxLoggedOutSAS\n");
/* When performing a direct logon without C-A-D, our poller might not be running */
int rc = VbglR3CredentialsQueryAvailability();
if (RT_FAILURE(rc))
if (GWlxLoggedOutSAS)
{
int iRet;
if (iRet == WLX_SAS_ACTION_LOGON)
{
//
// Copy pMprNotifyInfo and pLogonSid for later use
//
// pMprNotifyInfo->pszUserName
// pMprNotifyInfo->pszDomain
// pMprNotifyInfo->pszPassword
// pMprNotifyInfo->pszOldPassword
}
return iRet;
}
return WLX_SAS_ACTION_NONE;
}
/**
* WinLogon calls this function following a successful logon to request that the GINA activate the user's shell program.
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxActivateUserShell\n");
/*
* Report status "terminated" to the host -- this means that a user
* got logged in (either manually or automatically using the provided credentials).
*/
/* Forward call to MSGINA. */
return TRUE; /* Activate the user shell. */
}
{
/*
* We don't want to do anything special here since the OS should behave
* as VBoxGINA wouldn't have been installed. So pass all calls down
* to the original MSGINA.
*/
/* Forward call to MSGINA. */
VBoxGINAVerbose(0, "VBoxGINA::WlxLoggedOnSAS: Forwarding call to MSGINA ...\n");
if (GWlxLoggedOnSAS)
return WLX_SAS_ACTION_NONE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplayLockedNotice\n");
/* Check if there are credentials for us, if so simulate C-A-D */
int rc = VbglR3CredentialsQueryAvailability();
if (RT_SUCCESS(rc))
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplayLockedNotice: simulating C-A-D\n");
/* Automatic C-A-D */
}
else
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplayLockedNotice: starting credentials poller\n");
/* start the credentials poller thread */
/* Forward call to MSGINA. */
}
}
/*
* Winlogon calls this function before it attempts to lock the workstation.
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxIsLockOk\n");
/* Forward call to MSGINA. */
if (GWlxIsLockOk)
return GWlxIsLockOk(pWlxContext);
return TRUE; /* Locking is OK. */
}
{
/* When performing a direct logon without C-A-D, our poller might not be running */
int rc = VbglR3CredentialsQueryAvailability();
if (RT_FAILURE(rc))
/* Forward call to MSGINA. */
if (GWlxWkstaLockedSAS)
return WLX_SAS_ACTION_NONE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxIsLogoffOk\n");
if (GWlxIsLogoffOk)
return GWlxIsLogoffOk(pWlxContext);
return TRUE; /* Log off is OK. */
}
/*
* Winlogon calls this function to notify the GINA of a logoff operation on this
* workstation. This allows the GINA to perform any logoff operations that may be required.
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxLogoff\n");
/* No need to report the "active" status to the host here -- this will be done
* when VBoxGINA gets the chance to hook the dialogs (again). */
/* Forward call to MSGINA. */
if (GWlxLogoff)
}
/*
* Winlogon calls this function just before shutting down.
* This allows the GINA to perform any necessary shutdown tasks.
* Will be called *after* WlxLogoff!
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxShutdown\n");
/*
* Report status "inactive" to the host -- this means the
* auto-logon feature won't be active anymore at this point
* (until it maybe gets loaded again after a reboot).
*/
/* Forward call to MSGINA. */
if (GWlxShutdown)
}
/*
* GINA 1.1 entry points
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxScreenSaverNotify, pSecure=%d\n",
/* Report the status to "init" since the screensaver
* (Winlogon) does not give VBoxGINA yet the chance to hook into dialogs
* which only then in turn would set the status to "active" -- so
* at least set some status here. */
/* Note: Disabling the screensaver's grace period is necessary to get
* VBoxGINA loaded and set the status to "terminated" again properly
* after the logging-in handling was done. To do this:
* - on a non-domain machine, set:
* HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ScreenSaverGracePeriod (REG_SZ)
* to "0"
* - on a machine joined a domain:
* depending on the domain's policies.
*/
/* Indicate that the workstation should be locked. */
return TRUE; /* Screensaver should be activated. */
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxStartApplication: pWlxCtx=%p, pszDesktopName=%ls, pEnvironment=%p, pszCmdLine=%ls\n",
/* Forward to MSGINA if present. */
if (GWlxStartApplication)
return FALSE;
}
/*
* GINA 1.3 entry points
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxNetworkProviderLoad\n");
/* Forward to MSGINA if present. */
return FALSE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisplayStatusMessage\n");
/* Forward to MSGINA if present. */
return FALSE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxGetStatusMessage\n");
/* Forward to MSGINA if present. */
if (GWlxGetStatusMessage)
return FALSE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxRemoveStatusMessage\n");
/* Forward to MSGINA if present. */
return GWlxRemoveStatusMessage(pWlxContext);
return FALSE;
}
/*
* GINA 1.4 entry points
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WlxGetConsoleSwitchCredentials\n");
/* Forward call to MSGINA if present */
return FALSE;
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxReconnectNotify\n");
/* Forward to MSGINA if present. */
if (GWlxReconnectNotify)
}
{
VBoxGINAVerbose(0, "VBoxGINA::WlxDisconnectNotify\n");
/* Forward to MSGINA if present. */
if (GWlxDisconnectNotify)
}
/*
* Windows Notification Package callbacks
*/
{
VBoxGINAVerbose(0, "VBoxGINA::WnpScreenSaverStop\n");
/*
* Because we set the status to "init" in WlxScreenSaverNotify when
* the screensaver becomes active we also have to take into account
* that in case the screensaver terminates (either within the grace
* period or because the lock screen appears) we have to set the
* status accordingly.
*/
}
{
#ifdef DEBUG
if (!fRes)
return 1;
void* pWlxContext = NULL;
fRes = WlxInitialize(0, 0,
NULL /* Reserved */,
NULL /* Winlogon functions */,
&pWlxContext);
if (!fRes)
return 2;
void* pvProfile;
return iRes;
#else
return 0;
#endif
}