VirtualBox

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

Last change on this file since 61908 was 55401, checked in by vboxsync, 10 years ago

added a couple of missing Id headers

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