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