VirtualBox

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

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

winnt/vboxsf: Doxygen and related cleanups; eliminating the separate helper header. bugref:9172

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