VirtualBox

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

Last change on this file since 93668 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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

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