VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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