VirtualBox

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

Last change on this file since 39764 was 39759, checked in by vboxsync, 13 years ago

VBoxGINA + VBoxCredProv: Let the release log know about credential retrieval.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/* $Id: Helper.cpp 39759 2012-01-12 11:58:14Z 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 /* Do not report back an error here yet. */
91 return ERROR_SUCCESS;
92}
93
94/**
95 * Determines whether we should handle the current session or not.
96 *
97 * @return bool true if we should handle this session, false if not.
98 */
99bool handleCurrentSession(void)
100{
101 /* Load global configuration from registry. */
102 DWORD dwRet = loadConfiguration();
103 if (ERROR_SUCCESS != dwRet)
104 LogRel(("VBoxGINA::handleCurrentSession: Error loading global configuration, error=%ld\n", dwRet));
105
106 bool fHandle = false;
107 if (isRemoteSession())
108 {
109 if (g_dwHandleRemoteSessions) /* Force remote session handling. */
110 fHandle = true;
111 }
112 else /* No remote session. */
113 fHandle = true;
114
115 if (!fHandle)
116 LogRel(("VBoxGINA::handleCurrentSession: Handling of remote desktop sessions is disabled.\n"));
117
118 return fHandle;
119}
120
121void credentialsReset(void)
122{
123 RT_ZERO(g_Username);
124 RT_ZERO(g_Password);
125 RT_ZERO(g_Domain);
126}
127
128bool credentialsAvailable(void)
129{
130 if (!handleCurrentSession())
131 return false;
132
133 HANDLE vboxDriver = getVBoxDriver();
134 if (vboxDriver == INVALID_HANDLE_VALUE)
135 return false;
136
137 /* query the VMMDev whether there are credentials */
138 VMMDevCredentials vmmreqCredentials = {0};
139 vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqCredentials, VMMDevReq_QueryCredentials);
140 vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_QUERYPRESENCE;
141 DWORD cbReturned;
142 if (!DeviceIoControl(vboxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqCredentials)), &vmmreqCredentials, sizeof(vmmreqCredentials),
143 &vmmreqCredentials, sizeof(vmmreqCredentials), &cbReturned, NULL))
144 {
145 Log(("VBoxGINA::credentialsAvailable: error doing IOCTL, last error: %d\n", GetLastError()));
146 return false;
147 }
148 bool fAvailable = ((vmmreqCredentials.u32Flags & VMMDEV_CREDENTIALS_PRESENT) != 0);
149 /*Log(("VBoxGINA::credentialsAvailable: fAvailable: %d\n", fAvailable));*/
150 return fAvailable;
151}
152
153bool credentialsRetrieve(void)
154{
155 if (!handleCurrentSession())
156 return false;
157
158 Log(("VBoxGINA::credentialsRetrieve\n"));
159
160 HANDLE vboxDriver = getVBoxDriver();
161 if (vboxDriver == INVALID_HANDLE_VALUE)
162 return false;
163
164 /* to be safe, reset the credentials */
165 credentialsReset();
166
167 /* query the credentials */
168 VMMDevCredentials vmmreqCredentials = {0};
169 vmmdevInitRequest((VMMDevRequestHeader*)&vmmreqCredentials, VMMDevReq_QueryCredentials);
170 vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_READ;
171 vmmreqCredentials.u32Flags |= VMMDEV_CREDENTIALS_CLEAR;
172 DWORD cbReturned;
173 if (!DeviceIoControl(vboxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(vmmreqCredentials)), &vmmreqCredentials, sizeof(vmmreqCredentials),
174 &vmmreqCredentials, sizeof(vmmreqCredentials), &cbReturned, NULL))
175 {
176 Log(("VBoxGINA::credentialsRetrieve: error doing IOCTL, last error: %d\n", GetLastError()));
177 return false;
178 }
179 /* convert from UTF-8 to UTF-16 and store in global variables */
180 PRTUTF16 ptr = NULL;
181 if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szUserName, &ptr)) && ptr)
182 {
183 wcscpy(g_Username, ptr);
184 RTUtf16Free(ptr);
185 }
186 ptr = NULL;
187 if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szPassword, &ptr)) && ptr)
188 {
189 wcscpy(g_Password, ptr);
190 RTUtf16Free(ptr);
191 }
192 ptr = NULL;
193 if (RT_SUCCESS(RTStrToUtf16(vmmreqCredentials.szDomain, &ptr)) && ptr)
194 {
195 wcscpy(g_Domain, ptr);
196 RTUtf16Free(ptr);
197 }
198 Log(("VBoxGINA::credentialsRetrieve: returning user '%s', password '%s', domain '%s'\n",
199 vmmreqCredentials.szUserName, vmmreqCredentials.szPassword, vmmreqCredentials.szDomain));
200
201 /* Let the release log know that we got something. */
202 LogRel(("VBoxGINA: Credentials from host retrieved\n"));
203
204 return true;
205}
206
207/* handle of the poller thread */
208RTTHREAD gThreadPoller = NIL_RTTHREAD;
209
210
211/**
212 * Poller thread. Checks periodically whether there are credentials.
213 */
214static DECLCALLBACK(int) credentialsPoller(RTTHREAD ThreadSelf, void *pvUser)
215{
216 Log(("VBoxGINA::credentialsPoller\n"));
217
218 do
219 {
220 if (credentialsAvailable())
221 {
222 Log(("VBoxGINA::credentialsPoller: got credentials, simulating C-A-D\n"));
223 /* tell WinLogon to start the attestation process */
224 pWlxFuncs->WlxSasNotify(hGinaWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
225 /* time to say goodbye */
226 return 0;
227 }
228 /* wait a bit */
229 if (RTThreadUserWait(ThreadSelf, 500) == VINF_SUCCESS)
230 {
231 Log(("VBoxGINA::credentialsPoller: we were asked to terminate\n"));
232 /* we were asked to terminate, do that instantly! */
233 return 0;
234 }
235 }
236 while (1);
237
238 return 0;
239}
240
241bool credentialsPollerCreate(void)
242{
243 if (!handleCurrentSession())
244 return false;
245
246 Log(("VBoxGINA::credentialsPollerCreate\n"));
247
248 /* don't create more than one of them */
249 if (gThreadPoller != NIL_RTTHREAD)
250 {
251 Log(("VBoxGINA::credentialsPollerCreate: thread already running, returning!\n"));
252 return false;
253 }
254
255 /* create the poller thread */
256 int rc = RTThreadCreate(&gThreadPoller, credentialsPoller, NULL, 0, RTTHREADTYPE_INFREQUENT_POLLER,
257 RTTHREADFLAGS_WAITABLE, "creds");
258 if (RT_FAILURE(rc))
259 {
260 Log(("VBoxGINA::credentialsPollerCreate: failed to create thread, rc = %Rrc\n", rc));
261 return false;
262 }
263 return true;
264}
265
266bool credentialsPollerTerminate(void)
267{
268 Log(("VBoxGINA::credentialsPollerTerminate\n"));
269
270 if (gThreadPoller == NIL_RTTHREAD)
271 {
272 Log(("VBoxGINA::credentialsPollerTerminate: either thread or exit sem is NULL!\n"));
273 return false;
274 }
275 /* post termination event semaphore */
276 int rc = RTThreadUserSignal(gThreadPoller);
277 if (RT_SUCCESS(rc))
278 {
279 Log(("VBoxGINA::credentialsPollerTerminate: waiting for thread to terminate\n"));
280 /* wait until the thread has terminated */
281 rc = RTThreadWait(gThreadPoller, RT_INDEFINITE_WAIT, NULL);
282 Log(("VBoxGINA::credentialsPollerTermiante: thread has (probably) terminated (rc = %Rrc)\n", rc));
283 }
284 else
285 {
286 /* failed to signal the thread - very unlikely - so no point in waiting long. */
287 Log(("VBoxGINA::credentialsPollerTermiante: failed to signal semaphore, rc = %Rrc\n", rc));
288 rc = RTThreadWait(gThreadPoller, 100, NULL);
289 Log(("VBoxGINA::credentialsPollerTermiante: thread has terminated? wait rc = %Rrc\n", rc));
290 }
291 /* now cleanup */
292 gThreadPoller = NIL_RTTHREAD;
293 return true;
294}
295
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