Windows: Permit Media Player to work with mapped drives
[openafs.git] / src / WINNT / afsrdr / npdll / AFS_Npdll.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #ifndef _WIN32_WINNT
36 #define _WIN32_WINNT 0x0500
37 #endif
38
39 #include <windows.h>
40 #include <windef.h>
41 #include <winbase.h>
42 #include <winreg.h>
43 #include <winsvc.h>
44 #include <winnetwk.h>
45 #include <npapi.h>
46 #include <winioctl.h>
47 #include <strsafe.h>
48
49 #define AFS_DEBUG_TRACE 1
50
51 #ifndef WNNC_NET_OPENAFS
52 #define WNNC_NET_OPENAFS     0x00390000
53 #endif
54
55 #include "AFSUserDefines.h"
56 #include "AFSUserIoctl.h"
57 #include "AFSUserStructs.h"
58 #include "AFSProvider.h"
59 #include "AFS_Npdll.h"
60
61 #include "stdio.h"
62
63 #ifndef MAX_PATH
64 #define MAX_PATH 260
65 #endif
66
67 #define SCRATCHSZ 1024
68
69 //
70 // Common information
71 //
72
73 ULONG _cdecl AFSDbgPrint( PWCHAR Format, ... );
74
75 static DWORD APIENTRY
76 NPGetConnectionCommon( LPWSTR  lpLocalName,
77                        LPWSTR  lpRemoteName,
78                        LPDWORD lpBufferSize,
79                        BOOL    bDriveSubstOk);
80
81 static DWORD APIENTRY
82 NPGetConnection3Common( LPCWSTR lpLocalName,
83                         DWORD dwLevel,
84                         LPVOID lpBuffer,
85                         LPDWORD lpBufferSize,
86                         BOOL bDriveSubstOk);
87
88 static DWORD APIENTRY
89 NPGetUniversalNameCommon( LPCWSTR lpLocalPath,
90                           DWORD   dwInfoLevel,
91                           LPVOID  lpBuffer,
92                           LPDWORD lpBufferSize,
93                           BOOL    bDriveSubstOk);
94
95 static BOOL
96 DriveSubstitution( LPCWSTR drivestr,
97                    LPWSTR subststr,
98                    size_t substlen,
99                    DWORD * pStatus);
100
101 #define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor )
102
103 #define OPENAFS_PROVIDER_NAME           L"OpenAFS Network"
104 #define OPENAFS_PROVIDER_NAME_LENGTH    30
105
106 #define MAX_PROVIDER_NAME_LENGTH        256
107
108 static ULONG cbProviderNameLength = OPENAFS_PROVIDER_NAME_LENGTH;
109
110 static wchar_t wszProviderName[MAX_PROVIDER_NAME_LENGTH+1] = OPENAFS_PROVIDER_NAME;
111
112 static BOOL bProviderNameRead = FALSE;
113
114 #define OPENAFS_SERVER_NAME             L"AFS"
115 #define OPENAFS_SERVER_NAME_LENGTH      6
116
117 #define OPENAFS_SERVER_COMMENT          L"AFS Root"
118 #define OPENAFS_SERVER_COMMENT_LENGTH   16
119
120 #define MAX_SERVER_NAME_LENGTH         30
121
122 static ULONG cbServerNameLength = 0;
123
124 static ULONG cbServerNameUNCLength = 0;
125
126 static ULONG cbServerCommentLength = OPENAFS_SERVER_COMMENT_LENGTH;
127
128 static wchar_t wszServerName[MAX_SERVER_NAME_LENGTH+1];
129
130 static wchar_t wszServerNameUNC[MAX_SERVER_NAME_LENGTH+3];
131
132 static wchar_t wszServerComment[] = OPENAFS_SERVER_COMMENT;
133
134 static BOOL bServerNameRead = FALSE;
135
136 LARGE_INTEGER
137 AFSRetrieveAuthId( void);
138
139 void
140 ReadProviderNameString( void)
141 {
142     HKEY hk;
143     DWORD code;
144     DWORD dwLen = 0;
145
146     if ( bProviderNameRead )
147         return;
148
149     code = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
150                          L"SYSTEM\\CurrentControlSet\\Services\\AFSRedirector\\NetworkProvider",
151                          0, KEY_QUERY_VALUE, &hk);
152
153     if ( code == ERROR_SUCCESS) {
154
155         dwLen = sizeof(wszProviderName);
156
157         code = RegQueryValueExW( hk, L"Name", NULL, NULL,
158                                  (LPBYTE) wszProviderName, &dwLen);
159
160         if ( code == ERROR_SUCCESS)
161         {
162
163             wszProviderName[MAX_PROVIDER_NAME_LENGTH] = '\0';
164
165             cbProviderNameLength = wcslen( wszProviderName) * sizeof( WCHAR);
166         }
167
168         RegCloseKey( hk);
169     }
170
171     bProviderNameRead = TRUE;
172 }
173
174 void
175 ReadServerNameString( void)
176 {
177     HKEY hk;
178     DWORD code;
179     DWORD dwLen = 0;
180
181     if ( bServerNameRead )
182         return;
183
184     code = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
185                          L"SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters",
186                          0, KEY_QUERY_VALUE, &hk);
187
188     if ( code == ERROR_SUCCESS) {
189
190         dwLen = sizeof(wszProviderName);
191
192         code = RegQueryValueExW( hk, L"NetbiosName", NULL, NULL,
193                                  (LPBYTE) wszServerName, &dwLen);
194
195         if ( code == ERROR_SUCCESS)
196         {
197
198             wszServerName[MAX_SERVER_NAME_LENGTH] = '\0';
199
200             cbServerNameLength = wcslen( wszServerName) * sizeof( WCHAR);
201
202             wszServerNameUNC[0] = wszServerNameUNC[1] = L'\\';
203
204             memcpy(&wszServerNameUNC[2], wszServerName, (cbServerNameLength + 1) * sizeof( WCHAR));
205
206             cbServerNameUNCLength = cbServerNameLength + 2 * sizeof( WCHAR);
207         }
208
209         RegCloseKey( hk);
210     }
211
212     bServerNameRead = TRUE;
213 }
214
215
216
217 /* returns TRUE if the file system is disabled or not installed */
218 BOOL
219 NPIsFSDisabled( void)
220 {
221     HKEY hk;
222     DWORD code;
223     DWORD dwLen = 0;
224     DWORD dwStart = SERVICE_DISABLED;
225
226     code = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
227                          L"SYSTEM\\CurrentControlSet\\Services\\AFSRedirector",
228                          0, KEY_QUERY_VALUE, &hk);
229
230     if ( code != ERROR_SUCCESS)
231
232         return TRUE;
233
234
235     dwLen = sizeof(dwStart);
236
237     code = RegQueryValueExW( hk, L"Start", NULL, NULL,
238                              (LPBYTE) &dwStart, &dwLen);
239
240     RegCloseKey( hk);
241
242     return ( dwStart == SERVICE_DISABLED);
243 }
244
245
246 #define try_return(S) { S; goto try_exit; }
247
248 #define __Enter
249
250 #define NOTHING
251
252 typedef struct _UNICODE_STRING {
253     USHORT Length;
254     USHORT MaximumLength;
255     PWSTR Buffer;
256 } UNICODE_STRING, *PUNICODE_STRING;
257
258 HANDLE
259 OpenRedirector( void);
260
261 typedef struct _AFS_ENUM_CB
262 {
263
264     DWORD       CurrentIndex;
265
266     DWORD       Scope;
267
268     DWORD       Type;
269
270     WCHAR      *RemoteName;
271
272 } AFSEnumerationCB;
273
274
275 //
276 // Recursively evaluate drivestr to find the final
277 // dos drive letter to which the source is mapped.
278 //
279 static BOOL
280 DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen, DWORD * pStatus)
281 {
282     WCHAR drive[3];
283     WCHAR device[MAX_PATH + 26];
284     HRESULT hr = S_OK;
285
286     *pStatus = WN_SUCCESS;
287
288     memset( subststr, 0, substlen);
289     drive[0] = drivestr[0];
290     drive[1] = drivestr[1];
291     drive[2] = 0;
292
293     if ( substlen < 3 * sizeof( WCHAR))
294     {
295         //
296         // Cannot represent "D:"
297         //
298         return FALSE;
299     }
300
301     if ( QueryDosDevice(drive, device, MAX_PATH + 26) )
302     {
303 #ifdef AFS_DEBUG_TRACE
304         AFSDbgPrint( L"DriveSubstitution QueryDosDevice %s [%s -> %s]\n",
305                      drivestr,
306                      drive,
307                      device);
308 #endif
309         if ( device[0] == L'\\' &&
310              device[1] == L'?' &&
311              device[2] == L'?' &&
312              device[3] == L'\\' &&
313              iswalpha(device[4]) &&
314              device[5] == L':')
315         {
316             drive[0] = device[4];
317             drive[1] = L':';
318             drive[2] = L'\0';
319
320             if ( !DriveSubstitution(drive, subststr, substlen, pStatus) )
321             {
322
323                 subststr[0] = drive[0];
324                 subststr[1] = L':';
325                 subststr[2] = L'\0';
326             }
327
328             hr = S_OK;
329
330             if ( device[6] )
331             {
332                 hr = StringCbCat( subststr, substlen, &device[6]);
333             }
334             if ( SUCCEEDED(hr) && drivestr[2] )
335             {
336                 hr = StringCbCat( subststr, substlen, &drivestr[2]);
337             }
338
339             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
340             {
341
342                 if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER )
343                     *pStatus = WN_MORE_DATA;
344
345 #ifdef AFS_DEBUG_TRACE
346                     AFSDbgPrint( L"DriveSubstitution (hr = %X) %s -> %s\n",
347                                  hr,
348                                  drivestr,
349                                  subststr);
350 #endif
351                 return TRUE;
352             }
353         }
354         else if ( device[0] == L'\\' &&
355                   device[1] == L'?' &&
356                   device[2] == L'?' &&
357                   device[3] == L'\\' &&
358                   device[4] == L'U' &&
359                   device[5] == L'N' &&
360                   device[6] == L'C' &&
361                   device[7] == L'\\')
362         {
363
364             subststr[0] = L'\\';
365
366             hr = StringCbCopyN(&subststr[1], substlen - sizeof(WCHAR), &device[7], sizeof(device) - 7 * sizeof(WCHAR));
367
368             if ( SUCCEEDED(hr) && drivestr[2] )
369             {
370                 hr = StringCbCat( subststr, substlen, &drivestr[2]);
371             }
372
373             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
374             {
375
376                 if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER )
377                     *pStatus = WN_MORE_DATA;
378
379 #ifdef AFS_DEBUG_TRACE
380                     AFSDbgPrint( L"DriveSubstitution (hr = %X) %s -> %s\n",
381                                  hr,
382                                  drivestr,
383                                  subststr);
384 #endif
385                 return TRUE;
386             }
387
388 #ifdef AFS_DEBUG_TRACE
389             AFSDbgPrint( L"DriveSubstitution StringCbCopyN 1 hr 0x%X\n",
390                          hr);
391 #endif
392         }
393         else if ( _wcsnicmp( AFS_RDR_DEVICE_NAME, device, sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR) - 1) == 0)
394         {
395             //
396             // \Device\AFSRedirector\;X:\\afs\cellname
397             //
398
399             hr = StringCbCopy( subststr, substlen,
400                                &device[3 + sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR)]);
401
402             if ( SUCCEEDED(hr) && drivestr[2] )
403             {
404                 hr = StringCbCat( subststr, substlen, &drivestr[2]);
405             }
406
407             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
408             {
409
410                 if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER )
411                     *pStatus = WN_MORE_DATA;
412
413 #ifdef AFS_DEBUG_TRACE
414                 AFSDbgPrint( L"DriveSubstitution (hr = %X) %s -> %s\n",
415                              hr,
416                              drivestr,
417                              subststr);
418 #endif
419                 return TRUE;
420             }
421
422 #ifdef AFS_DEBUG_TRACE
423             AFSDbgPrint( L"DriveSubstitution StringCbCopyN 2 hr 0x%X\n",
424                          hr);
425 #endif
426         }
427
428 #ifdef AFS_DEBUG_TRACE
429         AFSDbgPrint( L"DriveSubstitution no substitution or match %s !! %s\n",
430                      drivestr,
431                      device);
432 #endif
433     }
434     else
435     {
436 #ifdef AFS_DEBUG_TRACE
437         AFSDbgPrint( L"DriveSubstitution QueryDosDevice failed %s gle 0x%X\n",
438                      drivestr,
439                      GetLastError());
440 #endif
441     }
442
443     return FALSE;
444 }
445
446
447 static const WCHAR *
448 NPGetCapsQueryString( DWORD nIndex)
449 {
450     switch ( nIndex) {
451     case WNNC_SPEC_VERSION:
452         return L"WNNC_SPEC_VERSION";
453
454     case WNNC_NET_TYPE:
455         return L"WNNC_NET_TYPE";
456
457     case WNNC_DRIVER_VERSION:
458         return L"WNNC_DRIVER_VERSION";
459
460     case WNNC_USER:
461         return L"WNNC_USER";
462
463     case WNNC_CONNECTION:
464         return L"WNNC_CONNECTION";
465
466     case WNNC_DIALOG:
467         return L"WNNC_DIALOG";
468
469     case WNNC_ADMIN:
470         return L"WNNC_ADMIN";
471
472     case WNNC_ENUMERATION:
473         return L"WNNC_ENUMERATION";
474
475     case WNNC_START:
476         return L"WNNC_START";
477
478     case WNNC_CONNECTION_FLAGS:
479         return L"WNNC_CONNECTION_FLAGS";
480
481     default:
482         return L"UNKNOWN";
483     }
484 }
485
486 //
487 // This is the only function which must be exported, everything else is optional
488 //
489
490 DWORD
491 APIENTRY
492 NPGetCaps( DWORD nIndex )
493 {
494
495     DWORD rc = 0;
496
497 #ifdef AFS_DEBUG_TRACE
498     AFSDbgPrint( L"NPGetCaps Index %u %s\n", nIndex,
499                  NPGetCapsQueryString( nIndex));
500 #endif
501     switch( nIndex)
502     {
503         case WNNC_SPEC_VERSION:
504         {
505
506             rc = WNNC_SPEC_VERSION51;
507             break;
508         }
509
510         case WNNC_NET_TYPE:
511         {
512             rc = WNNC_NET_OPENAFS;
513             break;
514         }
515
516         case WNNC_DRIVER_VERSION:
517         {
518
519             rc = WNNC_DRIVER(1, 0);
520             break;
521         }
522
523         case WNNC_CONNECTION:
524         {
525
526             //
527             // No support for:
528             //   WNNC_CON_GETPERFORMANCE
529             //   WNNC_CON_DEFER
530             //
531
532             rc = WNNC_CON_GETCONNECTIONS |
533                  WNNC_CON_CANCELCONNECTION |
534                  WNNC_CON_ADDCONNECTION |
535                  WNNC_CON_ADDCONNECTION3;
536
537             break;
538         }
539
540         case WNNC_ENUMERATION:
541         {
542             rc = WNNC_ENUM_LOCAL |
543                  WNNC_ENUM_CONTEXT |
544                  WNNC_ENUM_GLOBAL |
545                  WNNC_ENUM_SHAREABLE;
546             break;
547         }
548
549         case WNNC_START:
550         {
551
552             rc = WNNC_WAIT_FOR_START;
553
554             break;
555         }
556
557         case WNNC_DIALOG:
558         {
559
560             //
561             // No support for:
562             //    WNNC_DLG_DEVICEMODE
563             //    WNNC_DLG_PROPERTYDIALOG
564             //    WNNC_DLG_SEARCHDIALOG
565             //    WNNC_DLG_PERMISSIONEDITOR
566             //
567
568             rc = WNNC_DLG_FORMATNETWORKNAME |
569                  WNNC_DLG_GETRESOURCEINFORMATION |
570                  WNNC_DLG_GETRESOURCEPARENT;
571
572             break;
573         }
574
575         case WNNC_USER:
576         {
577             //
578             // No support for:
579             //    WNNC_USR_GETUSER
580             //
581
582             break;
583         }
584
585         case WNNC_ADMIN:
586         {
587             //
588             // No support for:
589             //    WNNC_ADM_GETDIRECTORYTYPE
590             //    WNNC_ADM_DIRECTORYNOTIFY
591             // used by the old File Manager
592             //
593             break;
594         }
595     }
596
597     return rc;
598 }
599
600 DWORD
601 APIENTRY
602 NPAddConnection( LPNETRESOURCE   lpNetResource,
603                  LPWSTR          lpPassword,
604                  LPWSTR          lpUserName )
605 {
606
607 #ifdef AFS_DEBUG_TRACE
608     AFSDbgPrint( L"NPAddConnection forwarding to NPAddConnection3\n");
609 #endif
610     return NPAddConnection3( NULL, lpNetResource, lpPassword, lpUserName, 0 );
611 }
612
613 DWORD
614 APIENTRY
615 NPAddConnection3( HWND            hwndOwner,
616                   LPNETRESOURCE   lpNetResource,
617                   LPWSTR          lpPassword,
618                   LPWSTR          lpUserName,
619                   DWORD           dwFlags )
620 {
621
622     DWORD    dwStatus = WN_SUCCESS;
623     WCHAR    wchRemoteName[MAX_PATH+1];
624     WCHAR    wchLocalName[3];
625     DWORD    dwCopyBytes = 0;
626     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
627     DWORD    dwError = 0;
628     DWORD    dwBufferSize = 0;
629     HANDLE   hControlDevice = NULL;
630     HANDLE   hToken = NULL;
631     LARGE_INTEGER liAuthId = {0,0};
632     HRESULT  hr;
633
634     __Enter
635     {
636         if ( NPIsFSDisabled())
637         {
638
639 #ifdef AFS_DEBUG_TRACE
640             AFSDbgPrint( L"NPAddConnection3 AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
641 #endif
642
643             return WN_BAD_NETNAME;
644         }
645
646         if ((lpNetResource->lpRemoteName == NULL) ||
647             (lpNetResource->lpRemoteName[0] != L'\\') ||
648             (lpNetResource->lpRemoteName[1] != L'\\') ||
649             ((lpNetResource->dwType != RESOURCETYPE_DISK) &&
650              (lpNetResource->dwType != RESOURCETYPE_ANY)))
651         {
652
653 #ifdef AFS_DEBUG_TRACE
654             AFSDbgPrint( L"NPAddConnection3 invalid input, returning WN_BAD_NETNAME\n");
655 #endif
656             return WN_BAD_NETNAME;
657         }
658
659 #ifdef AFS_DEBUG_TRACE
660         AFSDbgPrint( L"NPAddConnection3 processing\n");
661 #endif
662         if( lpNetResource->lpLocalName != NULL)
663         {
664
665             wchLocalName[0] = towupper(lpNetResource->lpLocalName[0]);
666             wchLocalName[1] = L':';
667             wchLocalName[2] = L'\0';
668         }
669
670         hr = StringCbCopy(wchRemoteName, sizeof( wchRemoteName), lpNetResource->lpRemoteName);
671         if ( FAILED(hr))
672         {
673
674 #ifdef AFS_DEBUG_TRACE
675             AFSDbgPrint( L"NPAddConnection3 lpRemoteName longer than MAX_PATH, returning WN_BAD_NETNAME\n");
676 #endif
677             return WN_BAD_NETNAME;
678         }
679
680         //
681         // Allocate our buffer to pass to the redirector filter
682         //
683
684         dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + (wcslen( wchRemoteName) * sizeof( WCHAR));
685
686         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
687
688         if( pConnectCB == NULL)
689         {
690
691             try_return( dwStatus = WN_OUT_OF_MEMORY);
692         }
693
694         if( lpNetResource->lpLocalName != NULL)
695         {
696
697             pConnectCB->LocalName = towupper(wchLocalName[0]);
698
699 #ifdef AFS_DEBUG_TRACE
700             AFSDbgPrint( L"NPAddConnection3 Adding mapping for drive %s remote name %s\n",
701                          wchLocalName,
702                          wchRemoteName);
703 #endif
704         }
705         else
706         {
707
708             pConnectCB->LocalName = L'\0';
709
710 #ifdef AFS_DEBUG_TRACE
711             AFSDbgPrint( L"NPAddConnection3 Adding mapping for NO drive remote name %s\n",
712                          wchRemoteName);
713 #endif
714         }
715
716         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
717
718         pConnectCB->RemoteNameLength = wcslen( wchRemoteName) * sizeof( WCHAR);
719
720         memcpy( pConnectCB->RemoteName,
721                 wchRemoteName,
722                 pConnectCB->RemoteNameLength);
723
724         pConnectCB->Type = lpNetResource->dwType;
725
726         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
727
728 #ifdef AFS_DEBUG_TRACE
729         AFSDbgPrint( L"NPAddConnection3 Retrieved authentication id %08lX-%08lX\n",
730                      pConnectCB->AuthenticationId.HighPart,
731                      pConnectCB->AuthenticationId.LowPart);
732 #endif
733
734         hControlDevice = OpenRedirector();
735
736         if( hControlDevice == NULL)
737         {
738
739 #ifdef AFS_DEBUG_TRACE
740             AFSDbgPrint( L"NPAddConnection3 OpenRedirector failure, returning WN_NET_ERROR\n");
741 #endif
742
743             try_return( dwStatus = WN_NET_ERROR);
744         }
745
746         dwError = DeviceIoControl( hControlDevice,
747                                    IOCTL_AFS_ADD_CONNECTION,
748                                    pConnectCB,
749                                    dwBufferSize,
750                                    &dwStatus,
751                                    sizeof( DWORD),
752                                    &dwCopyBytes,
753                                    NULL);
754
755         if( !dwError)
756         {
757 #ifdef AFS_DEBUG_TRACE
758             AFSDbgPrint( L"NPAddConnection3 Failed to add connection to file system %d\n", GetLastError());
759 #endif
760             try_return( dwStatus = WN_OUT_OF_MEMORY);
761         }
762
763         //
764         // The status returned from the driver will indicate how it was handled
765         //
766
767         if( dwStatus == WN_SUCCESS &&
768             lpNetResource->lpLocalName != NULL)
769         {
770
771             WCHAR TempBuf[MAX_PATH+26];
772
773             if( !QueryDosDeviceW( wchLocalName,
774                                   TempBuf,
775                                   MAX_PATH+26))
776             {
777
778                 if( GetLastError() != ERROR_FILE_NOT_FOUND)
779                 {
780
781 #ifdef AFS_DEBUG_TRACE
782                     AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW failed with file not found\n");
783 #endif
784                     NPCancelConnection( wchLocalName, TRUE);
785
786                     dwStatus = ERROR_ALREADY_ASSIGNED;
787                 }
788                 else
789                 {
790
791                     UNICODE_STRING uniConnectionName;
792
793                     //
794                     // Create a symbolic link object to the device we are redirecting
795                     //
796
797                     uniConnectionName.MaximumLength = (USHORT)( wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR) +
798                                                                 pConnectCB->RemoteNameLength +
799                                                                 8 +              // Local name and \;
800                                                                 sizeof(WCHAR));   //  Space for NULL-termination.
801
802                     //
803                     //  Don't include NULL-termination.
804                     //
805
806                     uniConnectionName.Length = uniConnectionName.MaximumLength - sizeof(WCHAR);
807
808                     uniConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT,
809                                                            uniConnectionName.MaximumLength);
810
811                     if( uniConnectionName.Buffer == NULL)
812                     {
813
814                         try_return( dwStatus = GetLastError());
815                     }
816
817                     hr = StringCbCopyW( uniConnectionName.Buffer,
818                                         uniConnectionName.MaximumLength,
819                                         AFS_RDR_DEVICE_NAME);
820                     if ( FAILED(hr))
821                     {
822 #ifdef AFS_DEBUG_TRACE
823                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
824 #endif
825                         try_return( dwStatus = WN_OUT_OF_MEMORY);
826                     }
827
828                     hr = StringCbCatW( uniConnectionName.Buffer,
829                                        uniConnectionName.MaximumLength,
830                                        L"\\;" );
831                     if ( FAILED(hr))
832                     {
833 #ifdef AFS_DEBUG_TRACE
834                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
835 #endif
836                         try_return( dwStatus = WN_OUT_OF_MEMORY);
837                     }
838
839                     hr = StringCbCatW( uniConnectionName.Buffer,
840                                        uniConnectionName.MaximumLength,
841                                        wchLocalName);
842                     if ( FAILED(hr))
843                     {
844 #ifdef AFS_DEBUG_TRACE
845                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
846 #endif
847                         try_return( dwStatus = WN_OUT_OF_MEMORY);
848                     }
849
850                     hr = StringCbCatW( uniConnectionName.Buffer,
851                                        uniConnectionName.MaximumLength,
852                                        wchRemoteName);
853                     if ( FAILED(hr))
854                     {
855 #ifdef AFS_DEBUG_TRACE
856                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
857 #endif
858                         try_return( dwStatus = WN_OUT_OF_MEMORY);
859                     }
860
861 #ifdef AFS_DEBUG_TRACE
862                     AFSDbgPrint( L"NPAddConnection3 DefineDosDevice Local %s connection name %s\n",
863                                  wchLocalName,
864                                  uniConnectionName.Buffer);
865 #endif
866
867                     if( !DefineDosDeviceW( DDD_RAW_TARGET_PATH |
868                                            DDD_NO_BROADCAST_SYSTEM,
869                                            wchLocalName,
870                                            uniConnectionName.Buffer))
871                     {
872 #ifdef AFS_DEBUG_TRACE
873                         AFSDbgPrint( L"NPAddConnection3 Failed to assign drive\n");
874 #endif
875                         dwStatus = GetLastError();
876                     }
877                     else
878                     {
879
880 #ifdef AFS_DEBUG_TRACE
881                         AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW assigned drive %s\n", wchLocalName);
882 #endif
883
884                         dwStatus = WN_SUCCESS;
885                     }
886
887                     LocalFree( uniConnectionName.Buffer);
888                 }
889             }
890             else
891             {
892
893 #ifdef AFS_DEBUG_TRACE
894                 AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW %Z already existed\n", TempBuf);
895 #endif
896                 NPCancelConnection( wchLocalName, TRUE);
897
898                 dwStatus = ERROR_ALREADY_ASSIGNED;
899             }
900         }
901
902 try_exit:
903
904         if ( hControlDevice != NULL)
905         {
906
907             CloseHandle( hControlDevice);
908         }
909
910         if( pConnectCB != NULL)
911         {
912
913             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
914         }
915     }
916
917     return dwStatus;
918 }
919
920 DWORD
921 APIENTRY
922 NPCancelConnection( LPWSTR  lpName,
923                     BOOL    fForce)
924 {
925
926     WCHAR    wchRemoteName[MAX_PATH+1];
927     DWORD    dwRemoteNameLength = (MAX_PATH+1) * sizeof(WCHAR);
928     DWORD    dwStatus = WN_NOT_CONNECTED;
929     DWORD    dwCopyBytes = 0;
930     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
931     AFSCancelConnectionResultCB stCancelConn;
932     DWORD    dwError = 0;
933     DWORD    dwBufferSize = 0;
934     BOOL     bLocalName = TRUE;
935     HANDLE   hControlDevice = NULL;
936     WCHAR    wchLocalName[ 3];
937     WCHAR   *pwchLocalName = NULL;
938     HRESULT hr;
939
940     __Enter
941     {
942
943         if ( NPIsFSDisabled())
944         {
945
946 #ifdef AFS_DEBUG_TRACE
947             AFSDbgPrint( L"NPCancelConnection AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
948 #endif
949
950             try_return( dwStatus = WN_NOT_CONNECTED);
951         }
952
953         if( *lpName == L'\\' &&
954             *(lpName + 1) == L'\\')
955         {
956
957             bLocalName = FALSE;
958
959             wchLocalName[0] = L'\0';
960
961             hr = StringCbCopyW( wchRemoteName, sizeof( wchRemoteName), lpName);
962
963             if ( FAILED(hr))
964             {
965 #ifdef AFS_DEBUG_TRACE
966                 AFSDbgPrint( L"NPCancelConnection lpName longer than MAX_PATH\n");
967 #endif
968                 try_return( dwStatus = WN_OUT_OF_MEMORY);
969             }
970
971             dwRemoteNameLength = (wcslen( wchRemoteName) * sizeof( WCHAR));
972         }
973         else
974         {
975
976             wchLocalName[0] = towupper(lpName[0]);
977             wchLocalName[1] = L':';
978             wchLocalName[2] = L'\0';
979
980             //
981             // Get the remote name for the connection, if we are handling it
982             //
983
984             dwStatus = NPGetConnectionCommon( wchLocalName,
985                                               wchRemoteName,
986                                               &dwRemoteNameLength,
987                                               FALSE);
988
989             if( dwStatus != WN_SUCCESS ||
990                 dwRemoteNameLength == 0)
991             {
992
993 #ifdef AFS_DEBUG_TRACE
994                 AFSDbgPrint( L"NPCancelConnection Status 0x%x NameLength %u, returning WN_NOT_CONNECTED\n",
995                              dwStatus, dwRemoteNameLength);
996 #endif
997                 try_return( dwStatus = WN_NOT_CONNECTED);
998             }
999
1000             //
1001             // NPGetConnection returns the buffer size not the length without NUL
1002             //
1003             dwRemoteNameLength -= sizeof( WCHAR);
1004         }
1005
1006         wchRemoteName[ dwRemoteNameLength/sizeof( WCHAR)] = L'\0';
1007
1008 #ifdef AFS_DEBUG_TRACE
1009         AFSDbgPrint( L"NPCancelConnection Attempting to cancel '%s' -> '%s'\n",
1010                      wchLocalName, wchRemoteName);
1011 #endif
1012
1013         dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + dwRemoteNameLength;
1014
1015         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1016
1017         if( pConnectCB == NULL)
1018         {
1019
1020             try_return( dwStatus = WN_OUT_OF_MEMORY);
1021         }
1022
1023         if( bLocalName)
1024         {
1025
1026             pConnectCB->LocalName = wchLocalName[0];
1027         }
1028         else
1029         {
1030
1031             pConnectCB->LocalName = L'\0';
1032         }
1033
1034         pConnectCB->RemoteNameLength = (USHORT)dwRemoteNameLength;
1035
1036         StringCbCopyW( pConnectCB->RemoteName,
1037                        dwRemoteNameLength + sizeof( WCHAR),
1038                        wchRemoteName);
1039
1040         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1041
1042         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1043
1044 #ifdef AFS_DEBUG_TRACE
1045         AFSDbgPrint( L"NPCancelConnection Retrieved authentication id %08lX-%08lX\n",
1046                      pConnectCB->AuthenticationId.HighPart,
1047                      pConnectCB->AuthenticationId.LowPart);
1048 #endif
1049
1050         hControlDevice = OpenRedirector();
1051
1052         if( hControlDevice == NULL)
1053         {
1054
1055 #ifdef AFS_DEBUG_TRACE
1056             AFSDbgPrint( L"NPCancelConnection OpenRedirector failure, returning WN_NET_ERROR\n");
1057 #endif
1058
1059             try_return( dwStatus = WN_NET_ERROR);
1060         }
1061
1062         memset( &stCancelConn,
1063                 '\0',
1064                 sizeof( AFSCancelConnectionResultCB));
1065
1066         dwError = DeviceIoControl( hControlDevice,
1067                                    IOCTL_AFS_CANCEL_CONNECTION,
1068                                    pConnectCB,
1069                                    dwBufferSize,
1070                                    &stCancelConn,
1071                                    sizeof( AFSCancelConnectionResultCB),
1072                                    &dwCopyBytes,
1073                                    NULL);
1074
1075         if( !dwError)
1076         {
1077 #ifdef AFS_DEBUG_TRACE
1078             DWORD gle = GetLastError();
1079
1080             AFSDbgPrint( L"NPCancelConnection DeviceIoControl failed - gle 0x%x\n", gle);
1081 #endif
1082             try_return( dwStatus = WN_NOT_CONNECTED);
1083         }
1084
1085         dwStatus = stCancelConn.Status;
1086
1087 #ifdef AFS_DEBUG_TRACE
1088         if ( dwStatus == WN_NOT_CONNECTED )
1089         {
1090
1091             AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status WN_NOT_CONNECTED\n",
1092                          lpName);
1093         }
1094         else
1095         {
1096
1097             AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status %08lX\n",
1098                          lpName,
1099                          dwStatus);
1100         }
1101 #endif
1102
1103         if( dwStatus == WN_SUCCESS &&
1104             ( bLocalName ||
1105               stCancelConn.LocalName != L'\0'))
1106         {
1107
1108             UNICODE_STRING uniConnectionName;
1109
1110             //
1111             // Create a symbolic link object to the device we are redirecting
1112             //
1113
1114             uniConnectionName.MaximumLength = (USHORT)( wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR) +
1115                                                         dwRemoteNameLength +
1116                                                         8 +             // Local name and \;
1117                                                         sizeof(WCHAR)); //  Space for NULL-termination.
1118
1119             //
1120             //  Don't include NULL-termination.
1121             //
1122
1123             uniConnectionName.Length = uniConnectionName.MaximumLength - sizeof(WCHAR);
1124
1125             uniConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT,
1126                                                    uniConnectionName.MaximumLength);
1127
1128             if( uniConnectionName.Buffer == NULL)
1129             {
1130
1131                 try_return( dwStatus = GetLastError());
1132             }
1133
1134             hr = StringCbCopyW( uniConnectionName.Buffer,
1135                                 uniConnectionName.MaximumLength,
1136                                 AFS_RDR_DEVICE_NAME);
1137
1138             if ( FAILED(hr))
1139             {
1140 #ifdef AFS_DEBUG_TRACE
1141                 AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (1)\n");
1142 #endif
1143                 try_return( dwStatus = WN_OUT_OF_MEMORY);
1144             }
1145
1146             hr = StringCbCatW( uniConnectionName.Buffer,
1147                                uniConnectionName.MaximumLength,
1148                                L"\\;" );
1149
1150             if ( FAILED(hr))
1151             {
1152 #ifdef AFS_DEBUG_TRACE
1153                 AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (2)\n");
1154 #endif
1155                 try_return( dwStatus = WN_OUT_OF_MEMORY);
1156             }
1157
1158             if( !bLocalName)
1159             {
1160
1161                 wchLocalName[ 0] = stCancelConn.LocalName;
1162
1163                 wchLocalName[ 1] = L':';
1164
1165                 wchLocalName[ 2] = L'\0';
1166
1167                 hr = StringCbCatW( uniConnectionName.Buffer,
1168                                    uniConnectionName.MaximumLength,
1169                                    wchLocalName);
1170
1171                 if ( FAILED(hr))
1172                 {
1173 #ifdef AFS_DEBUG_TRACE
1174                     AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (3)\n");
1175 #endif
1176                     try_return( dwStatus = WN_OUT_OF_MEMORY);
1177                 }
1178
1179                 pwchLocalName = wchLocalName;
1180             }
1181             else
1182             {
1183
1184                 hr = StringCbCatW( uniConnectionName.Buffer,
1185                                    uniConnectionName.MaximumLength,
1186                                    lpName);
1187
1188                 if ( FAILED(hr))
1189                 {
1190 #ifdef AFS_DEBUG_TRACE
1191                     AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (4)\n");
1192 #endif
1193                     try_return( dwStatus = WN_OUT_OF_MEMORY);
1194                 }
1195
1196                 pwchLocalName = lpName;
1197             }
1198
1199             hr = StringCbCatW( uniConnectionName.Buffer,
1200                                uniConnectionName.MaximumLength,
1201                                wchRemoteName);
1202
1203             if ( FAILED(hr))
1204             {
1205 #ifdef AFS_DEBUG_TRACE
1206                 AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (5)\n");
1207 #endif
1208                 try_return( dwStatus = WN_OUT_OF_MEMORY);
1209             }
1210
1211             if( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
1212                                   pwchLocalName,
1213                                   uniConnectionName.Buffer))
1214             {
1215
1216 #ifdef AFS_DEBUG_TRACE
1217                 DWORD gle = GetLastError();
1218
1219                 AFSDbgPrint( L"NPCancelConnection Failed to cancel connection to system - gle 0x%x Name %s connection %wZ\n",
1220                              gle,
1221                              pwchLocalName,
1222                              &uniConnectionName);
1223 #endif
1224             }
1225             else
1226             {
1227 #ifdef AFS_DEBUG_TRACE
1228
1229                 AFSDbgPrint( L"NPCancelConnection Canceled connection to system - Name %s connection %wZ\n",
1230                              pwchLocalName,
1231                              &uniConnectionName);
1232 #endif
1233             }
1234         }
1235
1236 try_exit:
1237
1238         if ( hControlDevice != NULL)
1239         {
1240
1241             CloseHandle( hControlDevice);
1242         }
1243
1244
1245         if( pConnectCB != NULL)
1246         {
1247
1248             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1249         }
1250
1251     }
1252
1253     return dwStatus;
1254 }
1255
1256 DWORD
1257 APIENTRY
1258 NPGetConnection( LPWSTR  lpLocalName,
1259                  LPWSTR  lpRemoteName,
1260                  LPDWORD lpBufferSize)
1261 {
1262
1263     DWORD dwBufferSize = *lpBufferSize;
1264     DWORD dwStatus;
1265
1266     dwStatus = NPGetConnectionCommon( lpLocalName,
1267                                       lpRemoteName,
1268                                       &dwBufferSize,
1269                                       FALSE);
1270
1271     if ( dwStatus == WN_NOT_CONNECTED)
1272     {
1273
1274         dwStatus = NPGetConnectionCommon( lpLocalName,
1275                                           lpRemoteName,
1276                                           lpBufferSize,
1277                                           TRUE);
1278     }
1279     else
1280     {
1281
1282         *lpBufferSize = dwBufferSize;
1283     }
1284
1285     return dwStatus;
1286 }
1287
1288 DWORD
1289 APIENTRY
1290 NPGetConnectionCommon( LPWSTR  lpLocalName,
1291                        LPWSTR  lpRemoteName,
1292                        LPDWORD lpBufferSize,
1293                        BOOL    bDriveSubstOk)
1294 {
1295
1296     DWORD    dwStatus = WN_NOT_CONNECTED;
1297     WCHAR    wchLocalName[3];
1298     WCHAR    wchSubstName[1024 + 26];
1299     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
1300     DWORD    dwError = 0;
1301     DWORD    dwBufferSize = 0;
1302     HANDLE   hControlDevice = NULL;
1303     DWORD    dwPassedSize;
1304
1305     __Enter
1306     {
1307
1308         if ( NPIsFSDisabled())
1309         {
1310
1311 #ifdef AFS_DEBUG_TRACE
1312             AFSDbgPrint( L"NPGetConnection AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
1313 #endif
1314
1315             try_return( dwStatus = WN_NOT_CONNECTED);
1316         }
1317
1318         if( lstrlen( lpLocalName) == 0)
1319         {
1320 #ifdef AFS_DEBUG_TRACE
1321             AFSDbgPrint( L"NPGetConnection No local name, returning WN_BAD_LOCALNAME\n");
1322 #endif
1323             try_return( dwStatus = WN_BAD_LOCALNAME);
1324         }
1325
1326         if ( lpBufferSize == NULL)
1327         {
1328 #ifdef AFS_DEBUG_TRACE
1329             AFSDbgPrint( L"NPGetConnection No output size, returning WN_BAD_LOCALNAME\n");
1330 #endif
1331             try_return( dwStatus = WN_BAD_VALUE);
1332         }
1333
1334         dwPassedSize = *lpBufferSize;
1335
1336         if ( !bDriveSubstOk ||
1337              !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName), &dwStatus))
1338         {
1339             wchLocalName[0] = towupper(lpLocalName[0]);
1340             wchLocalName[1] = L':';
1341             wchLocalName[2] = L'\0';
1342
1343 #ifdef AFS_DEBUG_TRACE
1344             AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n",
1345                          wchLocalName);
1346 #endif
1347         }
1348         else
1349         {
1350             ReadServerNameString();
1351
1352             if ( wchSubstName[0] != L'\\' &&
1353                  wchSubstName[1] == L':')
1354             {
1355
1356                 wchLocalName[0] = towupper(wchSubstName[0]);
1357                 wchLocalName[1] = L':';
1358                 wchLocalName[2] = L'\0';
1359
1360 #ifdef AFS_DEBUG_TRACE
1361                 AFSDbgPrint( L"NPGetConnection Requesting connection for drive substitution %s -> %s\n",
1362                              wchSubstName,
1363                              wchLocalName);
1364 #endif
1365             }
1366             else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
1367                       ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
1368                         wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
1369             {
1370                 HRESULT hr;
1371                 WCHAR  *pwch;
1372                 DWORD   dwCount = 0;
1373                 DWORD   dwRequiredSize;
1374
1375 #ifdef AFS_DEBUG_TRACE
1376                 AFSDbgPrint( L"NPGetConnection drive substitution %s is AFS\n",
1377                              wchSubstName);
1378 #endif
1379
1380                 dwRequiredSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
1381
1382                 if ( lpRemoteName == NULL ||
1383                      dwPassedSize == 0 ||
1384                      dwRequiredSize > *lpBufferSize)
1385                 {
1386
1387                     *lpBufferSize = dwRequiredSize;
1388
1389                     try_return( dwStatus = WN_MORE_DATA);
1390
1391                 }
1392
1393                 hr = StringCbCopyN(lpRemoteName, *lpBufferSize, wchSubstName, sizeof( wchSubstName));
1394
1395                 if ( SUCCEEDED(hr))
1396                 {
1397
1398                     for ( dwCount = 0, pwch = lpRemoteName; *pwch && pwch < lpRemoteName + (*lpBufferSize); pwch++ )
1399                     {
1400                         if ( *pwch == L'\\' )
1401                         {
1402                             dwCount++;
1403
1404                             if ( dwCount == 4)
1405                             {
1406                                 *pwch = L'\0';
1407
1408                                 break;
1409                             }
1410                         }
1411
1412                     }
1413
1414                     *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR);
1415
1416                     try_return( dwStatus = WN_SUCCESS);
1417                 }
1418                 else if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER)
1419                 {
1420
1421                     *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
1422
1423                     for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ )
1424                     {
1425                         if ( *pwch == L'\\' )
1426                         {
1427                             dwCount++;
1428
1429                             if ( dwCount == 4)
1430                             {
1431                                 *pwch = L'\0';
1432
1433                                 *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR);
1434
1435                                 try_return( dwStatus = WN_SUCCESS);
1436                             }
1437                         }
1438
1439                     }
1440
1441                     try_return( dwStatus = WN_MORE_DATA);
1442                 }
1443                 else
1444                 {
1445
1446 #ifdef AFS_DEBUG_TRACE
1447                     AFSDbgPrint( L"NPGetConnection StringCbCopyN failure 0x%X\n",
1448                                  hr);
1449 #endif
1450                     try_return( dwStatus = WN_NET_ERROR);
1451                 }
1452             }
1453             else
1454             {
1455
1456 #ifdef AFS_DEBUG_TRACE
1457                 AFSDbgPrint( L"NPGetConnection drive substitution %s is not AFS\n",
1458                              wchSubstName);
1459 #endif
1460                 try_return( dwStatus = WN_NOT_CONNECTED);
1461             }
1462         }
1463
1464 #ifdef AFS_DEBUG_TRACE
1465         AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n",
1466                      wchLocalName);
1467 #endif
1468
1469         dwBufferSize = 0x1000;
1470
1471         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1472
1473         if( pConnectCB == NULL)
1474         {
1475
1476             try_return( dwStatus = WN_OUT_OF_MEMORY);
1477         }
1478
1479         pConnectCB->LocalName = towupper(wchLocalName[0]);
1480
1481         pConnectCB->RemoteNameLength = 0;
1482
1483         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1484
1485         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1486
1487 #ifdef AFS_DEBUG_TRACE
1488         AFSDbgPrint( L"NPGetConnection Retrieved authentication id %08lX-%08lX\n",
1489                      pConnectCB->AuthenticationId.HighPart,
1490                      pConnectCB->AuthenticationId.LowPart);
1491 #endif
1492
1493         hControlDevice = OpenRedirector();
1494
1495         if( hControlDevice == NULL)
1496         {
1497
1498 #ifdef AFS_DEBUG_TRACE
1499             AFSDbgPrint( L"NPGetConnection OpenRedirector failure, returning WN_NET_ERROR\n");
1500 #endif
1501
1502             try_return( dwStatus = WN_NET_ERROR);
1503         }
1504
1505         dwError = DeviceIoControl( hControlDevice,
1506                                    IOCTL_AFS_GET_CONNECTION,
1507                                    pConnectCB,
1508                                    dwBufferSize,
1509                                    pConnectCB,
1510                                    dwBufferSize,
1511                                    lpBufferSize,
1512                                    NULL);
1513
1514         if( !dwError)
1515         {
1516 #ifdef AFS_DEBUG_TRACE
1517             DWORD gle = GetLastError();
1518
1519             AFSDbgPrint( L"NPGetConnection Failed to get connection from file system for local %s gle 0x%x\n",
1520                          wchLocalName, gle);
1521 #endif
1522             try_return( dwStatus = WN_NOT_CONNECTED);
1523         }
1524
1525         //
1526         // IOCTL_AFS_GET_CONNECTION returns a counted string
1527         //
1528
1529         if( lpRemoteName == NULL ||
1530             *lpBufferSize + sizeof( WCHAR) > dwPassedSize)
1531         {
1532
1533             *lpBufferSize += sizeof( WCHAR);
1534
1535             try_return( dwStatus = WN_MORE_DATA);
1536         }
1537
1538         memcpy( lpRemoteName,
1539                 (void *)pConnectCB,
1540                 *lpBufferSize);
1541
1542         lpRemoteName[ *lpBufferSize/sizeof( WCHAR)] = L'\0';
1543
1544         *lpBufferSize += sizeof( WCHAR);
1545
1546 #ifdef AFS_DEBUG_TRACE
1547         AFSDbgPrint( L"NPGetConnection local %s remote %s\n",
1548                      wchLocalName,
1549                      lpRemoteName);
1550 #endif
1551         dwStatus = WN_SUCCESS;
1552
1553 try_exit:
1554
1555         if ( hControlDevice != NULL)
1556         {
1557
1558             CloseHandle( hControlDevice);
1559         }
1560
1561         if( pConnectCB != NULL)
1562         {
1563
1564             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1565         }
1566     }
1567
1568     return dwStatus;
1569 }
1570
1571 DWORD APIENTRY
1572 NPGetConnection3( IN     LPCWSTR lpLocalName,
1573                   IN     DWORD dwLevel,
1574                   OUT    LPVOID lpBuffer,
1575                   IN OUT LPDWORD lpBufferSize)
1576 {
1577
1578     DWORD dwBufferSize = *lpBufferSize;
1579     DWORD dwStatus;
1580
1581     dwStatus = NPGetConnection3Common( lpLocalName,
1582                                        dwLevel,
1583                                        lpBuffer,
1584                                        &dwBufferSize,
1585                                        FALSE);
1586
1587     if ( dwStatus == WN_NOT_CONNECTED)
1588     {
1589
1590         dwStatus = NPGetConnection3Common( lpLocalName,
1591                                            dwLevel,
1592                                            lpBuffer,
1593                                            lpBufferSize,
1594                                            TRUE);
1595     }
1596     else
1597     {
1598
1599         *lpBufferSize = dwBufferSize;
1600     }
1601
1602     return dwStatus;
1603 }
1604
1605
1606 static DWORD APIENTRY
1607 NPGetConnection3Common( IN     LPCWSTR lpLocalName,
1608                         IN     DWORD dwLevel,
1609                         OUT    LPVOID lpBuffer,
1610                         IN OUT LPDWORD lpBufferSize,
1611                         IN     BOOL bDriveSubstOk)
1612 {
1613
1614     DWORD    dwStatus = WN_NOT_CONNECTED;
1615     WCHAR    wchLocalName[3];
1616     WCHAR    wchSubstName[1024 + 26];
1617     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
1618     DWORD    dwError = 0;
1619     DWORD    dwBufferSize = 0;
1620     HANDLE   hControlDevice = NULL;
1621     DWORD    dwPassedSize;
1622     DWORD   *pConnectState =(DWORD *)lpBuffer;
1623
1624     __Enter
1625     {
1626
1627         if ( NPIsFSDisabled())
1628         {
1629
1630 #ifdef AFS_DEBUG_TRACE
1631             AFSDbgPrint( L"NPGetConnection3 AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
1632 #endif
1633
1634             try_return( dwStatus = WN_NOT_CONNECTED);
1635         }
1636
1637         if( lstrlen( lpLocalName) == 0)
1638         {
1639 #ifdef AFS_DEBUG_TRACE
1640             AFSDbgPrint( L"NPGetConnection3 No local name, returning WN_BAD_LOCALNAME\n");
1641 #endif
1642             try_return( dwStatus = WN_BAD_LOCALNAME);
1643         }
1644
1645         //
1646         // LanMan NPGetConnection3 only responds to level 1
1647         //
1648
1649         if ( dwLevel != 0x1)
1650         {
1651 #ifdef AFS_DEBUG_TRACE
1652             AFSDbgPrint( L"NPGetConnection3 Level 0x%X returning WN_BAD_LEVEL\n", dwLevel);
1653 #endif
1654             try_return( dwStatus = WN_BAD_LEVEL);
1655         }
1656
1657         if ( lpBufferSize == NULL)
1658         {
1659 #ifdef AFS_DEBUG_TRACE
1660             AFSDbgPrint( L"NPGetConnection3 No output size, returning WN_BAD_VALUE\n");
1661 #endif
1662             try_return( dwStatus = WN_BAD_VALUE);
1663         }
1664
1665         dwPassedSize = *lpBufferSize;
1666
1667         if ( dwPassedSize == 0 ||
1668              lpBuffer == NULL)
1669         {
1670
1671             *lpBufferSize = sizeof( DWORD);
1672
1673             try_return( dwStatus = WN_MORE_DATA);
1674         }
1675
1676         if ( !bDriveSubstOk ||
1677              !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName), &dwStatus))
1678         {
1679             wchLocalName[0] = towupper(lpLocalName[0]);
1680             wchLocalName[1] = L':';
1681             wchLocalName[2] = L'\0';
1682
1683 #ifdef AFS_DEBUG_TRACE
1684             AFSDbgPrint( L"NPGetConnection3 Requesting connection for %s level 0x%X\n",
1685                          wchLocalName,
1686                          dwLevel);
1687 #endif
1688         }
1689         else
1690         {
1691
1692             ReadServerNameString();
1693
1694             if ( wchSubstName[0] != L'\\' &&
1695                  wchSubstName[1] == L':')
1696             {
1697
1698                 wchLocalName[0] = towupper(wchSubstName[0]);
1699                 wchLocalName[1] = L':';
1700                 wchLocalName[2] = L'\0';
1701
1702 #ifdef AFS_DEBUG_TRACE
1703                 AFSDbgPrint( L"NPGetConnection3 Requesting connection for drive substitution %s -> %s level 0x%x\n",
1704                              wchSubstName,
1705                              wchLocalName,
1706                              dwLevel);
1707 #endif
1708             }
1709             else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
1710                       ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
1711                         wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
1712             {
1713
1714 #ifdef AFS_DEBUG_TRACE
1715                 AFSDbgPrint( L"NPGetConnection3 drive substitution %s is AFS return connected\n",
1716                              wchSubstName);
1717 #endif
1718                 *pConnectState = WNGETCON_CONNECTED;
1719
1720                 *lpBufferSize = sizeof( DWORD);
1721
1722                 try_return( dwStatus = WN_SUCCESS);
1723             }
1724             else
1725             {
1726
1727 #ifdef AFS_DEBUG_TRACE
1728                 AFSDbgPrint( L"NPGetConnection3 drive substitution %s is not AFS return not connected\n",
1729                              wchSubstName);
1730 #endif
1731                 try_return( dwStatus = WN_NOT_CONNECTED);
1732             }
1733         }
1734
1735         dwBufferSize = 0x1000;
1736
1737         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1738
1739         if( pConnectCB == NULL)
1740         {
1741
1742             try_return( dwStatus = WN_OUT_OF_MEMORY);
1743         }
1744
1745         pConnectCB->LocalName = towupper(wchLocalName[0]);
1746
1747         pConnectCB->RemoteNameLength = 0;
1748
1749         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1750
1751         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1752
1753 #ifdef AFS_DEBUG_TRACE
1754         AFSDbgPrint( L"NPGetConnection3 Retrieved authentication id %08lX-%08lX\n",
1755                      pConnectCB->AuthenticationId.HighPart,
1756                      pConnectCB->AuthenticationId.LowPart);
1757 #endif
1758
1759         hControlDevice = OpenRedirector();
1760
1761         if( hControlDevice == NULL)
1762         {
1763
1764 #ifdef AFS_DEBUG_TRACE
1765             AFSDbgPrint( L"NPGetConnection3 OpenRedirector failure, returning WN_NET_ERROR\n");
1766 #endif
1767
1768             try_return( dwStatus = WN_NET_ERROR);
1769         }
1770
1771         dwError = DeviceIoControl( hControlDevice,
1772                                    IOCTL_AFS_GET_CONNECTION,
1773                                    pConnectCB,
1774                                    dwBufferSize,
1775                                    pConnectCB,
1776                                    dwBufferSize,
1777                                    &dwBufferSize,
1778                                    NULL);
1779
1780         if( !dwError)
1781         {
1782 #ifdef AFS_DEBUG_TRACE
1783             DWORD gle = GetLastError();
1784
1785             AFSDbgPrint( L"NPGetConnection3 Failed to get connection from file system for local %s gle 0x%x\n",
1786                          wchLocalName, gle);
1787 #endif
1788             try_return( dwStatus = WN_NOT_CONNECTED);
1789         }
1790
1791         *lpBufferSize = sizeof( DWORD);
1792
1793         if( sizeof( DWORD) > dwPassedSize)
1794         {
1795
1796             try_return( dwStatus = WN_MORE_DATA);
1797         }
1798
1799         *pConnectState = WNGETCON_CONNECTED;
1800
1801 #ifdef AFS_DEBUG_TRACE
1802         AFSDbgPrint( L"NPGetConnection3 local %s connect-state 0x%x\n",
1803                      wchLocalName,
1804                      *pConnectState);
1805 #endif
1806         dwStatus = WN_SUCCESS;
1807
1808 try_exit:
1809
1810         if ( hControlDevice != NULL)
1811         {
1812
1813             CloseHandle( hControlDevice);
1814         }
1815
1816         if( pConnectCB != NULL)
1817         {
1818
1819             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1820         }
1821     }
1822
1823     return dwStatus;
1824 }
1825
1826 DWORD
1827 APIENTRY
1828 NPGetConnectionPerformance( LPCWSTR lpRemoteName,
1829                             LPNETCONNECTINFOSTRUCT lpNetConnectInfo)
1830 {
1831
1832     DWORD dwReturn = WN_SUCCESS;
1833     AFSNetworkProviderConnectionCB *pConnectCB = NULL;
1834     DWORD dwBufferSize = 0;
1835     HANDLE hControlDevice = NULL;
1836     DWORD dwError = 0;
1837
1838     __Enter
1839     {
1840
1841         if ( NPIsFSDisabled())
1842         {
1843
1844 #ifdef AFS_DEBUG_TRACE
1845             AFSDbgPrint( L"NPGetConnectionPerformance AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
1846 #endif
1847
1848             return WN_NO_NETWORK;
1849         }
1850
1851         AFSDbgPrint( L"NPGetConnectionPerformance Entry for remote connection %S\n",
1852                      lpRemoteName);
1853
1854         dwBufferSize = 0x1000;
1855
1856         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1857
1858         if( pConnectCB == NULL)
1859         {
1860             try_return( dwReturn = WN_OUT_OF_MEMORY);
1861         }
1862
1863         pConnectCB->RemoteNameLength = wcslen( lpRemoteName) * sizeof( WCHAR);
1864
1865         StringCbCopy( pConnectCB->RemoteName,
1866                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
1867                       lpRemoteName);
1868
1869         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1870
1871         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1872
1873         hControlDevice = OpenRedirector();
1874
1875         if( hControlDevice == NULL)
1876         {
1877             AFSDbgPrint( L"NPGetConnectionPerformance OpenRedirector failure, returning WN_NET_ERROR\n");
1878
1879             try_return( dwReturn = WN_NET_ERROR);
1880         }
1881
1882         dwError = DeviceIoControl( hControlDevice,
1883                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
1884                                    pConnectCB,
1885                                    dwBufferSize,
1886                                    pConnectCB,
1887                                    dwBufferSize,
1888                                    &dwBufferSize,
1889                                    NULL);
1890
1891         if( !dwError)
1892         {
1893 #ifdef AFS_DEBUG_TRACE
1894             DWORD gle = GetLastError();
1895
1896             AFSDbgPrint( L"NPGetConnectionPerformance Failed to get connection info from file system for remote %S gle 0x%x\n",
1897                          lpRemoteName,
1898                          gle);
1899 #endif
1900             try_return( dwReturn = WN_NOT_CONNECTED);
1901         }
1902
1903         lpNetConnectInfo->dwFlags = WNCON_DYNAMIC;
1904
1905         lpNetConnectInfo->dwSpeed = 500;
1906
1907         lpNetConnectInfo->dwDelay = 0;
1908
1909         lpNetConnectInfo->dwOptDataSize = 0x1000;
1910
1911         AFSDbgPrint( L"NPGetConnectionPerformance Successfully returned information for remote connection %S\n",
1912                      lpRemoteName);
1913
1914 try_exit:
1915
1916         if ( hControlDevice != NULL)
1917         {
1918             CloseHandle( hControlDevice);
1919         }
1920
1921         if( pConnectCB != NULL)
1922         {
1923             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1924         }
1925     }
1926
1927     return dwReturn;
1928 }
1929
1930 static LPCWSTR
1931 GetUsageString( DWORD dwUsage)
1932 {
1933     static WCHAR Buffer[128] = L"";
1934     //
1935     // RESOURCEUSAGE_CONNECTABLE   0x00000001
1936     // RESOURCEUSAGE_CONTAINER     0x00000002
1937     // RESOURCEUSAGE_NOLOCALDEVICE 0x00000004
1938     // RESOURCEUSAGE_SIBLING       0x00000008
1939     // RESOURCEUSAGE_ATTACHED      0x00000010
1940     // RESOURCEUSAGE_ALL           (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED)
1941     // RESOURCEUSAGE_RESERVED      0x80000000
1942     //
1943
1944     Buffer[0] = L'\0';
1945
1946     if ( dwUsage == RESOURCEUSAGE_ALL )
1947     {
1948         return L"ALL";
1949     }
1950
1951     if ( dwUsage == 0 )
1952     {
1953         return L"NONE";
1954     }
1955
1956     if ( dwUsage & RESOURCEUSAGE_CONNECTABLE )
1957     {
1958         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTABLE|");
1959     }
1960
1961     if ( dwUsage & RESOURCEUSAGE_CONTAINER )
1962     {
1963         StringCbCat( Buffer, sizeof(Buffer), L"CONTAINER|");
1964     }
1965
1966     if ( dwUsage & RESOURCEUSAGE_NOLOCALDEVICE )
1967     {
1968         StringCbCat( Buffer, sizeof(Buffer), L"NOLOCALDEVICE|");
1969     }
1970
1971     if ( dwUsage & RESOURCEUSAGE_SIBLING )
1972     {
1973         StringCbCat( Buffer, sizeof(Buffer), L"SIBLING|");
1974     }
1975
1976     if ( dwUsage & RESOURCEUSAGE_ATTACHED )
1977     {
1978         StringCbCat( Buffer, sizeof(Buffer), L"ATTACHED|");
1979     }
1980
1981     if ( dwUsage & RESOURCEUSAGE_RESERVED )
1982     {
1983         StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|");
1984     }
1985
1986     if ( dwUsage & ~(RESOURCEUSAGE_ALL|RESOURCEUSAGE_NOLOCALDEVICE|RESOURCEUSAGE_SIBLING|RESOURCEUSAGE_RESERVED) )
1987     {
1988         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
1989     }
1990
1991     Buffer[lstrlen(Buffer)-1] = L'\0';
1992
1993     return Buffer;
1994 }
1995
1996 static LPCWSTR
1997 GetTypeString( DWORD dwType)
1998 {
1999     static WCHAR Buffer[128] = L"";
2000
2001     //
2002     // RESOURCETYPE_ANY        0x00000000
2003     // RESOURCETYPE_DISK       0x00000001
2004     // RESOURCETYPE_PRINT      0x00000002
2005     // RESOURCETYPE_RESERVED   0x00000008
2006     // RESOURCETYPE_UNKNOWN    0xFFFFFFFF
2007     //
2008
2009     Buffer[0] = L'\0';
2010
2011     if ( dwType == RESOURCETYPE_ANY )
2012     {
2013         return L"ANY";
2014     }
2015
2016     if ( dwType == RESOURCETYPE_UNKNOWN )
2017     {
2018         return L"UNKNOWN";
2019     }
2020
2021     if ( dwType & RESOURCETYPE_DISK )
2022     {
2023         StringCbCat( Buffer, sizeof(Buffer), L"DISK|");
2024     }
2025
2026     if ( dwType & RESOURCETYPE_PRINT )
2027     {
2028         StringCbCat( Buffer, sizeof(Buffer), L"PRINT|");
2029     }
2030
2031     if ( dwType & RESOURCETYPE_RESERVED )
2032     {
2033         StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|");
2034     }
2035
2036     if ( dwType & ~(RESOURCETYPE_DISK|RESOURCETYPE_PRINT|RESOURCETYPE_RESERVED) )
2037     {
2038         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
2039     }
2040
2041     Buffer[lstrlen(Buffer)-1] = L'\0';
2042
2043     return Buffer;
2044 }
2045
2046 static LPCWSTR
2047 GetScopeString( DWORD dwScope)
2048 {
2049     static WCHAR Buffer[128] = L"";
2050
2051     //
2052     // RESOURCE_CONNECTED      0x00000001
2053     // RESOURCE_GLOBALNET      0x00000002
2054     // RESOURCE_REMEMBERED     0x00000003
2055     // RESOURCE_RECENT         0x00000004
2056     // RESOURCE_CONTEXT        0x00000005
2057     //
2058
2059     Buffer[0] = L'\0';
2060
2061     if ( dwScope == RESOURCE_CONNECTED )
2062     {
2063         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTED|");
2064     }
2065
2066     if ( dwScope == RESOURCE_GLOBALNET )
2067     {
2068         StringCbCat( Buffer, sizeof(Buffer), L"GLOBALNET|");
2069     }
2070
2071     if ( dwScope == RESOURCE_REMEMBERED )
2072     {
2073         StringCbCat( Buffer, sizeof(Buffer), L"REMEMBERED|");
2074     }
2075
2076     if ( dwScope == RESOURCE_RECENT )
2077     {
2078         StringCbCat( Buffer, sizeof(Buffer), L"RECENT|");
2079     }
2080
2081     if ( dwScope == RESOURCE_CONTEXT )
2082     {
2083         StringCbCat( Buffer, sizeof(Buffer), L"CONTEXT|");
2084     }
2085
2086     if ( dwScope & ~(RESOURCE_CONNECTED|RESOURCE_GLOBALNET|RESOURCE_REMEMBERED|RESOURCE_RECENT|RESOURCE_CONTEXT) )
2087     {
2088         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
2089     }
2090
2091     Buffer[lstrlen(Buffer)-1] = L'\0';
2092
2093     return Buffer;
2094 }
2095
2096 static LPCWSTR
2097 GetDisplayString( DWORD dwDisplay)
2098 {
2099     //
2100     // RESOURCEDISPLAYTYPE_GENERIC        0x00000000
2101     // RESOURCEDISPLAYTYPE_DOMAIN         0x00000001
2102     // RESOURCEDISPLAYTYPE_SERVER         0x00000002
2103     // RESOURCEDISPLAYTYPE_SHARE          0x00000003
2104     // RESOURCEDISPLAYTYPE_FILE           0x00000004
2105     // RESOURCEDISPLAYTYPE_GROUP          0x00000005
2106     // RESOURCEDISPLAYTYPE_NETWORK        0x00000006
2107     // RESOURCEDISPLAYTYPE_ROOT           0x00000007
2108     // RESOURCEDISPLAYTYPE_SHAREADMIN     0x00000008
2109     // RESOURCEDISPLAYTYPE_DIRECTORY      0x00000009
2110     // RESOURCEDISPLAYTYPE_TREE           0x0000000A
2111     // RESOURCEDISPLAYTYPE_NDSCONTAINER   0x0000000B
2112     //
2113
2114     switch ( dwDisplay ) {
2115     case RESOURCEDISPLAYTYPE_GENERIC:
2116         return L"GENERIC";
2117     case RESOURCEDISPLAYTYPE_DOMAIN:
2118         return L"DOMAIN";
2119     case RESOURCEDISPLAYTYPE_SERVER:
2120         return L"SERVER";
2121     case RESOURCEDISPLAYTYPE_SHARE:
2122         return L"SHARE";
2123     case RESOURCEDISPLAYTYPE_FILE:
2124         return L"FILE";
2125     case RESOURCEDISPLAYTYPE_GROUP:
2126         return L"GROUP";
2127     case RESOURCEDISPLAYTYPE_NETWORK:
2128         return L"NETWORK";
2129     case RESOURCEDISPLAYTYPE_ROOT:
2130         return L"ROOT";
2131     case RESOURCEDISPLAYTYPE_SHAREADMIN:
2132         return L"SHAREADMIN";
2133     case RESOURCEDISPLAYTYPE_DIRECTORY:
2134         return L"DIRECTORY";
2135     case RESOURCEDISPLAYTYPE_TREE:
2136         return L"TREE";
2137     case RESOURCEDISPLAYTYPE_NDSCONTAINER:
2138         return L"NDSCONTAINER";
2139     default:
2140         return L"UNKNOWN";
2141     }
2142 }
2143
2144 DWORD
2145 APIENTRY
2146 NPOpenEnum( DWORD          dwScope,
2147             DWORD          dwType,
2148             DWORD          dwUsage,
2149             LPNETRESOURCE  lpNetResource,
2150             LPHANDLE       lphEnum )
2151 {
2152
2153     DWORD   dwStatus = WN_SUCCESS;
2154     AFSEnumerationCB *pEnumCB = NULL;
2155
2156 #ifdef AFS_DEBUG_TRACE
2157     if ( lpNetResource == NULL)
2158     {
2159         AFSDbgPrint( L"NPOpenEnum Scope %s Type %s Usage %s NetResource: (Null)\n",
2160                      GetScopeString(dwScope), GetTypeString(dwType), GetUsageString(dwUsage));
2161     }
2162     else
2163     {
2164         AFSDbgPrint( L"NPOpenEnum Scope %s Type %s Usage %s NetResource (0x%p): Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2165                      GetScopeString(dwScope),
2166                      GetTypeString(dwType),
2167                      GetUsageString(dwUsage),
2168                      lpNetResource,
2169                      GetScopeString(lpNetResource->dwScope),
2170                      GetTypeString(lpNetResource->dwType),
2171                      GetDisplayString(lpNetResource->dwDisplayType),
2172                      GetUsageString(lpNetResource->dwUsage),
2173                      lpNetResource->lpLocalName,
2174                      lpNetResource->lpRemoteName,
2175                      lpNetResource->lpComment);
2176     }
2177 #endif
2178
2179     if ( dwUsage == 0 )
2180     {
2181         dwUsage = RESOURCEUSAGE_ALL;
2182     }
2183
2184 #if 0
2185     if ( dwType == 0 || dwType == RESOURCEUSAGE_ATTACHED)
2186     {
2187         dwType |= RESOURCETYPE_DISK | RESOURCETYPE_PRINT;
2188     }
2189 #endif
2190
2191     *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( AFSEnumerationCB));
2192
2193     if( *lphEnum == NULL)
2194     {
2195
2196         return WN_OUT_OF_MEMORY;
2197     }
2198
2199     pEnumCB = (AFSEnumerationCB *)*lphEnum;
2200
2201     pEnumCB->CurrentIndex = 0;
2202
2203     pEnumCB->Type = dwType;
2204
2205     switch( dwScope )
2206     {
2207         case RESOURCE_CONNECTED:
2208         {
2209
2210             pEnumCB->Scope = RESOURCE_CONNECTED;
2211
2212             break;
2213         }
2214
2215         case RESOURCE_CONTEXT:
2216         {
2217
2218             pEnumCB->Scope = RESOURCE_CONTEXT;
2219
2220             break;
2221         }
2222
2223         case RESOURCE_GLOBALNET:
2224         {
2225
2226             if( lpNetResource != NULL &&
2227                 lpNetResource->lpRemoteName != NULL)
2228             {
2229
2230                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2231
2232                 if( pEnumCB->RemoteName == NULL)
2233                 {
2234
2235                     dwStatus = WN_OUT_OF_MEMORY;
2236                     HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2237                     *lphEnum = NULL;
2238                 }
2239                 else
2240                 {
2241
2242                     StringCbCopy( pEnumCB->RemoteName,
2243                                   0x1000,
2244                                   lpNetResource->lpRemoteName);
2245
2246                 }
2247             }
2248
2249             pEnumCB->Scope = RESOURCE_GLOBALNET;
2250
2251             break;
2252         }
2253
2254         default:
2255
2256 #ifdef AFS_DEBUG_TRACE
2257             AFSDbgPrint( L"NPOpenEnum Processing (Scope %s 0x%x) Type %s Usage %s, returning WN_NOT_SUPPORTED\n",
2258                          GetScopeString(dwScope), dwScope, GetTypeString(dwType), GetUsageString(dwUsage));
2259 #endif
2260
2261             dwStatus  = WN_NOT_SUPPORTED;
2262             HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2263             *lphEnum = NULL;
2264
2265             break;
2266     }
2267
2268     return dwStatus;
2269 }
2270
2271
2272 DWORD
2273 APIENTRY
2274 NPEnumResource( HANDLE  hEnum,
2275                 LPDWORD lpcCount,
2276                 LPVOID  lpBuffer,
2277                 LPDWORD lpBufferSize)
2278 {
2279
2280     DWORD            dwStatus = WN_NO_MORE_ENTRIES; //WN_SUCCESS;
2281     ULONG            dwCopyBytes;
2282     ULONG            EntriesCopied;
2283     ULONG            EntriesRequested;
2284     ULONG            dwIndex;
2285     LPNETRESOURCE    pNetResource;
2286     ULONG            SpaceNeeded;
2287     ULONG            SpaceAvailable;
2288     PWCHAR           StringZone;
2289     AFSNetworkProviderConnectionCB *pConnectionCB = NULL;
2290     void            *pConnectionCBBase = NULL;
2291     DWORD            dwError = 0;
2292     UNICODE_STRING   uniRemoteName;
2293     HANDLE           hControlDevice = NULL;
2294     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2295
2296     __Enter
2297     {
2298
2299         if ( lpBufferSize == NULL)
2300         {
2301 #ifdef AFS_DEBUG_TRACE
2302             AFSDbgPrint( L"NPEnumResource No output size, returning WN_BAD_VALUE\n");
2303 #endif
2304             try_return( dwStatus = WN_BAD_VALUE);
2305         }
2306
2307         ReadProviderNameString();
2308
2309         pNetResource = (LPNETRESOURCE) lpBuffer;
2310         SpaceAvailable = *lpBufferSize;
2311         EntriesRequested = *lpcCount;
2312         *lpcCount = EntriesCopied = 0;
2313         StringZone = (PWCHAR) ((char *)lpBuffer + *lpBufferSize);
2314
2315 #ifdef AFS_DEBUG_TRACE
2316         AFSDbgPrint( L"NPEnumResource Processing Remote name %s Scope %s Type %s Usage %s Index %d SpaceAvailable 0x%lX RequestedEntries %lu\n",
2317                      pEnumCB->RemoteName ? pEnumCB->RemoteName : L"(Null)",
2318                      GetScopeString(pEnumCB->Scope),
2319                      GetTypeString(pEnumCB->Type),
2320                      GetUsageString(pEnumCB->Type),
2321                      pEnumCB->CurrentIndex,
2322                      SpaceAvailable,
2323                      EntriesRequested);
2324 #endif
2325
2326         if ( NPIsFSDisabled())
2327         {
2328
2329 #ifdef AFS_DEBUG_TRACE
2330             AFSDbgPrint( L"NPEnumResource AFSRDFS is disabled, returning WN_NO_MORE_ENTRIES\n");
2331 #endif
2332
2333             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2334         }
2335
2336         pConnectionCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
2337
2338         if( pConnectionCB == NULL)
2339         {
2340
2341 #ifdef AFS_DEBUG_TRACE
2342             AFSDbgPrint( L"NPEnumResource Out of Memory\n");
2343 #endif
2344
2345             try_return( dwStatus = WN_OUT_OF_MEMORY);
2346         }
2347
2348         pConnectionCBBase = (void *)pConnectionCB;
2349
2350         hControlDevice = OpenRedirector();
2351
2352         if( hControlDevice == NULL)
2353         {
2354
2355 #ifdef AFS_DEBUG_TRACE
2356             AFSDbgPrint( L"NPEnumResource OpenRedirector failure, returning WN_NET_ERROR\n");
2357 #endif
2358
2359             try_return( dwStatus = WN_NET_ERROR);
2360         }
2361
2362         if( pEnumCB->Type != RESOURCETYPE_ANY && pEnumCB->Type != RESOURCETYPE_DISK)
2363         {
2364
2365 #ifdef AFS_DEBUG_TRACE
2366             AFSDbgPrint( L"NPEnumResource Non-DISK queries are not supported, returning WN_NO_MORE_ENTRIES\n");
2367 #endif
2368             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2369         }
2370
2371         //
2372         // Handle the special cases here
2373         //   0. Provider Network Root
2374         //   1. Server Root
2375         //
2376
2377 #if 0
2378         if ( pEnumCB->Scope == RESOURCE_GLOBALNET)
2379         {
2380
2381             ReadServerNameString();
2382
2383             if ( pEnumCB->CurrentIndex == 0 &&
2384                  pEnumCB->RemoteName == NULL)
2385             {
2386
2387                 // Determine the space needed for this entry...
2388
2389                 SpaceNeeded = 2 * ( cbProviderNameLength + sizeof( WCHAR));
2390
2391                 uniRemoteName.Length = (USHORT)cbProviderNameLength;
2392                 uniRemoteName.MaximumLength = uniRemoteName.Length;
2393                 uniRemoteName.Buffer = wszProviderName;
2394
2395                 if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2396                 {
2397
2398                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2399
2400 #ifdef AFS_DEBUG_TRACE
2401                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2402                                  &uniRemoteName,
2403                                  *lpBufferSize);
2404 #endif
2405                     try_return( dwStatus = WN_MORE_DATA);
2406                 }
2407
2408 #ifdef AFS_DEBUG_TRACE
2409                 AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2410                              &uniRemoteName);
2411 #endif
2412
2413                 SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2414
2415                 pNetResource->dwScope       = RESOURCE_GLOBALNET;
2416                 pNetResource->dwType        = RESOURCETYPE_ANY;
2417                 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
2418                 pNetResource->dwUsage       = RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_RESERVED;
2419
2420                 // setup string area at opposite end of buffer
2421                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2422
2423                 pNetResource->lpLocalName = NULL;
2424
2425                 // copy remote name
2426                 pNetResource->lpRemoteName = StringZone;
2427
2428                 StringCbCopy( StringZone,
2429                               cbProviderNameLength + sizeof( WCHAR),
2430                               wszProviderName);
2431
2432                 StringZone += cbProviderNameLength / sizeof(WCHAR) + 1;
2433
2434                 pNetResource->lpComment = NULL;
2435
2436                 // copy provider name
2437                 pNetResource->lpProvider = StringZone;
2438                 StringCbCopy( StringZone,
2439                               cbProviderNameLength + sizeof( WCHAR),
2440                               wszProviderName);
2441
2442                 StringZone += cbProviderNameLength / sizeof( WCHAR) + 1;
2443
2444 #ifdef AFS_DEBUG_TRACE
2445                 AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2446                              pNetResource,
2447                              GetScopeString(pNetResource->dwScope),
2448                              GetTypeString(pNetResource->dwType),
2449                              GetDisplayString(pNetResource->dwDisplayType),
2450                              GetUsageString(pNetResource->dwUsage),
2451                              pNetResource->lpLocalName,
2452                              pNetResource->lpRemoteName,
2453                              pNetResource->lpComment);
2454 #endif
2455
2456                 // setup the new end of buffer
2457                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2458
2459                 EntriesCopied++;
2460
2461                 pNetResource++;
2462
2463                 // do not change the index since we did not query the redirector
2464                 pEnumCB->CurrentIndex = 0;
2465
2466                 // remember that we returned the provider name
2467                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2468
2469                 if( pEnumCB->RemoteName == NULL)
2470                 {
2471
2472                     try_return( dwStatus = WN_OUT_OF_MEMORY);
2473                 }
2474                 else
2475                 {
2476
2477                     StringCbCopy( pEnumCB->RemoteName,
2478                                    0x1000,
2479                                    wszProviderName);
2480                 }
2481             }
2482
2483             if ( pEnumCB->CurrentIndex == 0 &&
2484                  lstrlen( pEnumCB->RemoteName) == cbProviderNameLength / sizeof( WCHAR) &&
2485                  _wcsnicmp( pEnumCB->RemoteName, wszProviderName, cbProviderNameLength / sizeof( WCHAR)) == 0 &&
2486                  EntriesCopied < EntriesRequested)
2487             {
2488
2489                 //
2490                 // After the network provider entry comes the server entry
2491                 //
2492
2493                 // Determine the space needed for this entry...
2494
2495                 SpaceNeeded = cbProviderNameLength + cbServerNameUNCLength + cbServerCommentLength + 3 * sizeof( WCHAR);
2496
2497                 uniRemoteName.Length = (USHORT)cbServerNameUNCLength;
2498                 uniRemoteName.MaximumLength = uniRemoteName.Length;
2499                 uniRemoteName.Buffer = wszServerNameUNC;
2500
2501                 if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2502                 {
2503
2504                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2505
2506 #ifdef AFS_DEBUG_TRACE
2507                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2508                                  &uniRemoteName,
2509                                  *lpBufferSize);
2510 #endif
2511                     try_return( dwStatus = WN_MORE_DATA);
2512                 }
2513
2514 #ifdef AFS_DEBUG_TRACE
2515                 AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2516                              &uniRemoteName);
2517 #endif
2518
2519                 SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2520
2521                 pNetResource->dwScope       = 0;
2522                 pNetResource->dwType        = RESOURCETYPE_ANY;
2523                 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2524                 pNetResource->dwUsage       = RESOURCEUSAGE_CONTAINER;
2525
2526                 // setup string area at opposite end of buffer
2527                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2528
2529                 pNetResource->lpLocalName = NULL;
2530
2531                 // copy remote name
2532                 pNetResource->lpRemoteName = StringZone;
2533
2534                 StringCbCopy( StringZone,
2535                               cbServerNameUNCLength + sizeof( WCHAR),
2536                               wszServerNameUNC);
2537
2538                 StringZone += cbServerNameUNCLength / sizeof(WCHAR) + 1;
2539
2540                 // copy comment
2541                 pNetResource->lpComment = StringZone;
2542
2543                 StringCbCopy( StringZone,
2544                               cbServerCommentLength + sizeof( WCHAR),
2545                               wszServerComment);
2546
2547                 StringZone += cbServerCommentLength / sizeof( WCHAR) + 1;
2548
2549                 // copy provider name
2550                 pNetResource->lpProvider = StringZone;
2551                 StringCbCopy( StringZone,
2552                               cbProviderNameLength + sizeof( WCHAR),
2553                               wszProviderName);
2554
2555                 StringZone += cbProviderNameLength / sizeof( WCHAR) + 1;
2556
2557 #ifdef AFS_DEBUG_TRACE
2558                 AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2559                              pNetResource,
2560                              GetScopeString(pNetResource->dwScope),
2561                              GetTypeString(pNetResource->dwType),
2562                              GetDisplayString(pNetResource->dwDisplayType),
2563                              GetUsageString(pNetResource->dwUsage),
2564                              pNetResource->lpLocalName,
2565                              pNetResource->lpRemoteName,
2566                              pNetResource->lpComment);
2567 #endif
2568
2569                 // setup the new end of buffer
2570                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2571
2572                 EntriesCopied++;
2573
2574                 pNetResource++;
2575
2576                 // do not update the index because we did not query the redirector
2577                 pEnumCB->CurrentIndex = 0;
2578
2579                 // remember that we returned the server
2580                 StringCbCopy( pEnumCB->RemoteName,
2581                               0x1000,
2582                               wszServerNameUNC);
2583             }
2584         }
2585 #endif
2586
2587         //
2588         // Setup what we are going to ask for
2589         //
2590
2591         pConnectionCB->Scope = pEnumCB->Scope;
2592
2593         pConnectionCB->Type = pEnumCB->Type;
2594
2595         pConnectionCB->CurrentIndex = pEnumCB->CurrentIndex;
2596
2597         pConnectionCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
2598
2599         //
2600         // If this is a RESOURCE_GLOBALNET enumeration then pass down the remote name if
2601         // there is one
2602         //
2603
2604         pConnectionCB->RemoteNameLength = 0;
2605
2606         if( pEnumCB->Scope == RESOURCE_GLOBALNET &&
2607             pEnumCB->RemoteName != NULL)
2608         {
2609
2610             pConnectionCB->RemoteNameLength = wcslen( pEnumCB->RemoteName) * sizeof( WCHAR);
2611
2612             StringCbCopy( pConnectionCB->RemoteName,
2613                           (0x1000 - sizeof(AFSNetworkProviderConnectionCB)) + sizeof(WCHAR),
2614                           pEnumCB->RemoteName);
2615         }
2616
2617         pConnectionCB->AuthenticationId = AFSRetrieveAuthId();
2618
2619 #ifdef AFS_DEBUG_TRACE
2620         AFSDbgPrint( L"NPEnumResource Retrieved authentication id %08lX-%08lX\n",
2621                      pConnectionCB->AuthenticationId.HighPart,
2622                      pConnectionCB->AuthenticationId.LowPart);
2623 #endif
2624
2625         dwError = DeviceIoControl( hControlDevice,
2626                                    IOCTL_AFS_LIST_CONNECTIONS,
2627                                    pConnectionCB,
2628                                    0x1000,
2629                                    pConnectionCB,
2630                                    0x1000,
2631                                    &dwCopyBytes,
2632                                    NULL);
2633
2634         if( !dwError)
2635         {
2636 #ifdef AFS_DEBUG_TRACE
2637             DWORD gle = GetLastError();
2638
2639             AFSDbgPrint( L"NPEnumResource Failed to list connections from file system - gle 0x%x\n",
2640                          gle);
2641 #endif
2642             try_return( dwStatus = WN_NOT_CONNECTED);
2643         }
2644
2645         if( dwCopyBytes == 0)
2646         {
2647
2648 #ifdef AFS_DEBUG_TRACE
2649             AFSDbgPrint( L"NPEnumResource No More Entries\n");
2650 #endif
2651             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2652         }
2653
2654         dwIndex = pEnumCB->CurrentIndex;
2655
2656         while( EntriesCopied < EntriesRequested)
2657         {
2658
2659             uniRemoteName.Length = (USHORT)pConnectionCB->RemoteNameLength;
2660             uniRemoteName.MaximumLength = uniRemoteName.Length;
2661             uniRemoteName.Buffer = pConnectionCB->RemoteName;
2662
2663             // Determine the space needed for this entry...
2664
2665             SpaceNeeded  = 0;
2666
2667             if( pConnectionCB->LocalName != 0)
2668             {
2669
2670                 SpaceNeeded += 3 * sizeof(WCHAR);                // local name
2671             }
2672
2673             SpaceNeeded += pConnectionCB->RemoteNameLength + sizeof( WCHAR);        // remote name
2674
2675             if( pConnectionCB->CommentLength > 0)
2676             {
2677
2678                 SpaceNeeded += pConnectionCB->CommentLength + sizeof( WCHAR);           // comment
2679             }
2680
2681             SpaceNeeded += cbProviderNameLength + sizeof( WCHAR);           // provider name
2682
2683             if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2684             {
2685
2686                 if (EntriesCopied == 0) {
2687
2688                     dwStatus = WN_MORE_DATA;
2689
2690                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2691
2692 #ifdef AFS_DEBUG_TRACE
2693                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2694                                  &uniRemoteName,
2695                                  *lpBufferSize);
2696 #endif
2697
2698                 } else {
2699
2700 #ifdef AFS_DEBUG_TRACE
2701                     AFSDbgPrint( L"NPEnumResource Return SUCCESS but more entries Index %d\n",
2702                                  dwIndex);
2703 #endif
2704
2705                     dwStatus = WN_SUCCESS;
2706                 }
2707
2708                 break;
2709             }
2710
2711             SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2712
2713             pNetResource->dwScope       = pConnectionCB->Scope;
2714             pNetResource->dwType        = pConnectionCB->Type;
2715
2716             pNetResource->dwDisplayType = pConnectionCB->DisplayType;
2717
2718             if ( pNetResource->dwType == RESOURCETYPE_ANY &&
2719                  pNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE)
2720             {
2721
2722                 pNetResource->dwType = RESOURCETYPE_DISK;
2723             }
2724
2725             if ( pEnumCB->Scope == RESOURCE_CONNECTED)
2726             {
2727
2728                 pNetResource->dwUsage       = 0;
2729             }
2730             else
2731             {
2732
2733                 pNetResource->dwUsage       = pConnectionCB->Usage;
2734             }
2735
2736             // setup string area at opposite end of buffer
2737             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2738
2739             // copy local name
2740             if( pConnectionCB->LocalName != 0)
2741             {
2742
2743                 pNetResource->lpLocalName = StringZone;
2744                 *StringZone++ = towupper(pConnectionCB->LocalName);
2745                 *StringZone++ = L':';
2746                 *StringZone++ = L'\0';
2747             }
2748             else
2749             {
2750
2751                 pNetResource->lpLocalName = NULL;
2752             }
2753
2754 #ifdef AFS_DEBUG_TRACE
2755             AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2756                          &uniRemoteName);
2757 #endif
2758
2759             // copy remote name
2760             pNetResource->lpRemoteName = StringZone;
2761
2762             CopyMemory( StringZone,
2763                         pConnectionCB->RemoteName,
2764                         pConnectionCB->RemoteNameLength);
2765
2766             StringZone += (pConnectionCB->RemoteNameLength / sizeof(WCHAR));
2767
2768             *StringZone++ = L'\0';
2769
2770             // copy comment
2771             if( pConnectionCB->CommentLength > 0)
2772             {
2773
2774                 pNetResource->lpComment = StringZone;
2775
2776                 CopyMemory( StringZone,
2777                             (void *)((char *)pConnectionCB + pConnectionCB->CommentOffset),
2778                             pConnectionCB->CommentLength);
2779
2780                 StringZone += (pConnectionCB->CommentLength / sizeof(WCHAR));
2781
2782                 *StringZone++ = L'\0';
2783             }
2784             else
2785             {
2786
2787                 pNetResource->lpComment = NULL;
2788             }
2789
2790             // copy provider name
2791             pNetResource->lpProvider = StringZone;
2792             StringCbCopy( StringZone,
2793                           cbProviderNameLength + sizeof( WCHAR),
2794                           wszProviderName);
2795
2796             StringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
2797
2798 #ifdef AFS_DEBUG_TRACE
2799             AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2800                          pNetResource,
2801                          GetScopeString(pNetResource->dwScope),
2802                          GetTypeString(pNetResource->dwType),
2803                          GetDisplayString(pNetResource->dwDisplayType),
2804                          GetUsageString(pNetResource->dwUsage),
2805                          pNetResource->lpLocalName,
2806                          pNetResource->lpRemoteName,
2807                          pNetResource->lpComment);
2808 #endif
2809
2810             // setup the new end of buffer
2811             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2812
2813             EntriesCopied++;
2814
2815             pNetResource++;
2816
2817             dwIndex++;
2818
2819             dwCopyBytes -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2820                            pConnectionCB->RemoteNameLength +
2821                            pConnectionCB->CommentLength;
2822
2823             if( dwCopyBytes == 0)
2824             {
2825
2826                 dwStatus = WN_SUCCESS;
2827
2828                 break;
2829             }
2830
2831             pConnectionCB = (AFSNetworkProviderConnectionCB *)((char *)pConnectionCB +
2832                             FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2833                             pConnectionCB->RemoteNameLength +
2834                             pConnectionCB->CommentLength);
2835         }
2836
2837         *lpcCount = EntriesCopied;
2838
2839         // update entry index
2840         pEnumCB->CurrentIndex = dwIndex;
2841
2842 #ifdef AFS_DEBUG_TRACE
2843         AFSDbgPrint( L"NPEnumResource Completed Count %d Index %d\n",
2844                      EntriesCopied,
2845                      dwIndex);
2846 #endif
2847
2848 try_exit:
2849
2850         if ( hControlDevice != NULL)
2851         {
2852
2853             CloseHandle( hControlDevice);
2854         }
2855
2856         if( pConnectionCBBase != NULL)
2857         {
2858
2859             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectionCBBase);
2860         }
2861     }
2862
2863     return dwStatus;
2864 }
2865
2866 /*++
2867
2868 Routine Description:
2869
2870     This routine closes the handle for enumeration of resources.
2871
2872 Arguments:
2873
2874     hEnum  - the enumeration handle
2875
2876 Return Value:
2877
2878     WN_SUCCESS if successful, otherwise the appropriate error
2879
2880 Notes:
2881
2882     The sample only supports the notion of enumerating connected shares
2883
2884 --*/
2885
2886 DWORD APIENTRY
2887 NPCloseEnum( HANDLE hEnum )
2888 {
2889
2890     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2891
2892 #ifdef AFS_DEBUG_TRACE
2893     AFSDbgPrint( L"NPCloseEnum\n");
2894 #endif
2895
2896     if( pEnumCB->RemoteName != NULL)
2897     {
2898
2899         HeapFree( GetProcessHeap( ), 0, (PVOID) pEnumCB->RemoteName);
2900     }
2901
2902     HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum );
2903
2904     return WN_SUCCESS;
2905 }
2906
2907 DWORD APIENTRY
2908 NPGetResourceParent( LPNETRESOURCE   lpNetResource,
2909                      LPVOID  lpBuffer,
2910                      LPDWORD lpBufferSize )
2911 {
2912
2913     DWORD    dwStatus = WN_ACCESS_DENIED;
2914     WCHAR   *pwchRemoteName = NULL, *pwchSearch = NULL, *pwchSystem = NULL;
2915     LPNETRESOURCE lpOutResource = (LPNETRESOURCE) lpBuffer;
2916
2917     if ( lpNetResource == NULL)
2918     {
2919 #ifdef AFS_DEBUG_TRACE
2920         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2921 #endif
2922         return WN_MORE_DATA;
2923     }
2924
2925     if( lpNetResource->lpRemoteName == NULL)
2926     {
2927 #ifdef AFS_DEBUG_TRACE
2928         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2929 #endif
2930         return WN_BAD_NETNAME;
2931     }
2932
2933     if ( lpNetResource->dwType != 0 &&
2934          lpNetResource->dwType != RESOURCETYPE_DISK)
2935     {
2936 #ifdef AFS_DEBUG_TRACE
2937         AFSDbgPrint( L"NPGetResourceParent Bad dwType\n");
2938 #endif
2939         return WN_BAD_VALUE;
2940     }
2941
2942     if ( lpBufferSize == NULL )
2943     {
2944
2945 #ifdef AFS_DEBUG_TRACE
2946         AFSDbgPrint( L"NPGetResourceParent Null lpBufferSize\n");
2947 #endif
2948         return WN_BAD_VALUE;
2949     }
2950
2951 #ifdef AFS_DEBUG_TRACE
2952     AFSDbgPrint( L"NPGetResourceParent For remote name %s\n",
2953                  lpNetResource->lpRemoteName);
2954 #endif
2955
2956     pwchRemoteName = lpNetResource->lpRemoteName;
2957
2958     pwchSearch = pwchRemoteName + (wcslen( pwchRemoteName) - 1);
2959
2960     while( pwchSearch != pwchRemoteName)
2961     {
2962
2963         if( *pwchSearch == L'\\')
2964         {
2965
2966             *pwchSearch = L'\0';
2967
2968             break;
2969         }
2970
2971         pwchSearch--;
2972     }
2973
2974     if( pwchSearch != pwchRemoteName)
2975     {
2976
2977 #ifdef AFS_DEBUG_TRACE
2978         AFSDbgPrint( L"NPGetResourceParent Processing parent %s\n",
2979                      lpNetResource->lpRemoteName);
2980 #endif
2981
2982         dwStatus = NPGetResourceInformation( lpNetResource,
2983                                              lpBuffer,
2984                                              lpBufferSize,
2985                                              &pwchSystem);
2986     }
2987     else
2988     {
2989         if ( lpOutResource == NULL ||
2990              *lpBufferSize < sizeof( NETRESOURCE) )
2991         {
2992             *lpBufferSize = sizeof( NETRESOURCE);
2993
2994             return WN_MORE_DATA;
2995         }
2996
2997         memset( lpOutResource, 0, sizeof( NETRESOURCE));
2998
2999         return WN_SUCCESS;
3000
3001     }
3002
3003     return dwStatus;
3004 }
3005
3006 DWORD APIENTRY
3007 NPGetResourceInformation( LPNETRESOURCE   lpNetResource,
3008                           LPVOID  lpBuffer,
3009                           LPDWORD lpBufferSize,
3010                           LPWSTR  *lplpSystem )
3011 {
3012
3013     DWORD    dwStatus = WN_NOT_CONNECTED;
3014     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3015     DWORD    dwError = 0;
3016     DWORD    dwBufferSize = 0;
3017     HANDLE   hControlDevice = NULL;
3018     NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
3019     PWCHAR   pStringZone = NULL;
3020     UNICODE_STRING uniRemoteName;
3021     DWORD    ulRequiredLen = 0;
3022     DWORD    dwPassedSize;
3023
3024
3025     __Enter
3026     {
3027         if ( lplpSystem)
3028         {
3029             *lplpSystem = NULL;
3030         }
3031
3032         ReadProviderNameString();
3033
3034         if ( NPIsFSDisabled())
3035         {
3036
3037 #ifdef AFS_DEBUG_TRACE
3038             AFSDbgPrint( L"NPGetResourceInformation AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
3039 #endif
3040
3041             try_return( dwStatus = WN_BAD_NETNAME);
3042         }
3043
3044         if ( lpNetResource == NULL ||
3045              lpBufferSize == NULL )
3046         {
3047
3048 #ifdef AFS_DEBUG_TRACE
3049             AFSDbgPrint( L"NPGetResourceInformaton Null lpNetResource or lpBufferSize\n");
3050 #endif
3051             return WN_BAD_VALUE;
3052         }
3053
3054         if( lpNetResource->lpRemoteName == NULL)
3055         {
3056 #ifdef AFS_DEBUG_TRACE
3057             AFSDbgPrint( L"NPGetResourceInformation No resource name\n");
3058 #endif
3059
3060             try_return( dwStatus = WN_NOT_CONNECTED);
3061         }
3062
3063         dwPassedSize = *lpBufferSize;
3064
3065         dwBufferSize = 0x1000;
3066
3067         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
3068
3069         if( pConnectCB == NULL)
3070         {
3071
3072             try_return( dwStatus = WN_OUT_OF_MEMORY);
3073         }
3074
3075         pConnectCB->RemoteNameLength = wcslen( lpNetResource->lpRemoteName) * sizeof( WCHAR);
3076
3077         StringCbCopy( pConnectCB->RemoteName,
3078                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
3079                       lpNetResource->lpRemoteName);
3080
3081         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
3082
3083         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
3084
3085 #ifdef AFS_DEBUG_TRACE
3086         AFSDbgPrint( L"NPGetResourceInformation Retrieved authentication id %08lX-%08lX\n",
3087                      pConnectCB->AuthenticationId.HighPart,
3088                      pConnectCB->AuthenticationId.LowPart);
3089 #endif
3090
3091         hControlDevice = OpenRedirector();
3092
3093         if( hControlDevice == NULL)
3094         {
3095
3096 #ifdef AFS_DEBUG_TRACE
3097             AFSDbgPrint( L"NPGetResourceInformation OpenRedirector failure, returning WN_NET_ERROR\n");
3098 #endif
3099
3100             try_return( dwStatus = WN_NET_ERROR);
3101         }
3102
3103         dwError = DeviceIoControl( hControlDevice,
3104                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
3105                                    pConnectCB,
3106                                    dwBufferSize,
3107                                    pConnectCB,
3108                                    dwBufferSize,
3109                                    lpBufferSize,
3110                                    NULL);
3111
3112         if( !dwError)
3113         {
3114 #ifdef AFS_DEBUG_TRACE
3115             DWORD gle = GetLastError();
3116
3117             AFSDbgPrint( L"NPGetResourceInformation Failed to get connection info from file system for local %s gle 0x%x\n",
3118                          lpNetResource->lpRemoteName, gle);
3119 #endif
3120             try_return( dwStatus = WN_BAD_NETNAME);
3121         }
3122
3123         uniRemoteName.Length = (USHORT)pConnectCB->RemoteNameLength;
3124         uniRemoteName.MaximumLength = uniRemoteName.Length;
3125         uniRemoteName.Buffer = pConnectCB->RemoteName;
3126
3127 #ifdef AFS_DEBUG_TRACE
3128         AFSDbgPrint( L"NPGetResourceInformation For remote name %wZ Scope %08lX Type %08lX Usage %08lX\n",
3129                      &uniRemoteName,
3130                      pConnectCB->Scope,
3131                      pConnectCB->Type,
3132                      pConnectCB->Usage);
3133 #endif
3134
3135         // Determine the space needed for this entry...
3136
3137         ulRequiredLen = sizeof( NETRESOURCE);
3138
3139         ulRequiredLen += pConnectCB->RemoteNameLength + sizeof( WCHAR);
3140
3141         ulRequiredLen += pConnectCB->CommentLength + sizeof( WCHAR);
3142
3143         ulRequiredLen += cbProviderNameLength + sizeof( WCHAR);
3144
3145         ulRequiredLen += pConnectCB->RemainingPathLength + sizeof( WCHAR);
3146
3147         if( pNetResource == NULL ||
3148             ulRequiredLen > dwPassedSize)
3149         {
3150
3151             *lpBufferSize = ulRequiredLen;
3152
3153             try_return( dwStatus = WN_MORE_DATA);
3154         }
3155
3156         pStringZone = (PWCHAR) ((char *)lpBuffer + sizeof( NETRESOURCE));
3157
3158         pNetResource->dwScope       = 0 /* pConnectCB->Scope*/;
3159         pNetResource->dwType        = 0 /* pConnectCB->Type */;
3160
3161         pNetResource->dwDisplayType = pConnectCB->DisplayType;
3162
3163         pNetResource->dwUsage       = pConnectCB->Usage;
3164
3165         pNetResource->lpLocalName = NULL;
3166
3167         // copy remote name
3168         pNetResource->lpRemoteName = pStringZone;
3169
3170         CopyMemory( pStringZone,
3171                     pConnectCB->RemoteName,
3172                     pConnectCB->RemoteNameLength);
3173
3174         pStringZone += (pConnectCB->RemoteNameLength / sizeof(WCHAR));
3175
3176         *pStringZone++ = L'\0';
3177
3178         // copy comment
3179         pNetResource->lpComment = pStringZone;
3180
3181         CopyMemory( pStringZone,
3182                     (void *)((char *)pConnectCB + pConnectCB->CommentOffset),
3183                     pConnectCB->CommentLength);
3184
3185         pStringZone += (pConnectCB->CommentLength / sizeof(WCHAR));
3186
3187         *pStringZone++ = L'\0';
3188
3189         // copy remaining path
3190         if (pConnectCB->RemainingPathLength > 0)
3191         {
3192             *lplpSystem = pStringZone;
3193
3194             CopyMemory( pStringZone,
3195                         (void *)((char *)pConnectCB + pConnectCB->RemainingPathOffset),
3196                         pConnectCB->RemainingPathLength);
3197
3198             pStringZone += (pConnectCB->RemainingPathLength / sizeof(WCHAR));
3199
3200             *pStringZone++ = L'\0';
3201
3202 #ifdef AFS_DEBUG_TRACE
3203             AFSDbgPrint( L"NPGetResourceInformation For remote name %s returning remaining path %s\n",
3204                          pNetResource->lpRemoteName,
3205                          *lplpSystem);
3206 #endif
3207         }
3208
3209         // copy provider name
3210         pNetResource->lpProvider = pStringZone;
3211
3212         StringCbCopy( pStringZone,
3213                       cbProviderNameLength + sizeof( WCHAR),
3214                       wszProviderName);
3215
3216         pStringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
3217
3218         *lpBufferSize = ulRequiredLen;
3219
3220         dwStatus = WN_SUCCESS;
3221
3222 try_exit:
3223
3224         if ( hControlDevice != NULL)
3225         {
3226
3227             CloseHandle( hControlDevice);
3228         }
3229
3230         if( pConnectCB != NULL)
3231         {
3232
3233             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3234         }
3235     }
3236
3237     return dwStatus;
3238 }
3239
3240 static VOID
3241 SeparateRemainingPath( WCHAR * lpConnectionName, WCHAR **lppRemainingPath)
3242 {
3243     WCHAR *pwch;
3244     WCHAR wch1, wch2;
3245     DWORD  dwCount;
3246
3247     //
3248     // at this point the lpConnectionName contains the full name.  We need to
3249     // truncate it to \\server\share and move the remaining path back one position.
3250     //
3251
3252     for ( pwch = lpConnectionName, dwCount = 0; *pwch; pwch++)
3253     {
3254         if ( *pwch == L'\\')
3255         {
3256             dwCount++;
3257         }
3258
3259         if ( dwCount == 4)
3260         {
3261             break;
3262         }
3263     }
3264
3265     if (*pwch == L'\\')
3266     {
3267         //
3268         // Found the remaining path that must be moved
3269         //
3270
3271         *lppRemainingPath = pwch + 1;
3272
3273         *pwch++ = 0;
3274
3275         //
3276         // Find the end
3277         //
3278         for ( ; *pwch; pwch++);
3279
3280         //
3281         // and work backwards moving the string
3282         // and then make sure that there is at least
3283         // a path separator.
3284         //
3285
3286         *(pwch + 1) = 0;
3287
3288         for ( ;pwch > *lppRemainingPath; pwch--)
3289         {
3290             *pwch = *(pwch - 1);
3291         }
3292
3293         *pwch = L'\\';
3294     }
3295 }
3296
3297 DWORD APIENTRY
3298 NPGetUniversalName( LPCWSTR lpLocalPath,
3299                     DWORD   dwInfoLevel,
3300                     LPVOID  lpBuffer,
3301                     LPDWORD lpBufferSize)
3302 {
3303
3304     DWORD dwBufferSize = *lpBufferSize;
3305     DWORD dwStatus;
3306
3307     dwStatus = NPGetUniversalNameCommon( lpLocalPath,
3308                                          dwInfoLevel,
3309                                          lpBuffer,
3310                                          &dwBufferSize,
3311                                          FALSE);
3312
3313     if ( dwStatus == WN_NOT_CONNECTED)
3314     {
3315
3316         dwStatus = NPGetUniversalNameCommon( lpLocalPath,
3317                                              dwInfoLevel,
3318                                              lpBuffer,
3319                                              lpBufferSize,
3320                                              TRUE);
3321     }
3322     else
3323     {
3324
3325         *lpBufferSize = dwBufferSize;
3326     }
3327
3328     return dwStatus;
3329 }
3330
3331 static DWORD APIENTRY
3332 NPGetUniversalNameCommon( LPCWSTR lpLocalPath,
3333                           DWORD   dwInfoLevel,
3334                           LPVOID  lpBuffer,
3335                           LPDWORD lpBufferSize,
3336                           BOOL    bDriveSubstOk)
3337 {
3338     DWORD    dwStatus = WN_NOT_CONNECTED;
3339     WCHAR    wchLocalName[3];
3340     WCHAR   *pwchSubstName = NULL;
3341     DWORD    dwSubstNameLength = 0;
3342     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3343     DWORD    dwError = 0;
3344     DWORD    dwBufferSize = 0;
3345     DWORD    dwPassedSize = *lpBufferSize;
3346     DWORD    dwRemainingLength = *lpBufferSize;
3347     HANDLE   hControlDevice = NULL;
3348     DWORD    dwLocalPathLength = 0;
3349     DWORD    dwRemainingPathLength = 0;
3350     CHAR    *pch;
3351
3352     __Enter
3353     {
3354
3355 #ifdef AFS_DEBUG_TRACE
3356         AFSDbgPrint( L"NPGetUniversalName local path %s level 0x%X\n",
3357                      lpLocalPath ? lpLocalPath : L"(Null)",
3358                      dwInfoLevel);
3359 #endif
3360
3361         if ( NPIsFSDisabled())
3362         {
3363
3364 #ifdef AFS_DEBUG_TRACE
3365             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
3366 #endif
3367
3368             try_return( dwStatus = WN_NOT_CONNECTED);
3369         }
3370
3371         dwLocalPathLength = lstrlen( lpLocalPath);
3372
3373         dwRemainingPathLength = dwLocalPathLength - 2;          // no drive letter
3374
3375         if( dwLocalPathLength == 0)
3376         {
3377
3378 #ifdef AFS_DEBUG_TRACE
3379             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_BAD_LOCALNAME\n");
3380 #endif
3381
3382             try_return( dwStatus = WN_BAD_LOCALNAME);
3383         }
3384
3385         if( lpBuffer == NULL ||
3386             lpBufferSize == NULL)
3387         {
3388 #ifdef AFS_DEBUG_TRACE
3389             AFSDbgPrint( L"NPGetUniversalName No output buffer or size\n");
3390 #endif
3391             try_return( dwStatus = WN_BAD_VALUE);
3392         }
3393
3394         dwSubstNameLength = 4096;
3395
3396         pwchSubstName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSubstNameLength);
3397
3398         if ( pwchSubstName == NULL)
3399         {
3400 #ifdef AFS_DEBUG_TRACE
3401             AFSDbgPrint( L"NPGetUniversalName unable to allocate substitution name buffer.\n");
3402 #endif
3403             try_return( dwStatus = WN_OUT_OF_MEMORY);
3404         }
3405
3406         memset(lpBuffer, 0, dwPassedSize);
3407
3408         if ( !bDriveSubstOk ||
3409              !DriveSubstitution( lpLocalPath, pwchSubstName, dwSubstNameLength, &dwStatus))
3410         {
3411             wchLocalName[0] = towupper(lpLocalPath[0]);
3412             wchLocalName[1] = L':';
3413             wchLocalName[2] = L'\0';
3414
3415 #ifdef AFS_DEBUG_TRACE
3416             AFSDbgPrint( L"NPGetUniversalName Requesting UNC for %s level 0x%X\n",
3417                          wchLocalName,
3418                          dwInfoLevel);
3419 #endif
3420         }
3421         else
3422         {
3423
3424             ReadServerNameString();
3425
3426             if ( pwchSubstName[0] != L'\\' &&
3427                  pwchSubstName[1] == L':')
3428             {
3429
3430                 wchLocalName[0] = towupper(pwchSubstName[0]);
3431                 wchLocalName[1] = L':';
3432                 wchLocalName[2] = L'\0';
3433
3434 #ifdef AFS_DEBUG_TRACE
3435                 AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n",
3436                              pwchSubstName,
3437                              wchLocalName);
3438 #endif
3439             }
3440             else if ( _wcsnicmp( pwchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
3441                       ( pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
3442                         pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
3443             {
3444                 HRESULT hr;
3445
3446 #ifdef AFS_DEBUG_TRACE
3447                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n",
3448                              pwchSubstName,
3449                              dwInfoLevel,
3450                              dwPassedSize);
3451 #endif
3452
3453                 dwBufferSize = (wcslen( pwchSubstName) + 1) * sizeof( WCHAR);
3454
3455                 switch( dwInfoLevel)
3456                 {
3457
3458                 case UNIVERSAL_NAME_INFO_LEVEL:
3459                 {
3460
3461                     UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3462
3463                     *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize;
3464
3465                     if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3466                     {
3467
3468 #ifdef AFS_DEBUG_TRACE
3469                         AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3470 #endif
3471
3472                         try_return( dwStatus = WN_MORE_DATA);
3473                     }
3474
3475                     dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3476
3477                     pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3478
3479                     memcpy( pUniversalInfo->lpUniversalName,
3480                             pwchSubstName,
3481                             min( dwBufferSize, dwRemainingLength));
3482
3483                     dwRemainingLength -= min( dwBufferSize, dwRemainingLength);
3484