VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/SharedFolders/driver/net.cpp@ 78304

Last change on this file since 78304 was 78304, checked in by vboxsync, 6 years ago

winnt/vboxsf: Use g_SfClient everywhere to avoid having dangling pointers (MRX_VBOX_NETROOT_EXTENSION::phgcmClient) and copies (MRX_VBOX_DEVICE_EXTENSION::hgcmClient). This also reduces the stack space usage. ASSUMES that the module can only be instantiated once (already an assumption of the g_SfClient variable and related code in VBoxGuestLibSharedFoldersInline.h). Renamed all sources to .cpp (except the w2k hacks). bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
Line 
1/* $Id: net.cpp 78304 2019-04-26 01:19:49Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Shared Folders - File System Driver network redirector subsystem routines
4 */
5
6/*
7 * Copyright (C) 2012-2019 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 "vbsf.h"
19
20NTSTATUS VBoxMRxUpdateNetRootState(IN OUT PMRX_NET_ROOT pNetRoot)
21{
22 RT_NOREF(pNetRoot);
23 Log(("VBOXSF: MRxUpdateNetRootState\n"));
24 return STATUS_NOT_IMPLEMENTED;
25}
26
27static void vbsfUpdateNetRoot(PMRX_NET_ROOT pNetRoot)
28{
29 Log(("VBOXSF: vbsfUpdateNetRoot: NetRoot = 0x%x Type = 0x%x\n",
30 pNetRoot, pNetRoot->Type));
31
32 switch (pNetRoot->Type)
33 {
34 case NET_ROOT_DISK:
35 pNetRoot->DeviceType = RxDeviceType(DISK);
36 break;
37 case NET_ROOT_PIPE:
38 pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
39 break;
40 case NET_ROOT_COMM:
41 pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
42 break;
43 case NET_ROOT_PRINT:
44 pNetRoot->DeviceType = RxDeviceType(PRINTER);
45 break;
46 case NET_ROOT_MAILSLOT:
47 pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
48 break;
49 case NET_ROOT_WILD:
50 /* We get this type when for example Windows Media player opens an MP3 file.
51 * This NetRoot has the same remote path (\\vboxsrv\dir) as other NetRoots,
52 * which were created earlier and which were NET_ROOT_DISK.
53 *
54 * In the beginning of the function (UpdateNetRoot) the DDK sample sets
55 * pNetRoot->Type of newly created NetRoots using a value previously
56 * pstored in a NetRootExtension. One NetRootExtensions is used for a single
57 * remote path and reused by a few NetRoots, if they point to the same path.
58 *
59 * To simplify things we just set the type to DISK here (we do not support
60 * anything else anyway), and update the DeviceType correspondingly.
61 */
62 pNetRoot->Type = NET_ROOT_DISK;
63 pNetRoot->DeviceType = RxDeviceType(DISK);
64 break;
65 default:
66 AssertMsgFailed(("VBOXSF: vbsfUpdateNetRoot: Invalid net root type! Type = 0x%x\n",
67 pNetRoot->Type));
68 break;
69 }
70
71 Log(("VBOXSF: vbsfUpdateNetRoot: leaving pNetRoot->DeviceType = 0x%x\n",
72 pNetRoot->DeviceType));
73}
74
75NTSTATUS VBoxMRxCreateVNetRoot(IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
76{
77 NTSTATUS Status;
78
79 PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
80
81 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot);
82
83 PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
84 PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
85
86 BOOLEAN fInitializeNetRoot = FALSE;
87
88 Log(("VBOXSF: MRxCreateVNetRoot: pNetRoot = %p, pNetRootExtension = %p, name = [%.*ls]\n",
89 pNetRoot, pNetRootExtension, pNetRoot->pNetRootName->Length / sizeof(WCHAR), pNetRoot->pNetRootName->Buffer));
90
91 /* IMPORTANT:
92 *
93 * This function must always call 'pCreateNetRootContext->Callback(pCreateNetRootContext)' before
94 * returning and then return STATUS_PENDING. Otherwise Win64 will hang.
95 */
96
97 if (pNetRoot->Type == NET_ROOT_PIPE)
98 {
99 /* VBoxSF claims everything which starts with '\vboxsrv'.
100 *
101 * So sometimes the system tries to open \vboxsrv\ipc$ pipe for DFS
102 * and fails the application call if an unexpected code is returned.
103 *
104 * According to MSDN: The Windows client returns STATUS_MORE_PROCESSING_REQUIRED to the calling
105 * application to indicate that the path does not correspond to a DFS Namespace.
106 */
107 pVNetRoot->Context = NULL;
108
109 if (pNetRoot->pNetRootName->Length >= 13 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv\ipc$' unicode string. */
110 {
111 const WCHAR *Suffix = &pNetRoot->pNetRootName->Buffer[8]; /* Number of chars in '\vboxsrv' */
112
113 if ( Suffix[0] == L'\\'
114 && (Suffix[1] == L'I' || Suffix[1] == L'i')
115 && (Suffix[2] == L'P' || Suffix[2] == L'p')
116 && (Suffix[3] == L'C' || Suffix[3] == L'c')
117 && Suffix[4] == L'$'
118 )
119 {
120 if ( pNetRoot->pNetRootName->Length == 13 * sizeof (WCHAR)
121 || (Suffix[5] == L'\\' || Suffix[5] == 0)
122 )
123 {
124 /* It is '\vboxsrv\IPC$[\*]'. */
125 Log(("VBOXSF: MRxCreateVNetRoot: IPC$\n"));
126 Status = STATUS_MORE_PROCESSING_REQUIRED;
127 goto l_Exit;
128 }
129 }
130 }
131
132 /* Fail all other pipe open requests. */
133 Log(("VBOXSF: MRxCreateVNetRoot: Pipe open not supported!\n"));
134 Status = STATUS_NOT_SUPPORTED;
135 goto l_Exit;
136 }
137 else if (pNetRoot->Type == NET_ROOT_MAILSLOT)
138 {
139 Log(("VBOXSF: MRxCreateVNetRoot: Mailslot open not supported!\n"));
140 pVNetRoot->Context = NULL;
141 Status = STATUS_NOT_SUPPORTED;
142 goto l_Exit;
143 }
144
145 if (!pNetRoot->Context)
146 {
147 /* MRxNetRootSize is not zero in VBoxSF, so it is expected
148 * that the Context, which is NetRootExtension, is already allocated.
149 */
150 Log(("VBOXSF: MRxCreateVNetRoot: NULL netroot context\n"));
151 pVNetRoot->Context = NULL;
152 Status = STATUS_NOT_SUPPORTED;
153 goto l_Exit;
154 }
155
156 /* Detect an already initialized NetRoot.
157 * pNetRootExtension is actually the pNetRoot->Context and it is not NULL.
158 */
159 Status = STATUS_SUCCESS;
160
161 if (!pNetRootExtension->fInitialized)
162 {
163 PWCHAR pRootName;
164 ULONG RootNameLength;
165 int vrc;
166 PSHFLSTRING ParsedPath = 0;
167
168 Log(("VBOXSF: MRxCreateVNetRoot: initialize NET_ROOT\n"));
169
170 pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
171 pNetRootExtension->map.root = SHFL_ROOT_NIL;
172
173 RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
174 if (RootNameLength < sizeof(WCHAR))
175 {
176 /* Refuse a netroot path with an empty shared folder name */
177 Log(("VBOXSF: MRxCreateVNetRoot: Empty shared folder name!\n"));
178 pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
179
180 Status = STATUS_BAD_NETWORK_NAME;
181 goto l_Exit;
182 }
183
184 RootNameLength -= sizeof(WCHAR); /* Remove leading backslash. */
185 pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
186 pRootName++; /* Remove leading backslash. */
187
188 /* Strip the trailing \0. Sometimes there is one, sometimes not... */
189 if ( RootNameLength >= sizeof(WCHAR)
190 && pRootName[RootNameLength / sizeof(WCHAR) - 1] == 0)
191 RootNameLength -= sizeof(WCHAR);
192
193 if (!pNetRootExtension->fInitialized)
194 {
195 Log(("VBOXSF: MRxCreateVNetRoot: Initialize netroot length = %d, name = %.*ls\n",
196 RootNameLength, RootNameLength / sizeof(WCHAR), pRootName));
197
198 Status = vbsfShflStringFromUnicodeAlloc(&ParsedPath, pRootName, (uint16_t)RootNameLength);
199 if (Status != STATUS_SUCCESS)
200 {
201 goto l_Exit;
202 }
203
204 vrc = VbglR0SfMapFolder(&g_SfClient, ParsedPath, &pNetRootExtension->map);
205 vbsfFreeNonPagedMem(ParsedPath);
206 if (RT_SUCCESS(vrc))
207 {
208 pNetRootExtension->fInitialized = true;
209 Status = STATUS_SUCCESS;
210 }
211 else
212 {
213 Log(("VBOXSF: MRxCreateVNetRoot: VbglR0SfMapFolder failed with %d\n", vrc));
214 pNetRootExtension->map.root = SHFL_ROOT_NIL;
215 Status = STATUS_BAD_NETWORK_NAME;
216 }
217 }
218 }
219 else
220 Log(("VBOXSF: MRxCreateVNetRoot: Creating V_NET_ROOT on existing NET_ROOT!\n"));
221
222 vbsfUpdateNetRoot(pNetRoot);
223
224l_Exit:
225 if (Status != STATUS_PENDING)
226 {
227 Log(("VBOXSF: MRxCreateVNetRoot: Returning 0x%08X\n", Status));
228 pCreateNetRootContext->VirtualNetRootStatus = Status;
229 if (fInitializeNetRoot)
230 pCreateNetRootContext->NetRootStatus = Status;
231 else
232 pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
233
234 /* Inform RDBSS. */
235 pCreateNetRootContext->Callback(pCreateNetRootContext);
236
237 /* RDBSS expects this. */
238 Status = STATUS_PENDING;
239 }
240
241 Log(("VBOXSF: MRxCreateVNetRoot: Returned STATUS_PENDING\n"));
242 return Status;
243}
244
245NTSTATUS VBoxMRxFinalizeVNetRoot(IN PMRX_V_NET_ROOT pVNetRoot, IN PBOOLEAN ForceDisconnect)
246{
247 RT_NOREF(pVNetRoot, ForceDisconnect);
248 Log(("VBOXSF: MRxFinalizeVNetRoot: V_NET_ROOT %p, NET_ROOT %p\n", pVNetRoot, pVNetRoot->pNetRoot));
249
250 return STATUS_SUCCESS;
251}
252
253NTSTATUS VBoxMRxFinalizeNetRoot(IN PMRX_NET_ROOT pNetRoot, IN PBOOLEAN ForceDisconnect)
254{
255 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(pNetRoot);
256 RT_NOREF(pNetRoot, ForceDisconnect);
257
258 Log(("VBOXSF: MRxFinalizeNetRoot: NET_ROOT %p\n", pNetRoot));
259
260 if ( pNetRootExtension->fInitialized
261 && g_SfClient.handle != NULL)
262 {
263 int vrc = VbglR0SfUnmapFolder(&g_SfClient, &pNetRootExtension->map);
264 if (vrc != VINF_SUCCESS)
265 Log(("VBOXSF: MRxFinalizeVNetRoot: VbglR0SfUnmapFolder failed with %d\n",
266 vrc));
267 pNetRootExtension->map.root = SHFL_ROOT_NIL;
268 pNetRootExtension->fInitialized = false;
269 }
270
271 return STATUS_SUCCESS;
272}
273
274VOID VBoxMRxExtractNetRootName(IN PUNICODE_STRING FilePathName,
275 IN PMRX_SRV_CALL SrvCall,
276 OUT PUNICODE_STRING NetRootName,
277 OUT PUNICODE_STRING RestOfName OPTIONAL)
278{
279 int cChars = FilePathName->Length/sizeof(WCHAR);
280 int iNetRoot;
281 int i;
282
283 /* Split "\vboxsvr\share\path" to
284 * NetRootName = "\share"
285 * RestOfName = "\path"
286 *
287 * Note that SrvCall->pSrvCallName contains "\vboxsrv".
288 */
289
290 Log(("VBOXSF: MRxExtractNetRootName: [%.*ls], RestOfName %p\n",
291 FilePathName->Length/sizeof(WCHAR), FilePathName->Buffer, RestOfName));
292
293 /* Assume that the server prefix is OK.
294 * iNetRoot points to the first char after server name, the delimiter.
295 */
296 iNetRoot = SrvCall->pSrvCallName->Length/sizeof(WCHAR);
297
298 /* Find the NetRoot length: end of FilePathName or the next delimiter. */
299 i = iNetRoot;
300 while (i < cChars)
301 {
302 if ( FilePathName->Buffer[i] == L'\\'
303 && i > iNetRoot)
304 {
305 break;
306 }
307 i++;
308 }
309
310 Log(("VBOXSF: MRxExtractNetRootName: cChars %d, iNetRoot %d, iRest %d\n",
311 cChars, iNetRoot, i));
312
313 NetRootName->Buffer = &FilePathName->Buffer[iNetRoot];
314 NetRootName->Length = (USHORT)((i - iNetRoot) * sizeof(WCHAR));
315 NetRootName->MaximumLength = NetRootName->Length;
316
317 Log(("VBOXSF: MRxExtractNetRootName: Srv = %.*ls, Root = %.*ls\n",
318 SrvCall->pSrvCallName->Length / sizeof(WCHAR), SrvCall->pSrvCallName->Buffer,
319 NetRootName->Length / sizeof(WCHAR), NetRootName->Buffer));
320
321 if (RestOfName)
322 {
323 RestOfName->Buffer = &FilePathName->Buffer[i];
324 RestOfName->Length = (USHORT)((cChars - i) * sizeof(WCHAR));
325 RestOfName->MaximumLength = RestOfName->Length;
326
327 Log(("VBOXSF: MRxExtractNetRootName: Rest = %.*ls\n",
328 RestOfName->Length / sizeof(WCHAR), RestOfName->Buffer));
329 }
330}
331
332static VOID vbsfExecuteCreateSrvCall(PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
333{
334 NTSTATUS Status;
335 PWCHAR pSrvName = 0;
336 BOOLEAN Verifier;
337
338 PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
339 PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure);
340 PMRX_SRV_CALL pSrvCall = SrvCalldownStructure->SrvCall;
341
342 /* Validate the server name with the test name of 'vboxsvr'. */
343 Log(("VBOXSF: vbsfExecuteCreateSrvCall: Connection Name %.*ls Length: %d, pSrvCall = %p\n",
344 pSrvCall->pSrvCallName->Length / sizeof(WCHAR), pSrvCall->pSrvCallName->Buffer, pSrvCall->pSrvCallName->Length, pSrvCall));
345
346 if (pSrvCall->pPrincipalName && pSrvCall->pPrincipalName->Length)
347 {
348 Log(("VBOXSF: vbsfExecuteCreateSrvCall: Principal name = %.*ls\n",
349 pSrvCall->pPrincipalName->Length / sizeof(WCHAR), pSrvCall->pPrincipalName->Buffer));
350 }
351
352 if (pSrvCall->pDomainName && pSrvCall->pDomainName->Length)
353 {
354 Log(("VBOXSF: vbsfExecuteCreateSrvCall: Domain name = %.*ls\n",
355 pSrvCall->pDomainName->Length / sizeof(WCHAR), pSrvCall->pDomainName->Buffer));
356 }
357
358 if (pSrvCall->pSrvCallName->Length >= 14)
359 {
360 pSrvName = pSrvCall->pSrvCallName->Buffer;
361
362 Verifier = (pSrvName[0] == L'\\');
363 Verifier &= (pSrvName[1] == L'V') || (pSrvName[1] == L'v');
364 Verifier &= (pSrvName[2] == L'B') || (pSrvName[2] == L'b');
365 Verifier &= (pSrvName[3] == L'O') || (pSrvName[3] == L'o');
366 Verifier &= (pSrvName[4] == L'X') || (pSrvName[4] == L'x');
367 Verifier &= (pSrvName[5] == L'S') || (pSrvName[5] == L's');
368 /* Both vboxsvr & vboxsrv are now accepted */
369 if ((pSrvName[6] == L'V') || (pSrvName[6] == L'v'))
370 {
371 Verifier &= (pSrvName[6] == L'V') || (pSrvName[6] == L'v');
372 Verifier &= (pSrvName[7] == L'R') || (pSrvName[7] == L'r');
373 }
374 else
375 {
376 Verifier &= (pSrvName[6] == L'R') || (pSrvName[6] == L'r');
377 Verifier &= (pSrvName[7] == L'V') || (pSrvName[7] == L'v');
378 }
379 Verifier &= (pSrvName[8] == L'\\') || (pSrvName[8] == 0);
380 }
381 else
382 Verifier = FALSE;
383
384 if (Verifier)
385 {
386 Log(("VBOXSF: vbsfExecuteCreateSrvCall: Verifier succeeded!\n"));
387 Status = STATUS_SUCCESS;
388 }
389 else
390 {
391 Log(("VBOXSF: vbsfExecuteCreateSrvCall: Verifier failed!\n"));
392 Status = STATUS_BAD_NETWORK_PATH;
393 }
394
395 SCCBC->Status = Status;
396 SrvCalldownStructure->CallBack(SCCBC);
397}
398
399NTSTATUS VBoxMRxCreateSrvCall(PMRX_SRV_CALL pSrvCall, PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
400{
401 PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
402 RT_NOREF(pSrvCall);
403
404 Log(("VBOXSF: MRxCreateSrvCall: %p.\n", pSrvCall));
405
406 if (IoGetCurrentProcess() == RxGetRDBSSProcess())
407 {
408 Log(("VBOXSF: MRxCreateSrvCall: Called in context of RDBSS process\n"));
409
410 vbsfExecuteCreateSrvCall(pCallbackContext);
411 }
412 else
413 {
414 NTSTATUS Status;
415
416 Log(("VBOXSF: MRxCreateSrvCall: Dispatching to worker thread\n"));
417
418 Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue,
419 (PWORKER_THREAD_ROUTINE)vbsfExecuteCreateSrvCall,
420 pCallbackContext);
421
422 if (Status == STATUS_SUCCESS)
423 Log(("VBOXSF: MRxCreateSrvCall: queued\n"));
424 else
425 {
426 pCallbackContext->Status = Status;
427 SrvCalldownStructure->CallBack(pCallbackContext);
428 }
429 }
430
431 /* RDBSS expect this. */
432 return STATUS_PENDING;
433}
434
435NTSTATUS VBoxMRxFinalizeSrvCall(PMRX_SRV_CALL pSrvCall, BOOLEAN Force)
436{
437 RT_NOREF(Force);
438 Log(("VBOXSF: MRxFinalizeSrvCall %p, ctx = %p.\n", pSrvCall, pSrvCall->Context));
439
440 pSrvCall->Context = NULL;
441
442 return STATUS_SUCCESS;
443}
444
445NTSTATUS VBoxMRxSrvCallWinnerNotify(IN PMRX_SRV_CALL pSrvCall, IN BOOLEAN ThisMinirdrIsTheWinner, IN OUT PVOID pSrvCallContext)
446{
447 RT_NOREF(ThisMinirdrIsTheWinner, pSrvCallContext);
448 Log(("VBOXSF: MRxSrvCallWinnerNotify: pSrvCall %p, pSrvCall->Ctx %p, winner %d, context %p\n",
449 pSrvCall, pSrvCall->Context, ThisMinirdrIsTheWinner, pSrvCallContext));
450
451 /* Set it to not NULL. */
452 pSrvCall->Context = pSrvCall;
453
454 return STATUS_SUCCESS;
455}
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