VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use