VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.cpp@ 63085

Last change on this file since 63085 was 63085, checked in by vboxsync, 8 years ago

vboxmrxnp.cpp/vboxToUpper: Should probably use the CharUpperW variant, since we give it a WCHAR and expect a WCHAR return.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.6 KB
Line 
1/* $Id: vboxmrxnp.cpp 63085 2016-08-06 14:35:30Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Shared Folders - Network provider dll
4 */
5
6/*
7 * Copyright (C) 2012-2016 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 <iprt/win/windows.h>
19#include <winsvc.h>
20#include <winnetwk.h>
21#include <npapi.h>
22#include <devioctl.h>
23#include <stdio.h>
24
25#include "..\driver\vbsfshared.h"
26
27#include <iprt/alloc.h>
28#include <iprt/initterm.h>
29#include <iprt/string.h>
30#include <iprt/log.h>
31#include <VBox/version.h>
32#include <VBox/VMMDev.h>
33#include <VBox/VBoxGuestLib.h>
34#include <VBox/Log.h>
35
36#define MRX_VBOX_SERVER_NAME_U L"VBOXSVR"
37#define MRX_VBOX_SERVER_NAME_ALT_U L"VBOXSRV"
38
39#define WNNC_DRIVER(major, minor) (major * 0x00010000 + minor)
40
41
42static WCHAR vboxToUpper(WCHAR wc)
43{
44 /* The CharUpper parameter is a pointer to a null-terminated string,
45 * or specifies a single character. If the high-order word of this
46 * parameter is zero, the low-order word must contain a single character to be converted.
47 */
48 return (WCHAR)(uintptr_t)CharUpperW((LPWSTR)(uintptr_t)wc);
49}
50
51static DWORD vbsfIOCTL(ULONG IoctlCode,
52 PVOID InputDataBuf,
53 ULONG InputDataLen,
54 PVOID OutputDataBuf,
55 PULONG pOutputDataLen)
56{
57 ULONG cbOut = 0;
58
59 if (!pOutputDataLen)
60 {
61 pOutputDataLen = &cbOut;
62 }
63
64 ULONG dwStatus = WN_SUCCESS;
65
66 HANDLE DeviceHandle = CreateFile(DD_MRX_VBOX_USERMODE_DEV_NAME_U,
67 GENERIC_READ | GENERIC_WRITE,
68 FILE_SHARE_READ | FILE_SHARE_WRITE,
69 (LPSECURITY_ATTRIBUTES)NULL,
70 OPEN_EXISTING,
71 0,
72 (HANDLE)NULL);
73
74 if (INVALID_HANDLE_VALUE != DeviceHandle)
75 {
76 BOOL fSuccess = DeviceIoControl(DeviceHandle,
77 IoctlCode,
78 InputDataBuf,
79 InputDataLen,
80 OutputDataBuf,
81 *pOutputDataLen,
82 pOutputDataLen,
83 NULL);
84
85 if (!fSuccess)
86 {
87 dwStatus = GetLastError();
88
89 Log(("VBOXNP: vbsfIOCTL: DeviceIoctl last error = %d\n", dwStatus));
90 }
91
92 CloseHandle(DeviceHandle);
93 }
94 else
95 {
96 dwStatus = GetLastError();
97
98 static int sLogged = 0;
99 if (!sLogged)
100 {
101 LogRel(("VBOXNP: vbsfIOCTL: Error opening device, last error = %d\n",
102 dwStatus));
103 sLogged++;
104 }
105 }
106
107 return dwStatus;
108}
109
110DWORD APIENTRY NPGetCaps(DWORD nIndex)
111{
112 DWORD rc = 0;
113
114 Log(("VBOXNP: GetNetCaps: Index = 0x%x\n", nIndex));
115
116 switch (nIndex)
117 {
118 case WNNC_SPEC_VERSION:
119 {
120 rc = WNNC_SPEC_VERSION51;
121 } break;
122
123 case WNNC_NET_TYPE:
124 {
125 rc = WNNC_NET_RDR2SAMPLE;
126 } break;
127
128 case WNNC_DRIVER_VERSION:
129 {
130 rc = WNNC_DRIVER(1, 0);
131 } break;
132
133 case WNNC_CONNECTION:
134 {
135 vbsfIOCTL(IOCTL_MRX_VBOX_START, NULL, 0, NULL, NULL);
136
137 rc = WNNC_CON_GETCONNECTIONS |
138 WNNC_CON_CANCELCONNECTION |
139 WNNC_CON_ADDCONNECTION |
140 WNNC_CON_ADDCONNECTION3;
141 } break;
142
143 case WNNC_ENUMERATION:
144 {
145 rc = WNNC_ENUM_LOCAL |
146 WNNC_ENUM_GLOBAL |
147 WNNC_ENUM_SHAREABLE;
148 } break;
149
150 case WNNC_START:
151 {
152 rc = WNNC_WAIT_FOR_START;
153 break;
154 }
155
156 case WNNC_DIALOG:
157 {
158 rc = WNNC_DLG_GETRESOURCEPARENT |
159 WNNC_DLG_GETRESOURCEINFORMATION;
160 } break;
161
162 case WNNC_USER:
163 case WNNC_ADMIN:
164 default:
165 {
166 rc = 0;
167 } break;
168 }
169
170 return rc;
171}
172
173DWORD APIENTRY NPLogonNotify(PLUID pLogonId,
174 LPCWSTR pAuthentInfoType,
175 LPVOID pAuthentInfo,
176 LPCWSTR pPreviousAuthentInfoType,
177 LPVOID pPreviousAuthentInfo,
178 LPWSTR pStationName,
179 LPVOID StationHandle,
180 LPWSTR *pLogonScript)
181{
182 RT_NOREF(pLogonId, pAuthentInfoType, pAuthentInfo, pPreviousAuthentInfoType, pPreviousAuthentInfo, pStationName,
183 StationHandle, pLogonScript);
184 Log(("VBOXNP: NPLogonNotify\n"));
185 *pLogonScript = NULL;
186 return WN_SUCCESS;
187}
188
189DWORD APIENTRY NPPasswordChangeNotify(LPCWSTR pAuthentInfoType,
190 LPVOID pAuthentInfo,
191 LPCWSTR pPreviousAuthentInfoType,
192 LPVOID pPreviousAuthentInfo,
193 LPWSTR pStationName,
194 LPVOID StationHandle,
195 DWORD dwChangeInfo)
196{
197 RT_NOREF(pAuthentInfoType, pAuthentInfo, pPreviousAuthentInfoType, pPreviousAuthentInfo, pStationName,
198 StationHandle, dwChangeInfo);
199 Log(("VBOXNP: NPPasswordChangeNotify\n"));
200
201 SetLastError(WN_NOT_SUPPORTED);
202 return WN_NOT_SUPPORTED;
203}
204
205DWORD APIENTRY NPAddConnection(LPNETRESOURCE pNetResource,
206 LPWSTR pPassword,
207 LPWSTR pUserName)
208{
209 Log(("VBOXNP: NPAddConnection\n"));
210 return NPAddConnection3(NULL, pNetResource, pPassword, pUserName, 0);
211}
212
213DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
214 LPNETRESOURCE pNetResource,
215 LPWSTR pPassword,
216 LPWSTR pUserName,
217 DWORD dwFlags)
218{
219 RT_NOREF(hwndOwner, pPassword, pUserName, dwFlags);
220 DWORD dwStatus = WN_SUCCESS;
221 WCHAR ConnectionName[256];
222 WCHAR LocalName[3];
223 BOOLEAN fLocalName = TRUE;
224
225 Log(("VBOXNP: NPAddConnection3: dwFlags = 0x%x\n", dwFlags));
226 Log(("VBOXNP: NPAddConnection3: Local Name: %ls\n", pNetResource->lpLocalName ));
227 Log(("VBOXNP: NPAddConnection3: Remote Name: %ls\n", pNetResource->lpRemoteName ));
228
229 if ( pNetResource->dwType != RESOURCETYPE_DISK
230 && pNetResource->dwType != RESOURCETYPE_ANY)
231 {
232 Log(("VBOXNP: NPAddConnection3: Incorrect net resource type %d\n", pNetResource->dwType));
233 return WN_BAD_NETNAME;
234 }
235
236 /* Build connection name: \Device\VBoxMiniRdr\;%DriveLetter%:\vboxsvr\share */
237
238 lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
239 lstrcat(ConnectionName, L"\\;");
240
241 if (pNetResource->lpLocalName == NULL)
242 {
243 LocalName[0] = L'\0';
244 fLocalName = FALSE;
245 }
246 else
247 {
248 if ( pNetResource->lpLocalName[0]
249 && pNetResource->lpLocalName[1] == L':')
250 {
251 LocalName[0] = vboxToUpper(pNetResource->lpLocalName[0]);
252 LocalName[1] = L':';
253 LocalName[2] = L'\0';
254
255 lstrcat(ConnectionName, LocalName);
256 }
257 else
258 {
259 dwStatus = WN_BAD_LOCALNAME;
260 }
261 }
262
263
264 if (dwStatus == WN_SUCCESS)
265 {
266 /* Append the remote name. */
267 if ( pNetResource->lpRemoteName
268 && pNetResource->lpRemoteName[0] == L'\\'
269 && pNetResource->lpRemoteName[1] == L'\\' )
270 {
271 /* No need for (lstrlen + 1), because 'lpNetResource->lpRemoteName' leading \ is not copied. */
272 if (lstrlen(ConnectionName) + lstrlen(pNetResource->lpRemoteName) <= sizeof(ConnectionName) / sizeof(WCHAR))
273 {
274 lstrcat(ConnectionName, &pNetResource->lpRemoteName[1]);
275 }
276 else
277 {
278 dwStatus = WN_BAD_NETNAME;
279 }
280 }
281 else
282 {
283 dwStatus = WN_BAD_NETNAME;
284 }
285 }
286
287 Log(("VBOXNP: NPAddConnection3: ConnectionName: [%ls], len %d, dwStatus 0x%08X\n",
288 ConnectionName, (lstrlen(ConnectionName) + 1) * sizeof(WCHAR), dwStatus));
289
290 if (dwStatus == WN_SUCCESS)
291 {
292 WCHAR wszTmp[128];
293
294 SetLastError(NO_ERROR);
295
296 if ( fLocalName
297 && QueryDosDevice(LocalName, wszTmp, sizeof(wszTmp) / sizeof(WCHAR)))
298 {
299 Log(("VBOXNP: NPAddConnection3: Connection [%ls] already connected.\n",
300 ConnectionName));
301 dwStatus = WN_ALREADY_CONNECTED;
302 }
303 else
304 {
305 if ( !fLocalName
306 || GetLastError() == ERROR_FILE_NOT_FOUND)
307 {
308 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_ADDCONN,
309 ConnectionName,
310 (lstrlen(ConnectionName) + 1) * sizeof(WCHAR),
311 NULL,
312 NULL);
313
314 if (dwStatus == WN_SUCCESS)
315 {
316 if ( fLocalName
317 && !DefineDosDevice(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM,
318 pNetResource->lpLocalName,
319 ConnectionName))
320 {
321 dwStatus = GetLastError();
322 }
323 }
324 else
325 {
326 dwStatus = WN_BAD_NETNAME;
327 }
328 }
329 else
330 {
331 dwStatus = WN_ALREADY_CONNECTED;
332 }
333 }
334 }
335
336 Log(("VBOXNP: NPAddConnection3: Returned 0x%08X\n",
337 dwStatus));
338 return dwStatus;
339}
340
341DWORD APIENTRY NPCancelConnection(LPWSTR pName,
342 BOOL fForce)
343{
344 RT_NOREF(fForce);
345 DWORD dwStatus = WN_NOT_CONNECTED;
346
347 Log(("VBOXNP: NPCancelConnection: Name = %ls\n",
348 pName));
349
350 if (pName && pName[0] != 0)
351 {
352 WCHAR ConnectionName[256];
353
354 if (pName[1] == L':')
355 {
356 WCHAR RemoteName[128];
357 WCHAR LocalName[3];
358
359 LocalName[0] = vboxToUpper(pName[0]);
360 LocalName[1] = L':';
361 LocalName[2] = L'\0';
362
363 ULONG cbOut = sizeof(RemoteName) - sizeof(WCHAR); /* Trailing NULL. */
364
365 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETCONN,
366 LocalName,
367 sizeof(LocalName),
368 (PVOID)RemoteName,
369 &cbOut);
370
371 if ( dwStatus == WN_SUCCESS
372 && cbOut > 0)
373 {
374 RemoteName[cbOut / sizeof(WCHAR)] = L'\0';
375
376 if (lstrlen(DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen(LocalName) + lstrlen(RemoteName) + 1 > sizeof(ConnectionName) / sizeof(WCHAR))
377 {
378 dwStatus = WN_BAD_NETNAME;
379 }
380 else
381 {
382 lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
383 lstrcat(ConnectionName, L"\\;");
384 lstrcat(ConnectionName, LocalName);
385 lstrcat(ConnectionName, RemoteName);
386
387 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_DELCONN,
388 ConnectionName,
389 (lstrlen(ConnectionName) + 1) * sizeof(WCHAR),
390 NULL,
391 NULL);
392
393 if (dwStatus == WN_SUCCESS)
394 {
395 if (!DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
396 LocalName,
397 ConnectionName))
398 {
399 dwStatus = GetLastError();
400 }
401 }
402 }
403 }
404 else
405 {
406 dwStatus = WN_NOT_CONNECTED;
407 }
408 }
409 else
410 {
411 BOOLEAN Verifier;
412
413 Verifier = ( pName[0] == L'\\' );
414 Verifier &= ( pName[1] == L'V' ) || ( pName[1] == L'v' );
415 Verifier &= ( pName[2] == L'B' ) || ( pName[2] == L'b' );
416 Verifier &= ( pName[3] == L'O' ) || ( pName[3] == L'o' );
417 Verifier &= ( pName[4] == L'X' ) || ( pName[4] == L'x' );
418 Verifier &= ( pName[5] == L'S' ) || ( pName[5] == L's' );
419 /* Both vboxsvr & vboxsrv are now accepted */
420 if (( pName[6] == L'V' ) || ( pName[6] == L'v'))
421 {
422 Verifier &= ( pName[6] == L'V' ) || ( pName[6] == L'v' );
423 Verifier &= ( pName[7] == L'R' ) || ( pName[7] == L'r' );
424 }
425 else
426 {
427 Verifier &= ( pName[6] == L'R' ) || ( pName[6] == L'r' );
428 Verifier &= ( pName[7] == L'V' ) || ( pName[7] == L'v' );
429 }
430 Verifier &= ( pName[8] == L'\\') || ( pName[8] == 0 );
431
432 if (Verifier)
433 {
434 /* Full remote path */
435 if (lstrlen(DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen(pName) + 1 > sizeof(ConnectionName) / sizeof(WCHAR))
436 {
437 dwStatus = WN_BAD_NETNAME;
438 }
439 else
440 {
441 lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
442 lstrcat(ConnectionName, L"\\;");
443 lstrcat(ConnectionName, pName);
444
445 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_DELCONN,
446 ConnectionName,
447 (lstrlen(ConnectionName) + 1) * sizeof(WCHAR),
448 NULL,
449 NULL);
450 }
451 }
452 else
453 {
454 dwStatus = WN_NOT_CONNECTED;
455 }
456 }
457 }
458
459 Log(("VBOXNP: NPCancelConnection: Returned 0x%08X\n",
460 dwStatus));
461 return dwStatus;
462}
463
464DWORD APIENTRY NPGetConnection(LPWSTR pLocalName,
465 LPWSTR pRemoteName,
466 LPDWORD pBufferSize)
467{
468 DWORD dwStatus = WN_NOT_CONNECTED;
469
470 WCHAR RemoteName[128];
471 ULONG cbOut = 0;
472
473 Log(("VBOXNP: NPGetConnection: pLocalName = %ls\n",
474 pLocalName));
475
476 if (pLocalName && pLocalName[0] != 0)
477 {
478 if (pLocalName[1] == L':')
479 {
480 WCHAR LocalName[3];
481
482 cbOut = sizeof(RemoteName) - sizeof(WCHAR);
483 RemoteName[cbOut / sizeof(WCHAR)] = 0;
484
485 LocalName[0] = vboxToUpper(pLocalName[0]);
486 LocalName[1] = L':';
487 LocalName[2] = L'\0';
488
489 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETCONN,
490 LocalName,
491 sizeof(LocalName),
492 (PVOID)RemoteName,
493 &cbOut);
494
495 if (dwStatus != NO_ERROR)
496 {
497 /* The device specified by pLocalName is not redirected by this provider. */
498 dwStatus = WN_NOT_CONNECTED;
499 }
500 else
501 {
502 RemoteName[cbOut / sizeof(WCHAR)] = 0;
503
504 if (cbOut == 0)
505 {
506 dwStatus = WN_NO_NETWORK;
507 }
508 }
509 }
510 }
511
512 if (dwStatus == WN_SUCCESS)
513 {
514 ULONG cbRemoteName = (lstrlen(RemoteName) + 1) * sizeof (WCHAR); /* Including the trailing 0. */
515
516 Log(("VBOXNP: NPGetConnection: RemoteName: %ls, cb %d\n",
517 RemoteName, cbRemoteName));
518
519 DWORD len = sizeof(WCHAR) + cbRemoteName; /* Including the leading '\'. */
520
521 if (*pBufferSize >= len)
522 {
523 pRemoteName[0] = L'\\';
524 CopyMemory(&pRemoteName[1], RemoteName, cbRemoteName);
525
526 Log(("VBOXNP: NPGetConnection: returning pRemoteName: %ls\n",
527 pRemoteName));
528 }
529 else
530 {
531 if (*pBufferSize != 0)
532 {
533 /* Log only real errors. Do not log a 0 bytes try. */
534 Log(("VBOXNP: NPGetConnection: Buffer overflow: *pBufferSize = %d, len = %d\n",
535 *pBufferSize, len));
536 }
537
538 dwStatus = WN_MORE_DATA;
539 }
540
541 *pBufferSize = len;
542 }
543
544 if ((dwStatus != WN_SUCCESS) &&
545 (dwStatus != WN_MORE_DATA))
546 {
547 Log(("VBOXNP: NPGetConnection: Returned error 0x%08X\n",
548 dwStatus));
549 }
550
551 return dwStatus;
552}
553
554static const WCHAR *vboxSkipServerPrefix(const WCHAR *pRemoteName, const WCHAR *pPrefix)
555{
556 while (*pPrefix)
557 {
558 if (vboxToUpper(*pPrefix) != vboxToUpper(*pRemoteName))
559 {
560 /* Not a prefix */
561 return NULL;
562 }
563
564 pPrefix++;
565 pRemoteName++;
566 }
567
568 return pRemoteName;
569}
570
571static const WCHAR *vboxSkipServerName(const WCHAR *pRemoteName)
572{
573 int cLeadingBackslashes = 0;
574 while (*pRemoteName == L'\\')
575 {
576 pRemoteName++;
577 cLeadingBackslashes++;
578 }
579
580 if (cLeadingBackslashes == 0 || cLeadingBackslashes == 2)
581 {
582 const WCHAR *pAfterPrefix = vboxSkipServerPrefix(pRemoteName, MRX_VBOX_SERVER_NAME_U);
583
584 if (!pAfterPrefix)
585 {
586 pAfterPrefix = vboxSkipServerPrefix(pRemoteName, MRX_VBOX_SERVER_NAME_ALT_U);
587 }
588
589 return pAfterPrefix;
590 }
591
592 return NULL;
593}
594
595/* Enumerate shared folders as hierarchy:
596 * VBOXSVR(container)
597 * +--------------------+
598 * | \
599 * Folder1(connectable) FolderN(connectable)
600 */
601typedef struct _NPENUMCTX
602{
603 ULONG index; /* Index of last entry returned. */
604 DWORD dwScope;
605 DWORD dwOriginalScope;
606 DWORD dwType;
607 DWORD dwUsage;
608 bool fRoot;
609} NPENUMCTX;
610
611DWORD APIENTRY NPOpenEnum(DWORD dwScope,
612 DWORD dwType,
613 DWORD dwUsage,
614 LPNETRESOURCE pNetResource,
615 LPHANDLE lphEnum)
616{
617 DWORD dwStatus;
618
619 Log(("VBOXNP: NPOpenEnum: dwScope 0x%08X, dwType 0x%08X, dwUsage 0x%08X, pNetResource %p\n",
620 dwScope, dwType, dwUsage, pNetResource));
621
622 if (dwUsage == 0)
623 {
624 /* The bitmask may be zero to match all of the flags. */
625 dwUsage = RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER;
626 }
627
628 *lphEnum = NULL;
629
630 /* Allocate the context structure. */
631 NPENUMCTX *pCtx = (NPENUMCTX *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NPENUMCTX));
632
633 if (pCtx == NULL)
634 {
635 dwStatus = WN_OUT_OF_MEMORY;
636 }
637 else
638 {
639 if (pNetResource && pNetResource->lpRemoteName)
640 {
641 Log(("VBOXNP: NPOpenEnum: pRemoteName %ls\n",
642 pNetResource->lpRemoteName));
643 }
644
645 switch (dwScope)
646 {
647 case 6: /* Advertised as WNNC_ENUM_SHAREABLE. This returns C$ system shares.
648 * NpEnumResource will return NO_MORE_ENTRIES.
649 */
650 {
651 if (pNetResource == NULL || pNetResource->lpRemoteName == NULL)
652 {
653 /* If it is NULL or if the pRemoteName field of the NETRESOURCE is NULL,
654 * the provider should enumerate the top level of its network.
655 * But system shares can't be on top level.
656 */
657 dwStatus = WN_NOT_CONTAINER;
658 break;
659 }
660
661 const WCHAR *pAfterName = vboxSkipServerName(pNetResource->lpRemoteName);
662 if ( pAfterName == NULL
663 || (*pAfterName != L'\\' && *pAfterName != 0))
664 {
665 dwStatus = WN_NOT_CONTAINER;
666 break;
667 }
668
669 /* Valid server name. */
670
671 pCtx->index = 0;
672 pCtx->dwScope = 6;
673 pCtx->dwOriginalScope = dwScope;
674 pCtx->dwType = dwType;
675 pCtx->dwUsage = dwUsage;
676
677 dwStatus = WN_SUCCESS;
678 break;
679 }
680 case RESOURCE_GLOBALNET: /* All resources on the network. */
681 {
682 if (pNetResource == NULL || pNetResource->lpRemoteName == NULL)
683 {
684 /* If it is NULL or if the pRemoteName field of the NETRESOURCE is NULL,
685 * the provider should enumerate the top level of its network.
686 */
687 pCtx->fRoot = true;
688 }
689 else
690 {
691 /* Enumerate pNetResource->lpRemoteName container, which can be only the VBOXSVR container. */
692 const WCHAR *pAfterName = vboxSkipServerName(pNetResource->lpRemoteName);
693 if ( pAfterName == NULL
694 || (*pAfterName != L'\\' && *pAfterName != 0))
695 {
696 dwStatus = WN_NOT_CONTAINER;
697 break;
698 }
699
700 /* Valid server name. */
701 pCtx->fRoot = false;
702 }
703
704 pCtx->index = 0;
705 pCtx->dwScope = RESOURCE_GLOBALNET;
706 pCtx->dwOriginalScope = dwScope;
707 pCtx->dwType = dwType;
708 pCtx->dwUsage = dwUsage;
709
710 dwStatus = WN_SUCCESS;
711 break;
712 }
713
714 case RESOURCE_CONNECTED: /* All currently connected resources. */
715 case RESOURCE_CONTEXT: /* The interpretation of this is left to the provider. Treat this as RESOURCE_GLOBALNET. */
716 {
717 pCtx->index = 0;
718 pCtx->dwScope = RESOURCE_CONNECTED;
719 pCtx->dwOriginalScope = dwScope;
720 pCtx->dwType = dwType;
721 pCtx->dwUsage = dwUsage;
722 pCtx->fRoot = false; /* Actually ignored for RESOURCE_CONNECTED. */
723
724 dwStatus = WN_SUCCESS;
725 break;
726 }
727
728 default:
729 Log(("VBOXNP: NPOpenEnum: unsupported scope 0x%lx\n",
730 dwScope));
731 dwStatus = WN_NOT_SUPPORTED;
732 break;
733 }
734 }
735
736 if (dwStatus != WN_SUCCESS)
737 {
738 Log(("VBOXNP: NPOpenEnum: Returned error 0x%08X\n",
739 dwStatus));
740 if (pCtx)
741 {
742 HeapFree(GetProcessHeap(), 0, pCtx);
743 }
744 }
745 else
746 {
747 Log(("VBOXNP: NPOpenEnum: pCtx %p\n",
748 pCtx));
749 *lphEnum = pCtx;
750 }
751
752 return dwStatus;
753}
754
755DWORD APIENTRY NPEnumResource(HANDLE hEnum,
756 LPDWORD lpcCount,
757 LPVOID pBuffer,
758 LPDWORD pBufferSize)
759{
760 DWORD dwStatus = WN_SUCCESS;
761 NPENUMCTX *pCtx = (NPENUMCTX *)hEnum;
762
763 BYTE ConnectionList[26];
764 ULONG cbOut;
765 WCHAR LocalName[3];
766 WCHAR RemoteName[128];
767 int cbRemoteName;
768
769 ULONG cbEntry = 0;
770
771 Log(("VBOXNP: NPEnumResource: hEnum %p, lpcCount %p, pBuffer %p, pBufferSize %p.\n",
772 hEnum, lpcCount, pBuffer, pBufferSize));
773
774 if (pCtx == NULL)
775 {
776 Log(("VBOXNP: NPEnumResource: WN_BAD_HANDLE\n"));
777 return WN_BAD_HANDLE;
778 }
779
780 if (lpcCount == NULL || pBuffer == NULL)
781 {
782 Log(("VBOXNP: NPEnumResource: WN_BAD_VALUE\n"));
783 return WN_BAD_VALUE;
784 }
785
786 Log(("VBOXNP: NPEnumResource: *lpcCount 0x%x, *pBufferSize 0x%x, pCtx->index %d\n",
787 *lpcCount, *pBufferSize, pCtx->index));
788
789 LPNETRESOURCE pNetResource = (LPNETRESOURCE)pBuffer;
790 ULONG cbRemaining = *pBufferSize;
791 ULONG cEntriesCopied = 0;
792 PWCHAR pStrings = (PWCHAR)((PBYTE)pBuffer + *pBufferSize);
793 PWCHAR pDst;
794
795 if (pCtx->dwScope == RESOURCE_CONNECTED)
796 {
797 Log(("VBOXNP: NPEnumResource: RESOURCE_CONNECTED\n"));
798
799 memset(ConnectionList, 0, sizeof(ConnectionList));
800 cbOut = sizeof(ConnectionList);
801
802 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETLIST,
803 NULL, 0,
804 ConnectionList,
805 &cbOut);
806
807 if (dwStatus == WN_SUCCESS && cbOut > 0)
808 {
809 while (cEntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList))
810 {
811 if (ConnectionList[pCtx->index])
812 {
813 LocalName[0] = L'A' + (WCHAR)pCtx->index;
814 LocalName[1] = L':';
815 LocalName[2] = L'\0';
816 memset(RemoteName, 0, sizeof(RemoteName));
817 cbOut = sizeof(RemoteName);
818
819 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETCONN,
820 LocalName,
821 sizeof(LocalName),
822 RemoteName,
823 &cbOut);
824
825 if (dwStatus != WN_SUCCESS || cbOut == 0)
826 {
827 dwStatus = WN_NO_MORE_ENTRIES;
828 break;
829 }
830
831 /* How many bytes is needed for the current NETRESOURCE data. */
832 cbRemoteName = (lstrlen(RemoteName) + 1) * sizeof(WCHAR);
833 cbEntry = sizeof(NETRESOURCE);
834 cbEntry += sizeof(LocalName);
835 cbEntry += sizeof(WCHAR) + cbRemoteName; /* Leading \. */
836 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U);
837
838 if (cbEntry > cbRemaining)
839 {
840 break;
841 }
842
843 cbRemaining -= cbEntry;
844
845 memset(pNetResource, 0, sizeof (*pNetResource));
846
847 pNetResource->dwScope = RESOURCE_CONNECTED;
848 pNetResource->dwType = RESOURCETYPE_DISK;
849 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
850 pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
851
852 /* Reserve the space in the string area. */
853 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
854 pDst = pStrings;
855
856 pNetResource->lpLocalName = pDst;
857 *pDst++ = L'A' + (WCHAR)pCtx->index;
858 *pDst++ = L':';
859 *pDst++ = L'\0';
860
861 pNetResource->lpRemoteName = pDst;
862 *pDst++ = L'\\';
863 CopyMemory(pDst, RemoteName, cbRemoteName);
864 pDst += cbRemoteName / sizeof(WCHAR);
865
866 pNetResource->lpComment = NULL;
867
868 pNetResource->lpProvider = pDst;
869 CopyMemory(pDst, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
870
871 Log(("VBOXNP: NPEnumResource: pRemoteName: %ls\n",
872 pNetResource->lpRemoteName));
873
874 cEntriesCopied++;
875 pNetResource++;
876 }
877
878 pCtx->index++;
879 }
880 }
881 else
882 {
883 dwStatus = WN_NO_MORE_ENTRIES;
884 }
885 }
886 else if (pCtx->dwScope == RESOURCE_GLOBALNET)
887 {
888 Log(("VBOXNP: NPEnumResource: RESOURCE_GLOBALNET: root %d\n", pCtx->fRoot));
889
890 if (pCtx->fRoot)
891 {
892 /* VBOXSVR container. */
893 if (pCtx->index > 0)
894 {
895 dwStatus = WN_NO_MORE_ENTRIES;
896 }
897 else
898 {
899 /* Return VBOXSVR server.
900 * Determine the space needed for this entry.
901 */
902 cbEntry = sizeof(NETRESOURCE);
903 cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + the server name */
904 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U);
905
906 if (cbEntry > cbRemaining)
907 {
908 /* Do nothing. */
909 }
910 else
911 {
912 cbRemaining -= cbEntry;
913
914 memset(pNetResource, 0, sizeof (*pNetResource));
915
916 pNetResource->dwScope = RESOURCE_GLOBALNET;
917 pNetResource->dwType = RESOURCETYPE_ANY;
918 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
919 pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
920
921 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
922 pDst = pStrings;
923
924 pNetResource->lpLocalName = NULL;
925
926 pNetResource->lpRemoteName = pDst;
927 *pDst++ = L'\\';
928 *pDst++ = L'\\';
929 CopyMemory(pDst, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U));
930 pDst += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR);
931
932 pNetResource->lpComment = NULL;
933
934 pNetResource->lpProvider = pDst;
935 CopyMemory(pDst, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
936
937 cEntriesCopied++;
938
939 pCtx->index++;
940 }
941 }
942 }
943 else
944 {
945 /* Shares of VBOXSVR. */
946 memset(ConnectionList, 0, sizeof (ConnectionList));
947 cbOut = sizeof(ConnectionList);
948
949 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETGLOBALLIST,
950 NULL,
951 0,
952 ConnectionList,
953 &cbOut);
954
955 if (dwStatus == WN_SUCCESS && cbOut > 0)
956 {
957 while (cEntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList))
958 {
959 if (ConnectionList[pCtx->index])
960 {
961 memset(RemoteName, 0, sizeof(RemoteName));
962 cbOut = sizeof(RemoteName);
963
964 dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETGLOBALCONN,
965 &ConnectionList[pCtx->index],
966 sizeof(ConnectionList[pCtx->index]),
967 RemoteName,
968 &cbOut);
969
970 if (dwStatus != WN_SUCCESS || cbOut == 0)
971 {
972 dwStatus = WN_NO_MORE_ENTRIES;
973 break;
974 }
975
976 /* How many bytes is needed for the current NETRESOURCE data. */
977 cbRemoteName = (lstrlen(RemoteName) + 1) * sizeof(WCHAR);
978 cbEntry = sizeof(NETRESOURCE);
979 /* Remote name: \\ + vboxsvr + \ + name. */
980 cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U) + cbRemoteName;
981 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U);
982
983 if (cbEntry > cbRemaining)
984 {
985 break;
986 }
987
988 cbRemaining -= cbEntry;
989
990 memset(pNetResource, 0, sizeof (*pNetResource));
991
992 pNetResource->dwScope = pCtx->dwOriginalScope;
993 pNetResource->dwType = RESOURCETYPE_DISK;
994 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
995 pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
996
997 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
998 pDst = pStrings;
999
1000 pNetResource->lpLocalName = NULL;
1001
1002 pNetResource->lpRemoteName = pDst;
1003 *pDst++ = L'\\';
1004 *pDst++ = L'\\';
1005 CopyMemory(pDst, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof(WCHAR));
1006 pDst += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
1007 *pDst++ = L'\\';
1008 CopyMemory(pDst, RemoteName, cbRemoteName);
1009 pDst += cbRemoteName / sizeof(WCHAR);
1010
1011 pNetResource->lpComment = NULL;
1012
1013 pNetResource->lpProvider = pDst;
1014 CopyMemory(pDst, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
1015
1016 Log(("VBOXNP: NPEnumResource: pRemoteName: %ls\n",
1017 pNetResource->lpRemoteName));
1018
1019 cEntriesCopied++;
1020 pNetResource++;
1021 }
1022
1023 pCtx->index++;
1024 }
1025 }
1026 else
1027 {
1028 dwStatus = WN_NO_MORE_ENTRIES;
1029 }
1030 }
1031 }
1032 else if (pCtx->dwScope == 6)
1033 {
1034 Log(("VBOXNP: NPEnumResource: dwScope 6\n"));
1035 dwStatus = WN_NO_MORE_ENTRIES;
1036 }
1037 else
1038 {
1039 Log(("VBOXNP: NPEnumResource: invalid dwScope 0x%x\n",
1040 pCtx->dwScope));
1041 return WN_BAD_HANDLE;
1042 }
1043
1044 *lpcCount = cEntriesCopied;
1045
1046 if (cEntriesCopied == 0 && dwStatus == WN_SUCCESS)
1047 {
1048 if (pCtx->index >= RTL_NUMBER_OF(ConnectionList))
1049 {
1050 dwStatus = WN_NO_MORE_ENTRIES;
1051 }
1052 else
1053 {
1054 Log(("VBOXNP: NPEnumResource: More Data Needed - %d\n",
1055 cbEntry));
1056 *pBufferSize = cbEntry;
1057 dwStatus = WN_MORE_DATA;
1058 }
1059 }
1060
1061 Log(("VBOXNP: NPEnumResource: Entries returned %d, dwStatus 0x%08X\n",
1062 cEntriesCopied, dwStatus));
1063 return dwStatus;
1064}
1065
1066DWORD APIENTRY NPCloseEnum(HANDLE hEnum)
1067{
1068 NPENUMCTX *pCtx = (NPENUMCTX *)hEnum;
1069
1070 Log(("VBOXNP: NPCloseEnum: hEnum %p\n",
1071 hEnum));
1072
1073 if (pCtx)
1074 {
1075 HeapFree(GetProcessHeap(), 0, pCtx);
1076 }
1077
1078 Log(("VBOXNP: NPCloseEnum: returns\n"));
1079 return WN_SUCCESS;
1080}
1081
1082DWORD APIENTRY NPGetResourceParent(LPNETRESOURCE pNetResource,
1083 LPVOID pBuffer,
1084 LPDWORD pBufferSize)
1085{
1086 Log(("VBOXNP: NPGetResourceParent: pNetResource %p, pBuffer %p, pBufferSize %p\n",
1087 pNetResource, pBuffer, pBufferSize));
1088
1089 /* Construct a new NETRESOURCE which is syntactically a parent of pNetResource,
1090 * then call NPGetResourceInformation to actually fill the buffer.
1091 */
1092 if (!pNetResource || !pNetResource->lpRemoteName || !pBufferSize)
1093 {
1094 return WN_BAD_NETNAME;
1095 }
1096
1097 const WCHAR *pAfterName = vboxSkipServerName(pNetResource->lpRemoteName);
1098 if ( pAfterName == NULL
1099 || (*pAfterName != L'\\' && *pAfterName != 0))
1100 {
1101 Log(("VBOXNP: NPGetResourceParent: WN_BAD_NETNAME\n"));
1102 return WN_BAD_NETNAME;
1103 }
1104
1105 DWORD RemoteNameLength = lstrlen(pNetResource->lpRemoteName);
1106
1107 DWORD cbEntry = sizeof (NETRESOURCE);
1108 cbEntry += (RemoteNameLength + 1) * sizeof (WCHAR);
1109
1110 NETRESOURCE *pParent = (NETRESOURCE *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbEntry);
1111
1112 if (!pParent)
1113 {
1114 return WN_OUT_OF_MEMORY;
1115 }
1116
1117 pParent->lpRemoteName = (WCHAR *)((PBYTE)pParent + sizeof (NETRESOURCE));
1118 lstrcpy(pParent->lpRemoteName, pNetResource->lpRemoteName);
1119
1120 /* Remove last path component of the pParent->lpRemoteName. */
1121 WCHAR *pLastSlash = pParent->lpRemoteName + RemoteNameLength;
1122 if (*pLastSlash == L'\\')
1123 {
1124 /* \\server\share\path\, skip last slash immediately. */
1125 pLastSlash--;
1126 }
1127
1128 while (pLastSlash != pParent->lpRemoteName)
1129 {
1130 if (*pLastSlash == L'\\')
1131 {
1132 break;
1133 }
1134
1135 pLastSlash--;
1136 }
1137
1138 DWORD dwStatus = WN_SUCCESS;
1139
1140 if ( pLastSlash == pParent->lpRemoteName
1141 || pLastSlash == pParent->lpRemoteName + 1)
1142 {
1143 /* It is a leading backslash. Construct "no parent" NETRESOURCE. */
1144 NETRESOURCE *pNetResource = (NETRESOURCE *)pBuffer;
1145
1146 cbEntry = sizeof(NETRESOURCE);
1147 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* remote name */
1148 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
1149
1150 if (cbEntry > *pBufferSize)
1151 {
1152 Log(("VBOXNP: NPGetResourceParent: WN_MORE_DATA 0x%x\n", cbEntry));
1153 *pBufferSize = cbEntry;
1154 dwStatus = WN_MORE_DATA;
1155 }
1156 else
1157 {
1158 memset (pNetResource, 0, sizeof (*pNetResource));
1159
1160 pNetResource->dwType = RESOURCETYPE_ANY;
1161 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
1162 pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
1163
1164 WCHAR *pStrings = (WCHAR *)((PBYTE)pBuffer + *pBufferSize);
1165 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
1166
1167 pNetResource->lpRemoteName = pStrings;
1168 CopyMemory (pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
1169 pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
1170
1171 pNetResource->lpProvider = pStrings;
1172 CopyMemory (pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
1173 pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
1174
1175 Log(("VBOXNP: NPGetResourceParent: no parent, strings %p/%p\n",
1176 pStrings, (PBYTE)pBuffer + *pBufferSize));
1177 }
1178 }
1179 else
1180 {
1181 /* Make the parent remote name and get its information. */
1182 *pLastSlash = 0;
1183
1184 LPWSTR pSystem = NULL;
1185 dwStatus = NPGetResourceInformation (pParent, pBuffer, pBufferSize, &pSystem);
1186 }
1187
1188 if (pParent)
1189 {
1190 HeapFree(GetProcessHeap(), 0, pParent);
1191 }
1192
1193 return dwStatus;
1194}
1195
1196DWORD APIENTRY NPGetResourceInformation(LPNETRESOURCE pNetResource,
1197 LPVOID pBuffer,
1198 LPDWORD pBufferSize,
1199 LPWSTR *lplpSystem)
1200{
1201 Log(("VBOXNP: NPGetResourceInformation: pNetResource %p, pBuffer %p, pBufferSize %p, lplpSystem %p\n",
1202 pNetResource, pBuffer, pBufferSize, lplpSystem));
1203
1204 if ( pNetResource == NULL
1205 || pNetResource->lpRemoteName == NULL
1206 || pBufferSize == NULL)
1207 {
1208 Log(("VBOXNP: NPGetResourceInformation: WN_BAD_VALUE\n"));
1209 return WN_BAD_VALUE;
1210 }
1211
1212 Log(("VBOXNP: NPGetResourceInformation: pRemoteName %ls, *pBufferSize 0x%x\n",
1213 pNetResource->lpRemoteName, *pBufferSize));
1214
1215 const WCHAR *pAfterName = vboxSkipServerName(pNetResource->lpRemoteName);
1216 if ( pAfterName == NULL
1217 || (*pAfterName != L'\\' && *pAfterName != 0))
1218 {
1219 Log(("VBOXNP: NPGetResourceInformation: WN_BAD_NETNAME\n"));
1220 return WN_BAD_NETNAME;
1221 }
1222
1223 if (pNetResource->dwType != 0 && pNetResource->dwType != RESOURCETYPE_DISK)
1224 {
1225 /* The caller passed in a nonzero dwType that does not match
1226 * the actual type of the network resource.
1227 */
1228 return WN_BAD_DEV_TYPE;
1229 }
1230
1231 /*
1232 * If the input remote resource name was "\\server\share\dir1\dir2",
1233 * then the output NETRESOURCE contains information about the resource "\\server\share".
1234 * The pRemoteName, pProvider, dwType, dwDisplayType, and dwUsage fields are returned
1235 * containing values, all other fields being set to NULL.
1236 */
1237 DWORD cbEntry;
1238 WCHAR *pStrings = (WCHAR *)((PBYTE)pBuffer + *pBufferSize);
1239 NETRESOURCE *pNetResourceInfo = (NETRESOURCE *)pBuffer;
1240
1241 /* Check what kind of the resource is that by parsing path components.
1242 * pAfterName points to first WCHAR after a valid server name.
1243 */
1244
1245 if (pAfterName[0] == 0 || pAfterName[1] == 0)
1246 {
1247 /* "\\VBOXSVR" or "\\VBOXSVR\" */
1248 cbEntry = sizeof(NETRESOURCE);
1249 cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name */
1250 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
1251
1252 if (cbEntry > *pBufferSize)
1253 {
1254 Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", cbEntry));
1255 *pBufferSize = cbEntry;
1256 return WN_MORE_DATA;
1257 }
1258
1259 memset(pNetResourceInfo, 0, sizeof (*pNetResourceInfo));
1260
1261 pNetResourceInfo->dwType = RESOURCETYPE_ANY;
1262 pNetResourceInfo->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1263 pNetResourceInfo->dwUsage = RESOURCEUSAGE_CONTAINER;
1264
1265 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
1266
1267 pNetResourceInfo->lpRemoteName = pStrings;
1268 *pStrings++ = L'\\';
1269 *pStrings++ = L'\\';
1270 CopyMemory (pStrings, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U));
1271 pStrings += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR);
1272
1273 pNetResourceInfo->lpProvider = pStrings;
1274 CopyMemory (pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
1275 pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
1276
1277 Log(("VBOXNP: NPGetResourceInformation: pRemoteName: %ls, strings %p/%p\n",
1278 pNetResourceInfo->lpRemoteName, pStrings, (PBYTE)pBuffer + *pBufferSize));
1279
1280 if (lplpSystem)
1281 {
1282 *lplpSystem = NULL;
1283 }
1284
1285 return WN_SUCCESS;
1286 }
1287
1288 /* *pAfterName == L'\\', could be share or share + path.
1289 * Check if there are more path components after the share name.
1290 */
1291 const WCHAR *lp = pAfterName + 1;
1292 while (*lp && *lp != L'\\')
1293 {
1294 lp++;
1295 }
1296
1297 if (*lp == 0)
1298 {
1299 /* It is a share only: \\vboxsvr\share */
1300 cbEntry = sizeof(NETRESOURCE);
1301 cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */
1302 cbEntry += (DWORD)((lp - pAfterName) * sizeof(WCHAR)); /* The share name with leading \\ */
1303 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
1304
1305 if (cbEntry > *pBufferSize)
1306 {
1307 Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", cbEntry));
1308 *pBufferSize = cbEntry;
1309 return WN_MORE_DATA;
1310 }
1311
1312 memset(pNetResourceInfo, 0, sizeof (*pNetResourceInfo));
1313
1314 pNetResourceInfo->dwType = RESOURCETYPE_DISK;
1315 pNetResourceInfo->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
1316 pNetResourceInfo->dwUsage = RESOURCEUSAGE_CONNECTABLE;
1317
1318 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
1319
1320 pNetResourceInfo->lpRemoteName = pStrings;
1321 *pStrings++ = L'\\';
1322 *pStrings++ = L'\\';
1323 CopyMemory(pStrings, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR));
1324 pStrings += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
1325 CopyMemory (pStrings, pAfterName, (lp - pAfterName + 1) * sizeof(WCHAR));
1326 pStrings += lp - pAfterName + 1;
1327
1328 pNetResourceInfo->lpProvider = pStrings;
1329 CopyMemory(pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
1330 pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
1331
1332 Log(("VBOXNP: NPGetResourceInformation: pRemoteName: %ls, strings %p/%p\n",
1333 pNetResourceInfo->lpRemoteName, pStrings, (PBYTE)pBuffer + *pBufferSize));
1334
1335 if (lplpSystem)
1336 {
1337 *lplpSystem = NULL;
1338 }
1339
1340 return WN_SUCCESS;
1341 }
1342
1343 /* \\vboxsvr\share\path */
1344 cbEntry = sizeof(NETRESOURCE);
1345 cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */
1346 cbEntry += (DWORD)((lp - pAfterName) * sizeof(WCHAR)); /* The share name with leading \\ */
1347 cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
1348 cbEntry += (lstrlen(lp) + 1) * sizeof (WCHAR); /* path string for lplpSystem */
1349
1350 if (cbEntry > *pBufferSize)
1351 {
1352 Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", cbEntry));
1353 *pBufferSize = cbEntry;
1354 return WN_MORE_DATA;
1355 }
1356
1357 memset(pNetResourceInfo, 0, sizeof (*pNetResourceInfo));
1358
1359 pNetResourceInfo->dwType = RESOURCETYPE_DISK;
1360 pNetResourceInfo->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
1361 pNetResourceInfo->dwUsage = RESOURCEUSAGE_CONNECTABLE;
1362
1363 pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
1364
1365 /* The server + share. */
1366 pNetResourceInfo->lpRemoteName = pStrings;
1367 *pStrings++ = L'\\';
1368 *pStrings++ = L'\\';
1369 CopyMemory (pStrings, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR));
1370 pStrings += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
1371 CopyMemory(pStrings, pAfterName, (lp - pAfterName) * sizeof(WCHAR));
1372 pStrings += lp - pAfterName;
1373 *pStrings++ = 0;
1374
1375 pNetResourceInfo->lpProvider = pStrings;
1376 CopyMemory(pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
1377 pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
1378
1379 if (lplpSystem)
1380 {
1381 *lplpSystem = pStrings;
1382 }
1383
1384 lstrcpy(pStrings, lp);
1385 pStrings += lstrlen(lp) + 1;
1386
1387 Log(("VBOXNP: NPGetResourceInformation: pRemoteName: %ls, strings %p/%p\n",
1388 pNetResourceInfo->lpRemoteName, pStrings, (PBYTE)pBuffer + *pBufferSize));
1389 Log(("VBOXNP: NPGetResourceInformation: *lplpSystem: %ls\n", *lplpSystem));
1390
1391 return WN_SUCCESS;
1392}
1393
1394DWORD APIENTRY NPGetUniversalName(LPCWSTR pLocalPath,
1395 DWORD dwInfoLevel,
1396 LPVOID pBuffer,
1397 LPDWORD pBufferSize)
1398{
1399 DWORD dwStatus;
1400
1401 DWORD BufferRequired = 0;
1402 DWORD RemoteNameLength = 0;
1403 DWORD RemainingPathLength = 0;
1404
1405 WCHAR LocalDrive[3];
1406
1407 const WCHAR *pRemainingPath;
1408 WCHAR *pString;
1409
1410 Log(("VBOXNP: NPGetUniversalName: pLocalPath = %ls, InfoLevel = %d, *pBufferSize = %d\n",
1411 pLocalPath, dwInfoLevel, *pBufferSize));
1412
1413 /* Check is input parameter is OK. */
1414 if ( dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL
1415 && dwInfoLevel != REMOTE_NAME_INFO_LEVEL)
1416 {
1417 Log(("VBOXNP: NPGetUniversalName: Bad dwInfoLevel value: %d\n",
1418 dwInfoLevel));
1419 return WN_BAD_LEVEL;
1420 }
1421
1422 /* The 'lpLocalPath' is "X:\something". Extract the "X:" to pass to NPGetConnection. */
1423 if ( pLocalPath == NULL
1424 || pLocalPath[0] == 0
1425 || pLocalPath[1] != L':')
1426 {
1427 Log(("VBOXNP: NPGetUniversalName: Bad pLocalPath.\n"));
1428 return WN_BAD_LOCALNAME;
1429 }
1430
1431 LocalDrive[0] = pLocalPath[0];
1432 LocalDrive[1] = pLocalPath[1];
1433 LocalDrive[2] = 0;
1434
1435 /* Length of the original path without the driver letter, including trailing NULL. */
1436 pRemainingPath = &pLocalPath[2];
1437 RemainingPathLength = (DWORD)((wcslen(pRemainingPath) + 1) * sizeof(WCHAR));
1438
1439 /* Build the required structure in place of the supplied buffer. */
1440 if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL)
1441 {
1442 LPUNIVERSAL_NAME_INFOW pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)pBuffer;
1443
1444 BufferRequired = sizeof (UNIVERSAL_NAME_INFOW);
1445
1446 if (*pBufferSize >= BufferRequired)
1447 {
1448 /* Enough place for the structure. */
1449 pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)pBuffer + sizeof(UNIVERSAL_NAME_INFOW));
1450
1451 /* At least so many bytes are available for obtaining the remote name. */
1452 RemoteNameLength = *pBufferSize - BufferRequired;
1453 }
1454 else
1455 {
1456 RemoteNameLength = 0;
1457 }
1458
1459 /* Put the remote name directly to the buffer if possible and get the name length. */
1460 dwStatus = NPGetConnection(LocalDrive,
1461 RemoteNameLength? pUniversalNameInfo->lpUniversalName: NULL,
1462 &RemoteNameLength);
1463
1464 if ( dwStatus != WN_SUCCESS
1465 && dwStatus != WN_MORE_DATA)
1466 {
1467 if (dwStatus != WN_NOT_CONNECTED)
1468 {
1469 Log(("VBOXNP: NPGetUniversalName: NPGetConnection returned error 0x%lx\n",
1470 dwStatus));
1471 }
1472 return dwStatus;
1473 }
1474
1475 if (RemoteNameLength < sizeof (WCHAR))
1476 {
1477 Log(("VBOXNP: NPGetUniversalName: Remote name is empty.\n"));
1478 return WN_NO_NETWORK;
1479 }
1480
1481 /* Adjust for actual remote name length. */
1482 BufferRequired += RemoteNameLength;
1483
1484 /* And for required place for remaining path. */
1485 BufferRequired += RemainingPathLength;
1486
1487 if (*pBufferSize < BufferRequired)
1488 {
1489 Log(("VBOXNP: NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n",
1490 BufferRequired));
1491 *pBufferSize = BufferRequired;
1492 return WN_MORE_DATA;
1493 }
1494
1495 /* Enough memory in the buffer. Add '\' and remaining path to the remote name. */
1496 pString = &pUniversalNameInfo->lpUniversalName[RemoteNameLength / sizeof (WCHAR)];
1497 pString--; /* Trailing NULL */
1498
1499 CopyMemory(pString, pRemainingPath, RemainingPathLength);
1500 }
1501 else
1502 {
1503 LPREMOTE_NAME_INFOW pRemoteNameInfo = (LPREMOTE_NAME_INFOW)pBuffer;
1504 WCHAR *pDelimiter;
1505
1506 BufferRequired = sizeof (REMOTE_NAME_INFOW);
1507
1508 if (*pBufferSize >= BufferRequired)
1509 {
1510 /* Enough place for the structure. */
1511 pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)pBuffer + sizeof(REMOTE_NAME_INFOW));
1512 pRemoteNameInfo->lpConnectionName = NULL;
1513 pRemoteNameInfo->lpRemainingPath = NULL;
1514
1515 /* At least so many bytes are available for obtaining the remote name. */
1516 RemoteNameLength = *pBufferSize - BufferRequired;
1517 }
1518 else
1519 {
1520 RemoteNameLength = 0;
1521 }
1522
1523 /* Put the remote name directly to the buffer if possible and get the name length. */
1524 dwStatus = NPGetConnection(LocalDrive, RemoteNameLength? pRemoteNameInfo->lpUniversalName: NULL, &RemoteNameLength);
1525
1526 if ( dwStatus != WN_SUCCESS
1527 && dwStatus != WN_MORE_DATA)
1528 {
1529 if (dwStatus != WN_NOT_CONNECTED)
1530 {
1531 Log(("VBOXNP: NPGetUniversalName: NPGetConnection returned error 0x%lx\n", dwStatus));
1532 }
1533 return dwStatus;
1534 }
1535
1536 if (RemoteNameLength < sizeof (WCHAR))
1537 {
1538 Log(("VBOXNP: NPGetUniversalName: Remote name is empty.\n"));
1539 return WN_NO_NETWORK;
1540 }
1541
1542 /* Adjust for actual remote name length as a part of the universal name. */
1543 BufferRequired += RemoteNameLength;
1544
1545 /* And for required place for remaining path as a part of the universal name. */
1546 BufferRequired += RemainingPathLength;
1547
1548 /* pConnectionName, which is the remote name. */
1549 BufferRequired += RemoteNameLength;
1550
1551 /* pRemainingPath. */
1552 BufferRequired += RemainingPathLength;
1553
1554 if (*pBufferSize < BufferRequired)
1555 {
1556 Log(("VBOXNP: NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n",
1557 BufferRequired));
1558 *pBufferSize = BufferRequired;
1559 return WN_MORE_DATA;
1560 }
1561
1562 /* Enough memory in the buffer. Add \ and remaining path to the remote name. */
1563 pString = &pRemoteNameInfo->lpUniversalName[RemoteNameLength / sizeof (WCHAR)];
1564 pString--; /* Trailing NULL */
1565
1566 pDelimiter = pString; /* Delimiter between the remote name and the remaining path.
1567 * May be 0 if the remaining path is empty.
1568 */
1569
1570 CopyMemory( pString, pRemainingPath, RemainingPathLength);
1571 pString += RemainingPathLength / sizeof (WCHAR);
1572
1573 *pDelimiter = 0; /* Keep NULL terminated remote name. */
1574
1575 pRemoteNameInfo->lpConnectionName = pString;
1576 CopyMemory( pString, pRemoteNameInfo->lpUniversalName, RemoteNameLength);
1577 pString += RemoteNameLength / sizeof (WCHAR);
1578
1579 pRemoteNameInfo->lpRemainingPath = pString;
1580 CopyMemory( pString, pRemainingPath, RemainingPathLength);
1581
1582 /* If remaining path was not empty, restore the delimiter in the universal name. */
1583 if (RemainingPathLength > sizeof(WCHAR))
1584 {
1585 *pDelimiter = L'\\';
1586 }
1587 }
1588
1589 Log(("VBOXNP: NPGetUniversalName: WN_SUCCESS\n"));
1590 return WN_SUCCESS;
1591}
1592
1593BOOL WINAPI DllMain(HINSTANCE hDLLInst,
1594 DWORD fdwReason,
1595 LPVOID pvReserved)
1596{
1597 RT_NOREF(hDLLInst, pvReserved);
1598 BOOL fReturn = TRUE;
1599
1600 switch (fdwReason)
1601 {
1602 case DLL_PROCESS_ATTACH:
1603 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
1604 VbglR3Init();
1605 LogRel(("VBOXNP: DLL loaded.\n"));
1606 break;
1607
1608 case DLL_PROCESS_DETACH:
1609 LogRel(("VBOXNP: DLL unloaded.\n"));
1610 VbglR3Term();
1611 /// @todo RTR3Term();
1612 break;
1613
1614 case DLL_THREAD_ATTACH:
1615 break;
1616
1617 case DLL_THREAD_DETACH:
1618 break;
1619
1620 default:
1621 break;
1622 }
1623
1624 return fReturn;
1625}
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