VirtualBox

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

Last change on this file since 42219 was 40295, checked in by vboxsync, 13 years ago

VBOXSF: NPGetUniversalName fix.

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