xref: /reactos/dll/np/nfs/nfs41_np.c (revision 5100859e)
1 /* NFSv4.1 client for Windows
2  * Copyright © 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * without any warranty; without even the implied warranty of merchantability
14  * or fitness for a particular purpose.  See the GNU Lesser General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  */
21 
22 #include <windows.h>
23 #include <npapi.h>
24 #include <devioctl.h>
25 #include <strsafe.h>
26 
27 #include "nfs41_driver.h"
28 #include "nfs41_np.h"
29 #include "options.h"
30 
31 #ifdef DBG
32 #define DbgP(_x_) NFS41DbgPrint _x_
33 #else
34 #define DbgP(_x_)
35 #endif
36 #define TRACE_TAG   L"[NFS41_NP]"
37 #define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor )
38 
39 
40 ULONG _cdecl NFS41DbgPrint( __in LPTSTR Format, ... )
41 {
42     ULONG rc = 0;
43     TCHAR szbuffer[256];
44 
45     va_list marker;
46     va_start( marker, Format );
47     {
48 
49         //StringCchVPrintfW( szbuffer, 127, Format, marker );
50         StringCchVPrintfW( szbuffer, 256, Format, marker );
51         szbuffer[255] = (TCHAR)0;
52         OutputDebugString( TRACE_TAG );
53         OutputDebugString( szbuffer );
54     }
55 
56     return rc;
57 }
58 
59 int filter(unsigned int code)
60 {
61     DbgP((L"####Got exception %u\n", code));
62     return EXCEPTION_CONTINUE_SEARCH;
63 }
64 
65 DWORD
66 OpenSharedMemory(
67     PHANDLE phMutex,
68     PHANDLE phMemory,
69     PVOID   *pMemory)
70 /*++
71 
72 Routine Description:
73 
74     This routine opens the shared memory for exclusive manipulation
75 
76 Arguments:
77 
78     phMutex - the mutex handle
79 
80     phMemory - the memory handle
81 
82     pMemory - a ptr. to the shared memory which is set if successful
83 
84 Return Value:
85 
86     WN_SUCCESS -- if successful
87 
88 --*/
89 {
90     DWORD dwStatus;
91 
92     *phMutex = 0;
93     *phMemory = 0;
94     *pMemory = NULL;
95 
96     *phMutex = CreateMutex(NULL, FALSE, TEXT(NFS41NP_MUTEX_NAME));
97     if (*phMutex == NULL)
98     {
99         dwStatus = GetLastError();
100         DbgP((TEXT("OpenSharedMemory:  OpenMutex failed\n")));
101         goto OpenSharedMemoryAbort1;
102     }
103 
104     WaitForSingleObject(*phMutex, INFINITE);
105 
106     *phMemory = OpenFileMapping(FILE_MAP_WRITE,
107                                 FALSE,
108                                 TEXT(NFS41_USER_SHARED_MEMORY_NAME));
109     if (*phMemory == NULL)
110     {
111         dwStatus = GetLastError();
112         DbgP((TEXT("OpenSharedMemory:  OpenFileMapping failed\n")));
113         goto OpenSharedMemoryAbort2;
114     }
115 
116     *pMemory = MapViewOfFile(*phMemory, FILE_MAP_WRITE, 0, 0, 0);
117     if (*pMemory == NULL)
118     {
119         dwStatus = GetLastError();
120         DbgP((TEXT("OpenSharedMemory:  MapViewOfFile failed\n")));
121         goto OpenSharedMemoryAbort3;
122     }
123 
124     return ERROR_SUCCESS;
125 
126 OpenSharedMemoryAbort3:
127     CloseHandle(*phMemory);
128 
129 OpenSharedMemoryAbort2:
130     ReleaseMutex(*phMutex);
131     CloseHandle(*phMutex);
132     *phMutex = NULL;
133 
134 OpenSharedMemoryAbort1:
135     DbgP((TEXT("OpenSharedMemory: return dwStatus: %d\n"), dwStatus));
136 
137     return dwStatus;
138 }
139 
140 VOID
141 CloseSharedMemory(
142     PHANDLE hMutex,
143     PHANDLE hMemory,
144     PVOID   *pMemory)
145 /*++
146 
147 Routine Description:
148 
149     This routine relinquishes control of the shared memory after exclusive
150     manipulation
151 
152 Arguments:
153 
154     hMutex - the mutex handle
155 
156     hMemory  - the memory handle
157 
158     pMemory - a ptr. to the shared memory which is set if successful
159 
160 Return Value:
161 
162 --*/
163 {
164     if (*pMemory)
165     {
166         UnmapViewOfFile(*pMemory);
167         *pMemory = NULL;
168     }
169     if (*hMemory)
170     {
171         CloseHandle(*hMemory);
172         *hMemory = 0;
173     }
174     if (*hMutex)
175     {
176         if (ReleaseMutex(*hMutex) == FALSE)
177         {
178             DbgP((TEXT("CloseSharedMemory: ReleaseMutex error: %d\n"), GetLastError()));
179         }
180         CloseHandle(*hMutex);
181         *hMutex = 0;
182     }
183 }
184 
185 static DWORD StoreConnectionInfo(
186     IN LPCWSTR LocalName,
187     IN LPCWSTR ConnectionName,
188     IN USHORT ConnectionNameLength,
189     IN LPNETRESOURCE lpNetResource)
190 {
191     DWORD status;
192     HANDLE hMutex, hMemory;
193     PNFS41NP_SHARED_MEMORY pSharedMemory;
194     PNFS41NP_NETRESOURCE pNfs41NetResource;
195     INT Index;
196     BOOLEAN FreeEntryFound = FALSE;
197 
198 #ifdef __REACTOS__
199     status = OpenSharedMemory(&hMutex, &hMemory, (PVOID *)&pSharedMemory);
200 #else
201     status = OpenSharedMemory(&hMutex, &hMemory, &(PVOID)pSharedMemory);
202 #endif
203     if (status)
204         goto out;
205 
206     DbgP((TEXT("StoreConnectionInfo: NextIndex %d, NumResources %d\n"),
207         pSharedMemory->NextAvailableIndex,
208         pSharedMemory->NumberOfResourcesInUse));
209 
210     for (Index = 0; Index < pSharedMemory->NextAvailableIndex; Index++)
211     {
212         if (!pSharedMemory->NetResources[Index].InUse)
213         {
214             FreeEntryFound = TRUE;
215             DbgP((TEXT("Reusing existing index %d\n"), Index));
216             break;
217         }
218     }
219 
220     if (!FreeEntryFound)
221     {
222         if (pSharedMemory->NextAvailableIndex >= NFS41NP_MAX_DEVICES) {
223             status = WN_NO_MORE_DEVICES;
224             goto out_close;
225         }
226         Index = pSharedMemory->NextAvailableIndex++;
227         DbgP((TEXT("Using new index %d\n"), Index));
228     }
229 
230     pSharedMemory->NumberOfResourcesInUse += 1;
231 
232     pNfs41NetResource = &pSharedMemory->NetResources[Index];
233 
234     pNfs41NetResource->InUse                = TRUE;
235     pNfs41NetResource->dwScope              = lpNetResource->dwScope;
236     pNfs41NetResource->dwType               = lpNetResource->dwType;
237     pNfs41NetResource->dwDisplayType        = lpNetResource->dwDisplayType;
238     pNfs41NetResource->dwUsage              = RESOURCEUSAGE_CONNECTABLE;
239     pNfs41NetResource->LocalNameLength      = (USHORT)(wcslen(LocalName) + 1) * sizeof(WCHAR);
240     pNfs41NetResource->RemoteNameLength     = (USHORT)(wcslen(lpNetResource->lpRemoteName) + 1) * sizeof(WCHAR);
241     pNfs41NetResource->ConnectionNameLength = ConnectionNameLength;
242 
243     StringCchCopy(pNfs41NetResource->LocalName,
244         pNfs41NetResource->LocalNameLength,
245         LocalName);
246     StringCchCopy(pNfs41NetResource->RemoteName,
247         pNfs41NetResource->RemoteNameLength,
248         lpNetResource->lpRemoteName);
249     StringCchCopy(pNfs41NetResource->ConnectionName,
250         pNfs41NetResource->ConnectionNameLength,
251         ConnectionName);
252 
253     // TODO: copy mount options -cbodley
254 
255 out_close:
256 #ifdef __REACTOS__
257     CloseSharedMemory(&hMutex, &hMemory, (PVOID *)&pSharedMemory);
258 #else
259     CloseSharedMemory(&hMutex, &hMemory, &(PVOID)pSharedMemory);
260 #endif
261 out:
262     return status;
263 }
264 
265 ULONG
266 SendTo_NFS41Driver(
267     IN ULONG            IoctlCode,
268     IN PVOID            InputDataBuf,
269     IN ULONG            InputDataLen,
270     IN PVOID            OutputDataBuf,
271     IN PULONG           pOutputDataLen)
272 {
273     HANDLE  DeviceHandle;       // The mini rdr device handle
274     BOOL    rc = FALSE;
275     ULONG   Status;
276 
277     Status = WN_SUCCESS;
278     DbgP((L"[aglo] calling CreateFile\n"));
279     DeviceHandle = CreateFile(
280         NFS41_USER_DEVICE_NAME,
281         GENERIC_READ | GENERIC_WRITE,
282         FILE_SHARE_READ | FILE_SHARE_WRITE,
283         (LPSECURITY_ATTRIBUTES)NULL,
284         OPEN_EXISTING,
285         0,
286         (HANDLE) NULL );
287 
288     DbgP((L"[aglo] after CreateFile Device Handle\n"));
289     if ( INVALID_HANDLE_VALUE != DeviceHandle )
290     {
291         _SEH2_TRY {
292         DbgP((L"[aglo] calling DeviceIoControl\n"));
293         rc = DeviceIoControl(
294             DeviceHandle,
295             IoctlCode,
296             InputDataBuf,
297             InputDataLen,
298             OutputDataBuf,
299             *pOutputDataLen,
300             pOutputDataLen,
301             NULL );
302         } _SEH2_EXCEPT(_SEH2_GetExceptionCode()) {
303             DbgP((L"#### In except\n"));
304         } _SEH2_END;
305         DbgP((L"[aglo] returned from DeviceIoControl %08lx\n", rc));
306             if ( !rc )
307             {
308                 DbgP((L"[aglo] SendTo_NFS41Driver: returning error from DeviceIoctl\n"));
309                 Status = GetLastError( );
310             }
311             else
312             {
313                 DbgP((L"[aglo] SendTo_NFS41Driver: The DeviceIoctl call succeded\n"));
314             }
315             CloseHandle(DeviceHandle);
316     }
317     else
318     {
319         Status = GetLastError( );
320         DbgP((L"[aglo] SendTo_NFS41Driver: error %08lx opening device \n", Status));
321     }
322     DbgP((L"[aglo] returned from SendTo_NFS41Driver %08lx\n", Status));
323     return Status;
324 }
325 
326 DWORD APIENTRY
327 NPGetCaps(
328     DWORD nIndex )
329 {
330    DWORD rc = 0;
331 
332 #ifndef __REACTOS__
333     DbgP(( L"[aglo] GetNetCaps %d\n", nIndex ));
334 #endif
335     switch ( nIndex )
336     {
337         case WNNC_SPEC_VERSION:
338             rc = WNNC_SPEC_VERSION51;
339             break;
340 
341         case WNNC_NET_TYPE:
342             rc = WNNC_NET_RDR2SAMPLE;
343             break;
344 
345         case WNNC_DRIVER_VERSION:
346             rc = WNNC_DRIVER(1, 0);
347             break;
348 
349         case WNNC_CONNECTION:
350             rc = WNNC_CON_GETCONNECTIONS |
351                  WNNC_CON_CANCELCONNECTION |
352                  WNNC_CON_ADDCONNECTION |
353                  WNNC_CON_ADDCONNECTION3;
354             break;
355 
356         case WNNC_ENUMERATION:
357             rc = WNNC_ENUM_LOCAL;
358             break;
359 
360         case WNNC_START:
361             rc = 1;
362             break;
363 
364         case WNNC_USER:
365         case WNNC_DIALOG:
366         case WNNC_ADMIN:
367         default:
368             rc = 0;
369             break;
370     }
371 
372     return rc;
373 }
374 
375 DWORD APIENTRY
376 NPLogonNotify(
377     __in PLUID   lpLogonId,
378     __in PCWSTR lpAuthentInfoType,
379     __in PVOID  lpAuthentInfo,
380     __in PCWSTR lpPreviousAuthentInfoType,
381     __in PVOID  lpPreviousAuthentInfo,
382     __in PWSTR  lpStationName,
383     __in PVOID  StationHandle,
384     __out PWSTR  *lpLogonScript)
385 {
386     *lpLogonScript = NULL;
387     DbgP(( L"[aglo] NPLogonNotify: returning WN_SUCCESS\n" ));
388     return WN_SUCCESS;
389 }
390 
391 DWORD APIENTRY
392 NPPasswordChangeNotify (
393     __in LPCWSTR lpAuthentInfoType,
394     __in LPVOID  lpAuthentInfo,
395     __in LPCWSTR lpPreviousAuthentInfoType,
396     __in LPVOID  lpPreviousAuthentInfo,
397     __in LPWSTR  lpStationName,
398     LPVOID  StationHandle,
399     DWORD   dwChangeInfo )
400 {
401     DbgP(( L"[aglo] NPPasswordChangeNotify: WN_NOT_SUPPORTED\n" ));
402     SetLastError( WN_NOT_SUPPORTED );
403     return WN_NOT_SUPPORTED;
404 }
405 
406 #ifdef __REACTOS__
407 DWORD APIENTRY
408 NPAddConnection3(
409     __in HWND           hwndOwner,
410     __in LPNETRESOURCE  lpNetResource,
411     __in_opt LPWSTR     lpPassword,
412     __in_opt LPWSTR     lpUserName,
413     __in DWORD          dwFlags);
414 #endif
415 
416 DWORD APIENTRY
417 NPAddConnection(
418     __in LPNETRESOURCE   lpNetResource,
419     __in_opt LPWSTR      lpPassword,
420     __in_opt LPWSTR      lpUserName )
421 {
422     return NPAddConnection3( NULL, lpNetResource, lpPassword, lpUserName, 0 );
423 }
424 
425 DWORD APIENTRY
426 NPAddConnection3(
427     __in HWND           hwndOwner,
428     __in LPNETRESOURCE  lpNetResource,
429     __in_opt LPWSTR     lpPassword,
430     __in_opt LPWSTR     lpUserName,
431     __in DWORD          dwFlags)
432 {
433     DWORD   Status;
434     WCHAR   wszScratch[128];
435     WCHAR   LocalName[3];
436     DWORD   CopyBytes = 0;
437     CONNECTION_INFO Connection;
438     LPWSTR  ConnectionName;
439     WCHAR ServerName[MAX_PATH];
440     PWCHAR p;
441     DWORD i;
442 
443     DbgP(( L"[aglo] NPAddConnection3('%s', '%s')\n",
444         lpNetResource->lpLocalName, lpNetResource->lpRemoteName ));
445     DbgP(( L"[aglo] username = '%s', passwd = '%s'\n", lpUserName, lpPassword));
446 
447     Status = InitializeConnectionInfo(&Connection,
448         (PMOUNT_OPTION_BUFFER)lpNetResource->lpComment,
449         &ConnectionName);
450     if (Status)  {
451         DbgP(( L"InitializeConnectionInfo failed with %d\n", Status ));
452         goto out;
453     }
454 
455     //  \device\miniredirector\;<DriveLetter>:\Server\Share
456 
457     // local name, must start with "X:"
458     if (lstrlen(lpNetResource->lpLocalName) < 2 ||
459         lpNetResource->lpLocalName[1] != L':') {
460         Status = WN_BAD_LOCALNAME;
461         goto out;
462     }
463 
464     LocalName[0] = (WCHAR) toupper(lpNetResource->lpLocalName[0]);
465     LocalName[1] = L':';
466     LocalName[2] = L'\0';
467     StringCchCopyW( ConnectionName, MAX_PATH, NFS41_DEVICE_NAME );
468     StringCchCatW( ConnectionName, MAX_PATH, L"\\;" );
469     StringCchCatW( ConnectionName, MAX_PATH, LocalName );
470 
471     // remote name, must start with "\\"
472     if (lpNetResource->lpRemoteName[0] == L'\0' ||
473         lpNetResource->lpRemoteName[0] != L'\\' ||
474         lpNetResource->lpRemoteName[1] != L'\\') {
475         Status = WN_BAD_NETNAME;
476         goto out;
477     }
478 
479     /* note: remotename comes as \\server but we need to add \server thus +1 pointer */
480     p = lpNetResource->lpRemoteName + 1;
481     ServerName[0] = L'\\';
482     i = 1;
483     for(;;) {
484         /* convert servername ending unix slash to windows slash */
485         if (p[i] == L'/')
486             p[i] = L'\\';
487         /* deal with servername ending with any slash */
488         if (p[i] == L'\0')
489             p[i] = L'\\';
490         ServerName[i] = p[i];
491         if (p[i] == L'\\') break;
492         i++;
493     }
494     ServerName[i] = L'\0';
495     StringCchCatW( ConnectionName, MAX_PATH, ServerName);
496     /* insert the "nfs4" in between the server name and the path,
497      * just to make sure all calls to our driver come thru this */
498     StringCchCatW( ConnectionName, MAX_PATH, L"\\nfs4" );
499 
500 #ifdef CONVERT_2_UNIX_SLASHES
501     /* convert all windows slashes to unix slashes */
502     {
503         PWCHAR q = p;
504         DWORD j = 0;
505         for(;;) {
506             if(q[j] == L'\0') break;
507             if (q[j] == L'\\') q[j] = L'/';
508             j++;
509         }
510     }
511 #else
512     /* convert all unix slashes to windows slashes */
513     {
514         PWCHAR q = p;
515         DWORD j = 0;
516         for(;;) {
517             if(q[j] == L'\0') break;
518             if (q[j] == L'/') q[j] = L'\\';
519             j++;
520         }
521     }
522 #endif
523     StringCchCatW( ConnectionName, MAX_PATH, &p[i]);
524     DbgP(( L"[aglo] Full Connect Name: %s\n", ConnectionName ));
525     DbgP(( L"[aglo] Full Connect Name Length: %d %d\n",
526         (wcslen(ConnectionName) + 1) * sizeof(WCHAR),
527         (lstrlen(ConnectionName) + 1) * sizeof(WCHAR)));
528 
529     if ( QueryDosDevice( LocalName, wszScratch, 128 )
530         || GetLastError() != ERROR_FILE_NOT_FOUND) {
531         Status = WN_ALREADY_CONNECTED;
532         goto out;
533     }
534 
535     MarshalConnectionInfo(&Connection);
536 
537     Status = SendTo_NFS41Driver( IOCTL_NFS41_ADDCONN,
538         Connection.Buffer, Connection.BufferSize,
539         NULL, &CopyBytes );
540     if (Status) {
541         DbgP(( L"[aglo] SendTo_NFS41Driver failed with %d\n", Status));
542         goto out;
543     }
544 
545     DbgP(( L"[aglo] calling DefineDosDevice\n"));
546     if ( !DefineDosDevice( DDD_RAW_TARGET_PATH |
547                            DDD_NO_BROADCAST_SYSTEM,
548                            lpNetResource->lpLocalName,
549                            ConnectionName ) ) {
550         Status = GetLastError();
551         DbgP(( L"[aglo] DefineDosDevice failed with %d\n", Status));
552         goto out_delconn;
553     }
554 
555     // The connection was established and the local device mapping
556     // added. Include this in the list of mapped devices.
557     Status = StoreConnectionInfo(LocalName, ConnectionName,
558         Connection.Buffer->NameLength, lpNetResource);
559     if (Status) {
560         DbgP(( L"[aglo] StoreConnectionInfo failed with %d\n", Status));
561         goto out_undefine;
562     }
563 
564 out:
565     FreeConnectionInfo(&Connection);
566     DbgP(( L"[aglo] NPAddConnection3: status %08X\n", Status));
567     return Status;
568 out_undefine:
569     DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH |
570         DDD_EXACT_MATCH_ON_REMOVE, LocalName, ConnectionName);
571 out_delconn:
572     SendTo_NFS41Driver(IOCTL_NFS41_DELCONN, ConnectionName,
573         Connection.Buffer->NameLength, NULL, &CopyBytes);
574     goto out;
575 }
576 
577 DWORD APIENTRY
578 NPCancelConnection(
579     __in LPWSTR  lpName,
580     __in BOOL    fForce )
581 {
582     DWORD   Status = 0;
583 
584     HANDLE  hMutex, hMemory;
585     PNFS41NP_SHARED_MEMORY  pSharedMemory;
586 
587     DbgP((TEXT("NPCancelConnection\n")));
588     DbgP((TEXT("NPCancelConnection: ConnectionName: %S\n"), lpName));
589 
590     Status = OpenSharedMemory( &hMutex,
591                                &hMemory,
592                                (PVOID)&pSharedMemory);
593 
594     if (Status == WN_SUCCESS)
595     {
596         INT  Index;
597         PNFS41NP_NETRESOURCE pNetResource;
598         Status = WN_NOT_CONNECTED;
599 
600         DbgP((TEXT("NPCancelConnection: NextIndex %d, NumResources %d\n"),
601                     pSharedMemory->NextAvailableIndex,
602                     pSharedMemory->NumberOfResourcesInUse));
603 
604         for (Index = 0; Index < pSharedMemory->NextAvailableIndex; Index++)
605         {
606             pNetResource = &pSharedMemory->NetResources[Index];
607 
608             if (pNetResource->InUse)
609             {
610                 if ( ( (wcslen(lpName) + 1) * sizeof(WCHAR) ==
611                         pNetResource->LocalNameLength)
612                         && ( !wcscmp(lpName, pNetResource->LocalName) ))
613                 {
614                     ULONG CopyBytes;
615 
616                     DbgP((TEXT("NPCancelConnection: Connection Found:\n")));
617 
618                     CopyBytes = 0;
619 
620                     Status = SendTo_NFS41Driver( IOCTL_NFS41_DELCONN,
621                                 pNetResource->ConnectionName,
622                                 pNetResource->ConnectionNameLength,
623                                 NULL,
624                                 &CopyBytes );
625 
626                     if (Status != WN_SUCCESS)
627                     {
628                         DbgP((TEXT("NPCancelConnection: SendToMiniRdr returned Status %lx\n"),Status));
629                         break;
630                     }
631 
632                     if (DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
633                             lpName,
634                             pNetResource->ConnectionName) == FALSE)
635                     {
636                         DbgP((TEXT("RemoveDosDevice:  DefineDosDevice error: %d\n"), GetLastError()));
637                         Status = GetLastError();
638                     }
639                     else
640                     {
641                         pNetResource->InUse = FALSE;
642                         pSharedMemory->NumberOfResourcesInUse--;
643 
644                         if (Index+1 == pSharedMemory->NextAvailableIndex)
645                             pSharedMemory->NextAvailableIndex--;
646                     }
647                     break;
648                 }
649 
650                 DbgP((TEXT("NPCancelConnection: Name %S EntryName %S\n"),
651                             lpName,pNetResource->LocalName));
652 #ifndef __REACTOS__
653                 DbgP((TEXT("NPCancelConnection: Name Length %d Entry Name Length %d\n"),
654                            pNetResource->LocalNameLength,pNetResource->LocalName));
655 #else
656                 DbgP((TEXT("NPCancelConnection: Name Length %d Entry Name Length %d\n"),
657                            (wcslen(lpName) + 1) * sizeof(WCHAR), pNetResource->LocalNameLength));
658 #endif
659 
660             }
661         }
662 
663         CloseSharedMemory( &hMutex,
664                            &hMemory,
665                           (PVOID)&pSharedMemory);
666     }
667 
668     return Status;
669 }
670 
671 DWORD APIENTRY
672 NPGetConnection(
673     __in LPWSTR  lpLocalName,
674     __out_bcount(*lpBufferSize) LPWSTR  lpRemoteName,
675     __inout LPDWORD lpBufferSize )
676 {
677     DWORD   Status = 0;
678 
679     HANDLE  hMutex, hMemory;
680     PNFS41NP_SHARED_MEMORY  pSharedMemory;
681 
682     Status = OpenSharedMemory( &hMutex,
683                                &hMemory,
684                                (PVOID)&pSharedMemory);
685 
686     if (Status == WN_SUCCESS)
687     {
688         INT  Index;
689         PNFS41NP_NETRESOURCE pNetResource;
690         Status = WN_NOT_CONNECTED;
691 
692         for (Index = 0; Index < pSharedMemory->NextAvailableIndex; Index++)
693         {
694             pNetResource = &pSharedMemory->NetResources[Index];
695 
696             if (pNetResource->InUse)
697             {
698                 if ( ( (wcslen(lpLocalName) + 1) * sizeof(WCHAR) ==
699                         pNetResource->LocalNameLength)
700                         && ( !wcscmp(lpLocalName, pNetResource->LocalName) ))
701                 {
702                     if (*lpBufferSize < pNetResource->RemoteNameLength)
703                     {
704                         *lpBufferSize = pNetResource->RemoteNameLength;
705                         Status = WN_MORE_DATA;
706                     }
707                     else
708                     {
709                         *lpBufferSize = pNetResource->RemoteNameLength;
710                         CopyMemory( lpRemoteName,
711                                     pNetResource->RemoteName,
712                                     pNetResource->RemoteNameLength);
713                         Status = WN_SUCCESS;
714                     }
715                     break;
716                 }
717             }
718         }
719 
720         CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory);
721     }
722 
723     return Status;
724 }
725 
726 DWORD APIENTRY
727 NPOpenEnum(
728     DWORD          dwScope,
729     DWORD          dwType,
730     DWORD          dwUsage,
731     LPNETRESOURCE  lpNetResource,
732     LPHANDLE       lphEnum )
733 {
734     DWORD   Status;
735 
736     DbgP((L"[aglo] NPOpenEnum\n"));
737 
738     *lphEnum = NULL;
739 
740     switch ( dwScope )
741     {
742         case RESOURCE_CONNECTED:
743         {
744             *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( ULONG ) );
745 
746             if (*lphEnum )
747             {
748                 Status = WN_SUCCESS;
749             }
750             else
751             {
752                 Status = WN_OUT_OF_MEMORY;
753             }
754             break;
755         }
756         break;
757 
758         case RESOURCE_CONTEXT:
759         default:
760             Status  = WN_NOT_SUPPORTED;
761             break;
762     }
763 
764 
765     DbgP((L"[aglo] NPOpenEnum returning Status %lx\n",Status));
766 
767     return(Status);
768 }
769 
770 DWORD APIENTRY
771 NPEnumResource(
772     HANDLE  hEnum,
773     LPDWORD lpcCount,
774     LPVOID  lpBuffer,
775     LPDWORD lpBufferSize)
776 {
777     DWORD           Status = WN_SUCCESS;
778     ULONG           EntriesCopied;
779     LPNETRESOURCE   pNetResource;
780     ULONG           SpaceNeeded = 0;
781     ULONG           SpaceAvailable;
782     PWCHAR          StringZone;
783     HANDLE  hMutex, hMemory;
784     PNFS41NP_SHARED_MEMORY  pSharedMemory;
785     PNFS41NP_NETRESOURCE pNfsNetResource;
786     INT  Index = *(PULONG)hEnum;
787 
788 
789     DbgP((L"[aglo] NPEnumResource\n"));
790 
791     DbgP((L"[aglo] NPEnumResource Count Requested %d\n", *lpcCount));
792 
793     pNetResource = (LPNETRESOURCE) lpBuffer;
794     SpaceAvailable = *lpBufferSize;
795     EntriesCopied = 0;
796     StringZone = (PWCHAR) ((PBYTE)lpBuffer + *lpBufferSize);
797 
798     Status = OpenSharedMemory( &hMutex,
799                                &hMemory,
800                                (PVOID)&pSharedMemory);
801 
802     if ( Status == WN_SUCCESS)
803     {
804         Status = WN_NO_MORE_ENTRIES;
805         for (Index = *(PULONG)hEnum; EntriesCopied < *lpcCount &&
806                 Index < pSharedMemory->NextAvailableIndex; Index++)
807         {
808             pNfsNetResource = &pSharedMemory->NetResources[Index];
809 
810             if (pNfsNetResource->InUse)
811             {
812                 SpaceNeeded  = sizeof( NETRESOURCE );
813                 SpaceNeeded += pNfsNetResource->LocalNameLength;
814                 SpaceNeeded += pNfsNetResource->RemoteNameLength;
815                 SpaceNeeded += 5 * sizeof(WCHAR);               // comment
816                 SpaceNeeded += sizeof(NFS41_PROVIDER_NAME_U);  // provider name
817                 if ( SpaceNeeded > SpaceAvailable )
818                 {
819                     Status = WN_MORE_DATA;
820                     DbgP((L"[aglo] NPEnumResource More Data Needed - %d\n", SpaceNeeded));
821                     *lpBufferSize = SpaceNeeded;
822                     break;
823                 }
824                 else
825                 {
826                     SpaceAvailable -= SpaceNeeded;
827 
828                     pNetResource->dwScope       = pNfsNetResource->dwScope;
829                     pNetResource->dwType        = pNfsNetResource->dwType;
830                     pNetResource->dwDisplayType = pNfsNetResource->dwDisplayType;
831                     pNetResource->dwUsage       = pNfsNetResource->dwUsage;
832 
833                     // setup string area at opposite end of buffer
834                     SpaceNeeded -= sizeof( NETRESOURCE );
835                     StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded );
836                     // copy local name
837                     StringCchCopy( StringZone,
838                         pNfsNetResource->LocalNameLength,
839                         pNfsNetResource->LocalName );
840                     pNetResource->lpLocalName = StringZone;
841                     StringZone += pNfsNetResource->LocalNameLength/sizeof(WCHAR);
842                     // copy remote name
843                     StringCchCopy( StringZone,
844                         pNfsNetResource->RemoteNameLength,
845                         pNfsNetResource->RemoteName );
846                     pNetResource->lpRemoteName = StringZone;
847                     StringZone += pNfsNetResource->RemoteNameLength/sizeof(WCHAR);
848                     // copy comment
849                     pNetResource->lpComment = StringZone;
850                     *StringZone++ = L'A';
851                     *StringZone++ = L'_';
852                     *StringZone++ = L'O';
853                     *StringZone++ = L'K';
854                     *StringZone++ = L'\0';
855                     // copy provider name
856                     pNetResource->lpProvider = StringZone;
857                     StringCbCopyW( StringZone, sizeof(NFS41_PROVIDER_NAME_U), NFS41_PROVIDER_NAME_U );
858                     StringZone += sizeof(NFS41_PROVIDER_NAME_U)/sizeof(WCHAR);
859                     EntriesCopied++;
860                     // set new bottom of string zone
861                     StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded );
862                     Status = WN_SUCCESS;
863                 }
864                 pNetResource++;
865             }
866         }
867         CloseSharedMemory( &hMutex, &hMemory, (PVOID*)&pSharedMemory);
868     }
869 
870     *lpcCount = EntriesCopied;
871     *(PULONG) hEnum = Index;
872 
873     DbgP((L"[aglo] NPEnumResource entries returned: %d\n", EntriesCopied));
874 
875     return Status;
876 }
877 
878 DWORD APIENTRY
879 NPCloseEnum(
880     HANDLE hEnum )
881 {
882     DbgP((L"[aglo] NPCloseEnum\n"));
883     HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum );
884     return WN_SUCCESS;
885 }
886 
887 DWORD APIENTRY
888 NPGetResourceParent(
889     LPNETRESOURCE   lpNetResource,
890     LPVOID  lpBuffer,
891     LPDWORD lpBufferSize )
892 {
893     DbgP(( L"[aglo] NPGetResourceParent: WN_NOT_SUPPORTED\n" ));
894     return WN_NOT_SUPPORTED;
895 }
896 
897 DWORD APIENTRY
898 NPGetResourceInformation(
899     __in LPNETRESOURCE   lpNetResource,
900     __out_bcount(*lpBufferSize) LPVOID  lpBuffer,
901     __inout LPDWORD lpBufferSize,
902     __deref_out LPWSTR *lplpSystem )
903 {
904     DbgP(( L"[aglo] NPGetResourceInformation: WN_NOT_SUPPORTED\n" ));
905     return WN_NOT_SUPPORTED;
906 }
907 
908 DWORD APIENTRY
909 NPGetUniversalName(
910     LPCWSTR lpLocalPath,
911     DWORD   dwInfoLevel,
912     LPVOID  lpBuffer,
913     LPDWORD lpBufferSize )
914 {
915     DbgP(( L"[aglo] NPGetUniversalName: WN_NOT_SUPPORTED\n" ));
916     return WN_NOT_SUPPORTED;
917 }
918