VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxGINA/Helper.cpp@ 36446

Last change on this file since 36446 was 36446, checked in by vboxsync, 14 years ago

VBoxGINA: Implemented support for handling/ignoring remote (desktop) sessions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 KB
Line 
1/* $Id: Helper.cpp 36446 2011-03-28 09:42:12Z vboxsync $ */
2/** @file
3 * VBoxGINA - Windows Logon DLL for VirtualBox, Helper Functions.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <windows.h>
19#include "winwlx.h"
20#include "Helper.h"
21#include "VBoxGINA.h"
22
23#include <VBox/VBoxGuest.h>
24#include <VBox/VMMDev.h>
25#include <iprt/string.h>
26
27/* remote session handling */
28DWORD g_dwHandleRemoteSessions = 0;
29
30/* the credentials */
31wchar_t g_Username[VMMDEV_CREDENTIALS_SZ_SIZE];
32wchar_t g_Password[VMMDEV_CREDENTIALS_SZ_SIZE];
33wchar_t g_Domain[VMMDEV_CREDENTIALS_SZ_SIZE];
34
35
36HANDLE getVBoxDriver(void)
37{
38 static HANDLE sVBoxDriver = INVALID_HANDLE_VALUE;
39 if (sVBoxDriver == INVALID_HANDLE_VALUE)
40 {
41 sVBoxDriver = CreateFile(L"\\\\.\\VBoxGuest", /** @todo use define */
42 GENERIC_READ | GENERIC_WRITE,
43 FILE_SHARE_READ | FILE_SHARE_WRITE,
44 NULL,
45 OPEN_EXISTING,
46 FILE_ATTRIBUTE_NORMAL,
47 NULL);
48 if (sVBoxDriver == INVALID_HANDLE_VALUE)
49 Log(("VBoxGINA::sVBoxDriver: failed to open VBoxGuest driver, last error = %d\n", GetLastError()));
50 }
51 return sVBoxDriver;
52}
53
54/**
55 * Detects whether our process is running in a remote session or not.
56 *
57 * @return bool true if running in a remote session, false if not.
58 */
59bool isRemoteSession(void)
60{
61 return (0 != GetSystemMetrics(SM_REMOTESESSION)) ? true : false;
62}
63
64/**
65 * Loads the global configuration from registry.
66 *
67 * @return DWORD Windows error code.
68 */
69DWORD loadConfiguration(void)
70{
71 HKEY hKey;
72 /** @todo Add some registry wrapper function(s) as soon as we got more values to retrieve. */
73 DWORD dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Oracle\\VirtualBox Guest Additions\\AutoLogon",
74 0L, KEY_QUERY_VALUE, &hKey);
75 if (dwRet == ERROR_SUCCESS)
76 {
77 DWORD dwValue;
78 DWORD dwType = REG_DWORD;
79 DWORD dwSize = sizeof(DWORD);
80
81 dwRet = RegQueryValueEx(hKey, L"HandleRemoteSessions", NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
82 if ( dwRet == ERROR_SUCCESS
83 && dwType == REG_DWORD
84 && dwSize == sizeof(DWORD))
85 {
86 g_dwHandleRemoteSessions = dwValue;
87 }
88 RegCloseKey(hKey);
89 }
90 return dwRet;
91}
92
93/**
94 * Determines whether we should handle the current session or not.
95 *
96 * @return bool true if we should handle this session, false if not.
97 */
98bool handleCurrentSession(void)
99{
100 bool fHandle = false;
101 if (isRemoteSession())
102 {
103 if (g_dwHandleRemoteSessions) /* Force remote session handling. */
104 fHandle = true;
105 }
106 else /* No remote session. */
107 fHandle = true;
108 return fHandle;
109}
110
111void credentialsReset(void)
112{
113 RT_ZERO(g_Username);
114 RT_ZERO(g_Password);
115 RT_ZERO(g_Domain);
116}
117
118bool credentialsAvailable(void)
119{
120 if (!handleCurrentSession())
121 return false;
122
123 HANDLE vboxDriver = getVBoxDriver();
124 if (vboxDriver == INVALID_HANDLE_VALUE)
125 return false;
126
127 /* query the VMMDev whether there are credentials */
128 VMMDevCredentials vmmreqCredentials = {0};
129 vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqCredentials, VMMDevReq_QueryCredentials);
130 vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_QUERYPRESENCE;
131 DWORD cbReturned;
132 if (!DeviceIoControl(vboxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqCredentials)), &vmmreqCredentials, sizeof(vmmreqCredentials),
133 &vmmreqCredentials, sizeof(vmmreqCredentials), &cbReturned, NULL))
134 {
135 Log(("VBoxGINA::credentialsAvailable: error doing IOCTL, last error: %d\n", GetLastError()));
136 return false;
137 }
138 bool fAvailable = ((vmmreqCredentials.u32Flags & VMMDEV_CREDENTIALS_PRESENT) != 0);
139 /*Log(("VBoxGINA::credentialsAvailable: fAvailable: %d\n", fAvailable));*/
140 return fAvailable;
141}
142
143bool credentialsRetrieve(void)
144{
145 if (!handleCurrentSession())
146 return false;
147
148 Log(("VBoxGINA::credentialsRetrieve\n"));
149
150 HANDLE vboxDriver = getVBoxDriver();
151 if (vboxDriver == INVALID_HANDLE_VALUE)
152 return false;
153
154 /* to be safe, reset the credentials */
155 credentialsReset();
156
157 /* query the credentials */
158 VMMDevCredentials vmmreqCredentials = {0};
159 vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqCredentials, VMMDevReq_QueryCredentials);
160 vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_READ;
161 vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_CLEAR;
162 DWORD cbReturned;
163 if (!DeviceIoControl(vboxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqCredentials)), &vmmreqCredentials, sizeof(vmmreqCredentials),
164 &vmmreqCredentials, sizeof(vmmreqCredentials), &cbReturned, NULL))
165 {
166 Log(("VBoxGINA::credentialsRetrieve: error doing IOCTL, last error: %d\n", GetLastError()));
167 return false;
168 }
169 /* convert from UTF-8 to UTF-16 and store in global variables */
170 PRTUTF16 ptr = NULL;
171 if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szUserName, &ptr)) && ptr)
172 {
173 wcscpy(g_Username, ptr);
174 RTUtf16Free(ptr);
175 }
176 ptr = NULL;
177 if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szPassword, &ptr)) && ptr)
178 {
179 wcscpy(g_Password, ptr);
180 RTUtf16Free(ptr);
181 }
182 ptr = NULL;
183 if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szDomain, &ptr)) && ptr)
184 {
185 wcscpy(g_Domain, ptr);
186 RTUtf16Free(ptr);
187 }
188 Log(("VBoxGINA::credentialsRetrieve: returning user '%s', password '%s', domain '%s'\n",
189 vmmreqCredentials.szUserName, vmmreqCredentials.szPassword, vmmreqCredentials.szDomain));
190 return true;
191}
192
193/* handle of the poller thread */
194RTTHREAD gThreadPoller = NIL_RTTHREAD;
195
196
197/**
198 * Poller thread. Checks periodically whether there are credentials.
199 */
200static DECLCALLBACK(int) credentialsPoller(RTTHREAD ThreadSelf, void *pvUser)
201{
202 Log(("VBoxGINA::credentialsPoller\n"));
203
204 do
205 {
206 if (credentialsAvailable())
207 {
208 Log(("VBoxGINA::credentialsPoller: got credentials, simulating C-A-D\n"));
209 /* tell WinLogon to start the attestation process */
210 pWlxFuncs->WlxSasNotify(hGinaWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
211 /* time to say goodbye */
212 return 0;
213 }
214 /* wait a bit */
215 if (RTThreadUserWait(ThreadSelf, 500) == VINF_SUCCESS)
216 {
217 Log(("VBoxGINA::credentialsPoller: we were asked to terminate\n"));
218 /* we were asked to terminate, do that instantly! */
219 return 0;
220 }
221 }
222 while (1);
223
224 return 0;
225}
226
227bool credentialsPollerCreate(void)
228{
229 if (!handleCurrentSession())
230 return false;
231
232 Log(("VBoxGINA::credentialsPollerCreate\n"));
233
234 /* don't create more than one of them */
235 if (gThreadPoller != NIL_RTTHREAD)
236 {
237 Log(("VBoxGINA::credentialsPollerCreate: thread already running, returning!\n"));
238 return false;
239 }
240
241 /* create the poller thread */
242 int rc = RTThreadCreate(&gThreadPoller, credentialsPoller, NULL, 0, RTTHREADTYPE_INFREQUENT_POLLER,
243 RTTHREADFLAGS_WAITABLE, "creds");
244 if (RT_FAILURE(rc))
245 {
246 Log(("VBoxGINA::credentialsPollerCreate: failed to create thread, rc = %Rrc\n", rc));
247 return false;
248 }
249 return true;
250}
251
252bool credentialsPollerTerminate(void)
253{
254 Log(("VBoxGINA::credentialsPollerTerminate\n"));
255
256 if (gThreadPoller == NIL_RTTHREAD)
257 {
258 Log(("VBoxGINA::credentialsPollerTerminate: either thread or exit sem is NULL!\n"));
259 return false;
260 }
261 /* post termination event semaphore */
262 int rc = RTThreadUserSignal(gThreadPoller);
263 if (RT_SUCCESS(rc))
264 {
265 Log(("VBoxGINA::credentialsPollerTerminate: waiting for thread to terminate\n"));
266 /* wait until the thread has terminated */
267 rc = RTThreadWait(gThreadPoller, RT_INDEFINITE_WAIT, NULL);
268 Log(("VBoxGINA::credentialsPollerTermiante: thread has (probably) terminated (rc = %Rrc)\n", rc));
269 }
270 else
271 {
272 /* failed to signal the thread - very unlikely - so no point in waiting long. */
273 Log(("VBoxGINA::credentialsPollerTermiante: failed to signal semaphore, rc = %Rrc\n", rc));
274 rc = RTThreadWait(gThreadPoller, 100, NULL);
275 Log(("VBoxGINA::credentialsPollerTermiante: thread has terminated? wait rc = %Rrc\n", rc));
276 }
277 /* now cleanup */
278 gThreadPoller = NIL_RTTHREAD;
279 return true;
280}
281
Note: See TracBrowser for help on using the repository browser.

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