VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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