VirtualBox

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

Last change on this file since 108849 was 108849, checked in by vboxsync, 5 weeks ago

WINNT/Shared Folders/np: NPGetConnection() returns characters for *pBufferSize, not bytes. bugref:10884

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette