VirtualBox

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

Last change on this file since 63081 was 63081, checked in by vboxsync, 9 years ago

NPGetResourceInformation: Local variable s/pNetResource/pNetResourceInfo/ as the name is easy to confusing with unrelated parameter lpNetResource.

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

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