1 | /*++
|
---|
2 |
|
---|
3 | Copyright (c) 1989 - 1999 Microsoft Corporation
|
---|
4 |
|
---|
5 | Module Name:
|
---|
6 |
|
---|
7 | netroot.c
|
---|
8 |
|
---|
9 | Abstract:
|
---|
10 |
|
---|
11 | This module implements the routines for creating the net root.
|
---|
12 |
|
---|
13 | --*/
|
---|
14 |
|
---|
15 | #include "precomp.h"
|
---|
16 | #pragma hdrstop
|
---|
17 |
|
---|
18 | //
|
---|
19 | // Forward declarations ...
|
---|
20 | //
|
---|
21 |
|
---|
22 | NTSTATUS VBoxMRxUpdateNetRootState (IN OUT PMRX_NET_ROOT pNetRoot)
|
---|
23 | /*++
|
---|
24 |
|
---|
25 | Routine Description:
|
---|
26 |
|
---|
27 | This routine updates the mini redirector state associated with a net root.
|
---|
28 |
|
---|
29 | Arguments:
|
---|
30 |
|
---|
31 | pNetRoot - the net root instance.
|
---|
32 |
|
---|
33 | Return Value:
|
---|
34 |
|
---|
35 | NTSTATUS - The return status for the operation
|
---|
36 |
|
---|
37 | Notes:
|
---|
38 |
|
---|
39 | By differentiating the mini redirector state from the net root condition it is possible
|
---|
40 | to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
|
---|
41 | a net root to be good while the underlying mini redirector might mark it as invalid
|
---|
42 | and reconnect on the fly.
|
---|
43 |
|
---|
44 | --*/
|
---|
45 | {
|
---|
46 | NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
---|
47 |
|
---|
48 | Log(("VBOXSF: VBoxMRxUpdateNetRootState: Called.\n"));
|
---|
49 | return (Status);
|
---|
50 | }
|
---|
51 |
|
---|
52 | NTSTATUS VBoxMRxInitializeNetRootEntry (IN PMRX_NET_ROOT pNetRoot)
|
---|
53 | /*++
|
---|
54 |
|
---|
55 | Routine Description:
|
---|
56 |
|
---|
57 | This routine initializes a new net root.
|
---|
58 | It also validates rootnames. Eg: attempts to create a
|
---|
59 | file in a root that has not been created will fail.
|
---|
60 |
|
---|
61 | Arguments:
|
---|
62 |
|
---|
63 | pNetRoot - the net root
|
---|
64 |
|
---|
65 | Return Value:
|
---|
66 |
|
---|
67 | NTSTATUS - The return status for the operation
|
---|
68 |
|
---|
69 | Notes:
|
---|
70 |
|
---|
71 | --*/
|
---|
72 | {
|
---|
73 | NTSTATUS Status = STATUS_SUCCESS;
|
---|
74 | PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
|
---|
75 | PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context;
|
---|
76 |
|
---|
77 | Log(("VBOXSF: VBoxMRxInitializeNetRootEntry: Called.\n"));
|
---|
78 | return Status;
|
---|
79 | }
|
---|
80 |
|
---|
81 | NTSTATUS VBoxUpdateNetRoot (PMRX_NET_ROOT pNetRoot)
|
---|
82 | /*++
|
---|
83 |
|
---|
84 | Routine Description:
|
---|
85 |
|
---|
86 | This routine initializes the wrapper data structure corresponding to a
|
---|
87 | given net root entry.
|
---|
88 |
|
---|
89 | Arguments:
|
---|
90 |
|
---|
91 | pNetRootEntry - the server entry
|
---|
92 |
|
---|
93 | Return Value:
|
---|
94 |
|
---|
95 | STATUS_SUCCESS if successful
|
---|
96 |
|
---|
97 | --*/
|
---|
98 | {
|
---|
99 | PAGED_CODE();
|
---|
100 |
|
---|
101 | Log(("VBOXSF: VBoxUpdateNetRoot: NetRoot = 0x%x Type = 0x%x\n", pNetRoot, pNetRoot->Type));
|
---|
102 |
|
---|
103 | switch (pNetRoot->Type)
|
---|
104 | {
|
---|
105 | case NET_ROOT_DISK:
|
---|
106 | pNetRoot->DeviceType = RxDeviceType(DISK);
|
---|
107 | break;
|
---|
108 |
|
---|
109 | case NET_ROOT_PIPE:
|
---|
110 | pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
|
---|
111 | break;
|
---|
112 | case NET_ROOT_COMM:
|
---|
113 | pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
|
---|
114 | break;
|
---|
115 | case NET_ROOT_PRINT:
|
---|
116 | pNetRoot->DeviceType = RxDeviceType(PRINTER);
|
---|
117 | break;
|
---|
118 | case NET_ROOT_MAILSLOT:
|
---|
119 | pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
|
---|
120 | break;
|
---|
121 | case NET_ROOT_WILD:
|
---|
122 | /* We get this type when for example Windows Media player opens an MP3 file.
|
---|
123 | * This NetRoot has the same remote path (\\vboxsrv\dir) as other NetRoots,
|
---|
124 | * which were created earlier and which were NET_ROOT_DISK.
|
---|
125 | *
|
---|
126 | * In the beginning of the function (UpdateNetRoot) the DDK sample sets
|
---|
127 | * pNetRoot->Type of newly created NetRoots using a value previously
|
---|
128 | * pstored in a NetRootExtension. One NetRootExtensions is used for a single
|
---|
129 | * remote path and reused by a few NetRoots, if they point to the same path.
|
---|
130 | *
|
---|
131 | * To simplify things we just set the type to DISK here (we do not support
|
---|
132 | * anything else anyway), and update the DeviceType correspondingly.
|
---|
133 | */
|
---|
134 | pNetRoot->Type = NET_ROOT_DISK;
|
---|
135 | pNetRoot->DeviceType = RxDeviceType(DISK);
|
---|
136 | break;
|
---|
137 | default:
|
---|
138 | AssertMsgFailed(("VBOXSF: VBoxUpdateNetRoot: Invalid net root type! Type = 0x%x\n", pNetRoot->Type));
|
---|
139 | break;
|
---|
140 | }
|
---|
141 |
|
---|
142 | Log(("VBOXSF: VBoxUpdateNetRoot: leaving pNetRoot->DeviceType = 0x%x\n", pNetRoot->DeviceType));
|
---|
143 | return STATUS_SUCCESS;
|
---|
144 | }
|
---|
145 |
|
---|
146 | NTSTATUS VBoxMRxCreateVNetRoot (IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
|
---|
147 | /*++
|
---|
148 |
|
---|
149 | Routine Description:
|
---|
150 |
|
---|
151 | This routine patches the RDBSS created net root instance with the information required
|
---|
152 | by the mini redirector.
|
---|
153 |
|
---|
154 | Arguments:
|
---|
155 |
|
---|
156 | pVNetRoot - the virtual net root instance.
|
---|
157 |
|
---|
158 | pCreateNetRootContext - the net root context for calling back
|
---|
159 |
|
---|
160 | Return Value:
|
---|
161 |
|
---|
162 | NTSTATUS - The return status for the operation
|
---|
163 |
|
---|
164 | Notes:
|
---|
165 |
|
---|
166 | --*/
|
---|
167 | {
|
---|
168 | NTSTATUS Status;
|
---|
169 | PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext;
|
---|
170 | PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
|
---|
171 | VBoxMRxGetDeviceExtension(pRxContext, pDeviceExtension);
|
---|
172 | VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension);
|
---|
173 |
|
---|
174 | PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
|
---|
175 | PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
|
---|
176 |
|
---|
177 | BOOLEAN fTreeConnectOpen = TRUE; // RxContext->Create.ThisIsATreeConnectOpen;
|
---|
178 | BOOLEAN fInitializeNetRoot = FALSE; //// !! Fix
|
---|
179 |
|
---|
180 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: pNetRoot = %p, fTreeConnectOpen = %d\n", pNetRoot, pRxContext->Create.ThisIsATreeConnectOpen));
|
---|
181 |
|
---|
182 | /* IMPORTANT:
|
---|
183 | *
|
---|
184 | * This function must always call 'pCreateNetRootContext->Callback(pCreateNetRootContext)' before
|
---|
185 | * returning and then return STATUS_PENDING. Otherwise Win64 will hang.
|
---|
186 | */
|
---|
187 |
|
---|
188 | if (pNetRoot->Type == NET_ROOT_PIPE)
|
---|
189 | {
|
---|
190 | pNetRoot->Type = NET_ROOT_WILD;
|
---|
191 | }
|
---|
192 |
|
---|
193 |
|
---|
194 | if (pNetRoot->Type == NET_ROOT_MAILSLOT)
|
---|
195 | {
|
---|
196 |
|
---|
197 | /* DDK sample returns this status code. And our driver does get such NetRoots. */
|
---|
198 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: Mailslot or Pipe open (%d) not supported!\n", pNetRoot->Type));
|
---|
199 |
|
---|
200 | pVNetRoot->Context = NULL;
|
---|
201 |
|
---|
202 | Status = STATUS_NOT_SUPPORTED;
|
---|
203 | goto l_Exit;
|
---|
204 | }
|
---|
205 |
|
---|
206 |
|
---|
207 | // The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as
|
---|
208 | // follows
|
---|
209 | // 1) the V_NET_ROOT and the associated NET_ROOT are being newly created.
|
---|
210 | // 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created.
|
---|
211 | //
|
---|
212 | // These two cases can be distinguished by checking if the context associated with
|
---|
213 | // NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized
|
---|
214 | // by the wrapper this is a safe check.
|
---|
215 | // ( The wrapper cannot have more then one thread trying to initialize the same
|
---|
216 | // NET_ROOT).
|
---|
217 | //
|
---|
218 | // The above is not really true in our case. Since we have asked the wrapper,
|
---|
219 | // to manage our netroot extension, the netroot context will always be non-NULL.
|
---|
220 | // We will distinguish the cases by checking our root state in the context...
|
---|
221 | //
|
---|
222 |
|
---|
223 | if (pNetRoot->Context == NULL)
|
---|
224 | {
|
---|
225 | fInitializeNetRoot = TRUE;
|
---|
226 | }
|
---|
227 | else
|
---|
228 | {
|
---|
229 | VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
|
---|
230 | /* Detect an already initialized NetRoot.
|
---|
231 | * pNetRootExtension is actually the pNetRoot->Context and it is not null.
|
---|
232 | */
|
---|
233 | fInitializeNetRoot = pNetRootExtension->phgcmClient == NULL;
|
---|
234 | }
|
---|
235 |
|
---|
236 | Assert((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) && (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
|
---|
237 |
|
---|
238 | Status = STATUS_SUCCESS;
|
---|
239 |
|
---|
240 | // update the net root state to be good.
|
---|
241 |
|
---|
242 | if (fInitializeNetRoot)
|
---|
243 | {
|
---|
244 | PWCHAR pRootName;
|
---|
245 | ULONG RootNameLength;
|
---|
246 | int vboxRC;
|
---|
247 | PSHFLSTRING ParsedPath = 0;
|
---|
248 | ULONG ParsedPathSize;
|
---|
249 |
|
---|
250 | pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
|
---|
251 |
|
---|
252 | // validate the fixed netroot name
|
---|
253 |
|
---|
254 | RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
|
---|
255 | if (!RootNameLength)
|
---|
256 | {
|
---|
257 | /* Refuse a netroot path with an empty shared folder name */
|
---|
258 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: Invalid shared folder name! (length=0)\n"));
|
---|
259 | pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
|
---|
260 |
|
---|
261 | Status = STATUS_BAD_NETWORK_NAME;
|
---|
262 | goto l_Exit;
|
---|
263 | }
|
---|
264 |
|
---|
265 | RootNameLength -= 2; /* remove leading backslash */
|
---|
266 |
|
---|
267 | pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
|
---|
268 | pRootName++; /* remove leading backslash */
|
---|
269 |
|
---|
270 | if (pNetRootExtension->phgcmClient == NULL)
|
---|
271 | {
|
---|
272 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: Initialize netroot length = %d, name = %.*ls\n", RootNameLength, RootNameLength / sizeof(WCHAR), pRootName));
|
---|
273 |
|
---|
274 | /* Calculate length required for parsed path.
|
---|
275 | */
|
---|
276 | ParsedPathSize = sizeof(*ParsedPath) + RootNameLength + sizeof(WCHAR);
|
---|
277 |
|
---|
278 | ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
|
---|
279 | if (!ParsedPath)
|
---|
280 | {
|
---|
281 | Status = STATUS_INSUFFICIENT_RESOURCES;
|
---|
282 | goto l_Exit;
|
---|
283 | }
|
---|
284 | memset(ParsedPath, 0, ParsedPathSize);
|
---|
285 |
|
---|
286 | ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
|
---|
287 |
|
---|
288 | ParsedPath->u16Size = (uint16_t)RootNameLength + sizeof(WCHAR);
|
---|
289 | ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */
|
---|
290 | RtlCopyMemory(ParsedPath->String.ucs2, pRootName, ParsedPath->u16Length);
|
---|
291 |
|
---|
292 | vboxRC = vboxCallMapFolder(&pDeviceExtension->hgcmClient, ParsedPath, &pNetRootExtension->map);
|
---|
293 | vbsfFreeNonPagedMem(ParsedPath);
|
---|
294 | if (vboxRC != VINF_SUCCESS)
|
---|
295 | {
|
---|
296 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
|
---|
297 | Status = STATUS_BAD_NETWORK_NAME;
|
---|
298 | }
|
---|
299 | else
|
---|
300 | {
|
---|
301 | Status = STATUS_SUCCESS;
|
---|
302 | pNetRootExtension->phgcmClient = &pDeviceExtension->hgcmClient;
|
---|
303 | }
|
---|
304 | }
|
---|
305 | }
|
---|
306 | else Log(("VBOXSF: VBoxMRxCreateVNetRoot: Creating V_NET_ROOT on existing NET_ROOT!\n"));
|
---|
307 |
|
---|
308 | if ((Status == STATUS_SUCCESS) && fInitializeNetRoot)
|
---|
309 | {
|
---|
310 | //
|
---|
311 | // A new NET_ROOT and associated V_NET_ROOT are being created !
|
---|
312 | //
|
---|
313 | Status = VBoxMRxInitializeNetRootEntry(pNetRoot);
|
---|
314 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: NulMRXInitializeNetRootEntry called, Status = 0x%lx\n", Status));
|
---|
315 | }
|
---|
316 |
|
---|
317 | VBoxUpdateNetRoot(pNetRoot);
|
---|
318 |
|
---|
319 | l_Exit:
|
---|
320 | if (Status != STATUS_PENDING)
|
---|
321 | {
|
---|
322 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returning 0x%lx\n", Status));
|
---|
323 | pCreateNetRootContext->VirtualNetRootStatus = Status;
|
---|
324 | if (fInitializeNetRoot)
|
---|
325 | pCreateNetRootContext->NetRootStatus = Status;
|
---|
326 | else pCreateNetRootContext->NetRootStatus = Status;
|
---|
327 |
|
---|
328 | // Callback the RDBSS for resumption.
|
---|
329 | pCreateNetRootContext->Callback(pCreateNetRootContext);
|
---|
330 |
|
---|
331 | // Map the error code to STATUS_PENDING since this triggers
|
---|
332 | // the synchronization mechanism in the RDBSS.
|
---|
333 | Status = STATUS_PENDING;
|
---|
334 | }
|
---|
335 |
|
---|
336 | Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returned STATUS_PENDING\n"));
|
---|
337 | return Status;
|
---|
338 | }
|
---|
339 |
|
---|
340 | NTSTATUS VBoxMRxFinalizeVNetRoot (IN PMRX_V_NET_ROOT pVNetRoot, IN PBOOLEAN ForceDisconnect)
|
---|
341 | /*++
|
---|
342 |
|
---|
343 | Routine Description:
|
---|
344 |
|
---|
345 |
|
---|
346 | Arguments:
|
---|
347 |
|
---|
348 | pVNetRoot - the virtual net root
|
---|
349 |
|
---|
350 | ForceDisconnect - disconnect is forced
|
---|
351 |
|
---|
352 | Return Value:
|
---|
353 |
|
---|
354 | NTSTATUS - The return status for the operation
|
---|
355 |
|
---|
356 | --*/
|
---|
357 | {
|
---|
358 | NTSTATUS Status = STATUS_SUCCESS;
|
---|
359 | PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
|
---|
360 | VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension);
|
---|
361 | int vboxRC;
|
---|
362 |
|
---|
363 | Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: Address = 0x%lx\n", pVNetRoot));
|
---|
364 |
|
---|
365 | if (pNetRootExtension->phgcmClient)
|
---|
366 | {
|
---|
367 | vboxRC = vboxCallUnmapFolder(pNetRootExtension->phgcmClient, &pNetRootExtension->map);
|
---|
368 | if (vboxRC != VINF_SUCCESS)
|
---|
369 | {
|
---|
370 | Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
|
---|
371 | }
|
---|
372 | pNetRootExtension->phgcmClient = NULL;
|
---|
373 | }
|
---|
374 |
|
---|
375 | //
|
---|
376 | // This is called when all outstanding handles on this
|
---|
377 | // root have been cleaned up ! We can now zap the netroot
|
---|
378 | // extension...
|
---|
379 | //
|
---|
380 |
|
---|
381 | return Status;
|
---|
382 | }
|
---|
383 |
|
---|
384 | NTSTATUS VBoxMRxFinalizeNetRoot (IN PMRX_NET_ROOT pNetRoot, IN PBOOLEAN ForceDisconnect)
|
---|
385 | /*++
|
---|
386 |
|
---|
387 | Routine Description:
|
---|
388 |
|
---|
389 |
|
---|
390 | Arguments:
|
---|
391 |
|
---|
392 | pVirtualNetRoot - the virtual net root
|
---|
393 |
|
---|
394 | ForceDisconnect - disconnect is forced
|
---|
395 |
|
---|
396 | Return Value:
|
---|
397 |
|
---|
398 | NTSTATUS - The return status for the operation
|
---|
399 |
|
---|
400 | --*/
|
---|
401 | {
|
---|
402 | NTSTATUS Status = STATUS_SUCCESS;
|
---|
403 |
|
---|
404 | Log(("VBOXSF: VBoxMRxFinalizeNetRoot: Called.\n"));
|
---|
405 | //
|
---|
406 | // This is called when all outstanding handles on this
|
---|
407 | // root have been cleaned up ! We can now zap the netroot
|
---|
408 | // extension...
|
---|
409 | //
|
---|
410 | return (Status);
|
---|
411 | }
|
---|
412 |
|
---|
413 | VOID VBoxMRxExtractNetRootName (IN PUNICODE_STRING FilePathName, IN PMRX_SRV_CALL SrvCall, OUT PUNICODE_STRING NetRootName, OUT PUNICODE_STRING RestOfName OPTIONAL
|
---|
414 | )
|
---|
415 | /*++
|
---|
416 |
|
---|
417 | Routine Description:
|
---|
418 |
|
---|
419 | This routine parses the input name into srv, netroot, and the
|
---|
420 | rest.
|
---|
421 |
|
---|
422 | Arguments:
|
---|
423 |
|
---|
424 |
|
---|
425 | --*/
|
---|
426 | {
|
---|
427 | UNICODE_STRING xRestOfName;
|
---|
428 |
|
---|
429 | ULONG length = FilePathName->Length;
|
---|
430 | PWCH w = FilePathName->Buffer;
|
---|
431 | PWCH wlimit = (PWCH)(((PCHAR)w) + length);
|
---|
432 | PWCH wlow;
|
---|
433 |
|
---|
434 | Log(("VBOXSF: VBoxMRxExtractNetRootName: Called.\n"));
|
---|
435 |
|
---|
436 | w += (SrvCall->pSrvCallName->Length / sizeof(WCHAR));
|
---|
437 | NetRootName->Buffer = wlow = w;
|
---|
438 | for (;;)
|
---|
439 | {
|
---|
440 | if (w >= wlimit)
|
---|
441 | break;
|
---|
442 | if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow))
|
---|
443 | {
|
---|
444 | break;
|
---|
445 | }
|
---|
446 | w++;
|
---|
447 | }
|
---|
448 |
|
---|
449 | NetRootName->Length = NetRootName->MaximumLength = (USHORT)((PCHAR)w - (PCHAR)wlow);
|
---|
450 |
|
---|
451 | //w = FilePathName->Buffer;
|
---|
452 | //NetRootName->Buffer = w++;
|
---|
453 |
|
---|
454 | if (!RestOfName)
|
---|
455 | RestOfName = &xRestOfName;
|
---|
456 | RestOfName->Buffer = w;
|
---|
457 | RestOfName->Length = (USHORT)RestOfName->MaximumLength = (USHORT)((PCHAR)wlimit - (PCHAR)w);
|
---|
458 |
|
---|
459 | Log(("VBOXSF: VBoxMRxExtractNetRootName: FilePath = %.*ls\n", FilePathName->Length / sizeof(WCHAR), FilePathName->Buffer));
|
---|
460 | Log(("VBOXSF: VBoxMRxExtractNetRootName: Srv = %.*ls, Root = %.*ls, Rest = %.*ls\n", SrvCall->pSrvCallName->Length / sizeof(WCHAR), SrvCall->pSrvCallName->Buffer, NetRootName->Length
|
---|
461 | / sizeof(WCHAR), NetRootName->Buffer, RestOfName->Length / sizeof(WCHAR), RestOfName->Buffer));
|
---|
462 |
|
---|
463 | return;
|
---|
464 | }
|
---|
465 |
|
---|