Linux-6.9: file_lock mbrs moved to file_lock_core
[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     hControlDevice = OpenRedirector();
2243
2244     if( hControlDevice == NULL)
2245     {
2246
2247 #ifdef AFS_DEBUG_TRACE
2248         AFSDbgPrint( L"NPOpenEnum OpenRedirector failure, returning WN_NET_ERROR\n");
2249 #endif
2250
2251         return WN_NO_NETWORK;
2252     }
2253
2254     CloseHandle( hControlDevice);
2255
2256
2257     *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( AFSEnumerationCB));
2258
2259     if( *lphEnum == NULL)
2260     {
2261
2262         return WN_OUT_OF_MEMORY;
2263     }
2264
2265     pEnumCB = (AFSEnumerationCB *)*lphEnum;
2266
2267     pEnumCB->CurrentIndex = 0;
2268
2269     pEnumCB->Type = dwType;
2270
2271     switch( dwScope )
2272     {
2273         case RESOURCE_CONNECTED:
2274         {
2275
2276             pEnumCB->Scope = RESOURCE_CONNECTED;
2277
2278             break;
2279         }
2280
2281         case RESOURCE_CONTEXT:
2282         {
2283
2284             pEnumCB->Scope = RESOURCE_CONTEXT;
2285
2286             break;
2287         }
2288
2289         case RESOURCE_GLOBALNET:
2290         {
2291
2292             if( lpNetResource != NULL &&
2293                 lpNetResource->lpRemoteName != NULL)
2294             {
2295
2296                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2297
2298                 if( pEnumCB->RemoteName == NULL)
2299                 {
2300
2301                     dwStatus = WN_OUT_OF_MEMORY;
2302                     HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2303                     *lphEnum = NULL;
2304                 }
2305                 else
2306                 {
2307
2308                     StringCbCopy( pEnumCB->RemoteName,
2309                                   0x1000,
2310                                   lpNetResource->lpRemoteName);
2311
2312                 }
2313             }
2314
2315             pEnumCB->Scope = RESOURCE_GLOBALNET;
2316
2317             break;
2318         }
2319
2320         default:
2321
2322 #ifdef AFS_DEBUG_TRACE
2323             AFSDbgPrint( L"NPOpenEnum Processing (Scope %s 0x%x) Type %s Usage %s, returning WN_NOT_SUPPORTED\n",
2324                          GetScopeString(dwScope), dwScope, GetTypeString(dwType), GetUsageString(dwUsage));
2325 #endif
2326
2327             dwStatus  = WN_NOT_SUPPORTED;
2328             HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2329             *lphEnum = NULL;
2330
2331             break;
2332     }
2333
2334     return dwStatus;
2335 }
2336
2337
2338 DWORD
2339 APIENTRY
2340 NPEnumResource( HANDLE  hEnum,
2341                 LPDWORD lpcCount,
2342                 LPVOID  lpBuffer,
2343                 LPDWORD lpBufferSize)
2344 {
2345
2346     DWORD            dwStatus = WN_NO_MORE_ENTRIES; //WN_SUCCESS;
2347     ULONG            dwCopyBytes;
2348     ULONG            EntriesCopied;
2349     ULONG            EntriesRequested;
2350     ULONG            dwIndex;
2351     LPNETRESOURCE    pNetResource;
2352     ULONG            SpaceNeeded;
2353     ULONG            SpaceAvailable;
2354     PWCHAR           StringZone;
2355     AFSNetworkProviderConnectionCB *pConnectionCB = NULL;
2356     void            *pConnectionCBBase = NULL;
2357     DWORD            dwError = 0;
2358     UNICODE_STRING   uniRemoteName;
2359     HANDLE           hControlDevice = NULL;
2360     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2361
2362     __Enter
2363     {
2364
2365         if ( lpBufferSize == NULL)
2366         {
2367 #ifdef AFS_DEBUG_TRACE
2368             AFSDbgPrint( L"NPEnumResource No output size, returning WN_BAD_VALUE\n");
2369 #endif
2370             try_return( dwStatus = WN_BAD_VALUE);
2371         }
2372
2373         ReadProviderNameString();
2374
2375         pNetResource = (LPNETRESOURCE) lpBuffer;
2376         SpaceAvailable = *lpBufferSize;
2377         EntriesRequested = *lpcCount;
2378         *lpcCount = EntriesCopied = 0;
2379         StringZone = (PWCHAR) ((char *)lpBuffer + *lpBufferSize);
2380
2381 #ifdef AFS_DEBUG_TRACE
2382         AFSDbgPrint( L"NPEnumResource Processing Remote name %s Scope %s Type %s Usage %s Index %d SpaceAvailable 0x%lX RequestedEntries %lu\n",
2383                      pEnumCB->RemoteName ? pEnumCB->RemoteName : L"(Null)",
2384                      GetScopeString(pEnumCB->Scope),
2385                      GetTypeString(pEnumCB->Type),
2386                      GetUsageString(pEnumCB->Type),
2387                      pEnumCB->CurrentIndex,
2388                      SpaceAvailable,
2389                      EntriesRequested);
2390 #endif
2391
2392         if ( NPIsFSDisabled())
2393         {
2394
2395 #ifdef AFS_DEBUG_TRACE
2396             AFSDbgPrint( L"NPEnumResource AFSRDFS is disabled, returning WN_NO_MORE_ENTRIES\n");
2397 #endif
2398
2399             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2400         }
2401
2402         pConnectionCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
2403
2404         if( pConnectionCB == NULL)
2405         {
2406
2407 #ifdef AFS_DEBUG_TRACE
2408             AFSDbgPrint( L"NPEnumResource Out of Memory\n");
2409 #endif
2410
2411             try_return( dwStatus = WN_OUT_OF_MEMORY);
2412         }
2413
2414         pConnectionCBBase = (void *)pConnectionCB;
2415
2416         hControlDevice = OpenRedirector();
2417
2418         if( hControlDevice == NULL)
2419         {
2420
2421 #ifdef AFS_DEBUG_TRACE
2422             AFSDbgPrint( L"NPEnumResource OpenRedirector failure, returning WN_NET_ERROR\n");
2423 #endif
2424
2425             try_return( dwStatus = WN_NET_ERROR);
2426         }
2427
2428         if( pEnumCB->Type != RESOURCETYPE_ANY && pEnumCB->Type != RESOURCETYPE_DISK)
2429         {
2430
2431 #ifdef AFS_DEBUG_TRACE
2432             AFSDbgPrint( L"NPEnumResource Non-DISK queries are not supported, returning WN_NO_MORE_ENTRIES\n");
2433 #endif
2434             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2435         }
2436
2437         //
2438         // Setup what we are going to ask for
2439         //
2440
2441         pConnectionCB->Scope = pEnumCB->Scope;
2442
2443         pConnectionCB->Type = pEnumCB->Type;
2444
2445         pConnectionCB->CurrentIndex = pEnumCB->CurrentIndex;
2446
2447         pConnectionCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
2448
2449         //
2450         // If this is a RESOURCE_GLOBALNET enumeration then pass down the remote name if
2451         // there is one
2452         //
2453
2454         pConnectionCB->RemoteNameLength = 0;
2455
2456         if( pEnumCB->Scope == RESOURCE_GLOBALNET &&
2457             pEnumCB->RemoteName != NULL)
2458         {
2459
2460             pConnectionCB->RemoteNameLength = wcslen( pEnumCB->RemoteName) * sizeof( WCHAR);
2461
2462             StringCbCopy( pConnectionCB->RemoteName,
2463                           (0x1000 - sizeof(AFSNetworkProviderConnectionCB)) + sizeof(WCHAR),
2464                           pEnumCB->RemoteName);
2465         }
2466
2467         dwError = DeviceIoControl( hControlDevice,
2468                                    IOCTL_AFS_LIST_CONNECTIONS,
2469                                    pConnectionCB,
2470                                    0x1000,
2471                                    pConnectionCB,
2472                                    0x1000,
2473                                    &dwCopyBytes,
2474                                    NULL);
2475
2476         if( !dwError)
2477         {
2478 #ifdef AFS_DEBUG_TRACE
2479             DWORD gle = GetLastError();
2480
2481             AFSDbgPrint( L"NPEnumResource Failed to list connections from file system - gle 0x%x\n",
2482                          gle);
2483 #endif
2484             try_return( dwStatus = WN_NOT_CONNECTED);
2485         }
2486
2487         if( dwCopyBytes == 0)
2488         {
2489
2490 #ifdef AFS_DEBUG_TRACE
2491             AFSDbgPrint( L"NPEnumResource No More Entries\n");
2492 #endif
2493             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2494         }
2495
2496         dwIndex = pEnumCB->CurrentIndex;
2497
2498         while( EntriesCopied < EntriesRequested)
2499         {
2500
2501             uniRemoteName.Length = (USHORT)pConnectionCB->RemoteNameLength;
2502             uniRemoteName.MaximumLength = uniRemoteName.Length;
2503             uniRemoteName.Buffer = pConnectionCB->RemoteName;
2504
2505             // Determine the space needed for this entry...
2506
2507             SpaceNeeded  = 0;
2508
2509             if( pConnectionCB->LocalName != 0)
2510             {
2511
2512                 SpaceNeeded += 3 * sizeof(WCHAR);                // local name
2513             }
2514
2515             SpaceNeeded += pConnectionCB->RemoteNameLength + sizeof( WCHAR);        // remote name
2516
2517             if( pConnectionCB->CommentLength > 0)
2518             {
2519
2520                 SpaceNeeded += pConnectionCB->CommentLength + sizeof( WCHAR);           // comment
2521             }
2522
2523             SpaceNeeded += cbProviderNameLength + sizeof( WCHAR);           // provider name
2524
2525             if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2526             {
2527
2528                 if (EntriesCopied == 0) {
2529
2530                     dwStatus = WN_MORE_DATA;
2531
2532                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2533
2534 #ifdef AFS_DEBUG_TRACE
2535                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2536                                  &uniRemoteName,
2537                                  *lpBufferSize);
2538 #endif
2539
2540                 } else {
2541
2542 #ifdef AFS_DEBUG_TRACE
2543                     AFSDbgPrint( L"NPEnumResource Return SUCCESS but more entries Index %d\n",
2544                                  dwIndex);
2545 #endif
2546
2547                     dwStatus = WN_SUCCESS;
2548                 }
2549
2550                 break;
2551             }
2552
2553             SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2554
2555             pNetResource->dwScope       = pConnectionCB->Scope;
2556             pNetResource->dwType        = pConnectionCB->Type;
2557
2558             pNetResource->dwDisplayType = pConnectionCB->DisplayType;
2559
2560             if ( pNetResource->dwType == RESOURCETYPE_ANY &&
2561                  pNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE)
2562             {
2563
2564                 pNetResource->dwType = RESOURCETYPE_DISK;
2565             }
2566
2567             if ( pEnumCB->Scope == RESOURCE_CONNECTED)
2568             {
2569
2570                 pNetResource->dwUsage       = 0;
2571             }
2572             else
2573             {
2574
2575                 pNetResource->dwUsage       = pConnectionCB->Usage;
2576             }
2577
2578             // setup string area at opposite end of buffer
2579             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2580
2581             // copy local name
2582             if( pConnectionCB->LocalName != 0)
2583             {
2584
2585                 pNetResource->lpLocalName = StringZone;
2586                 *StringZone++ = towupper(pConnectionCB->LocalName);
2587                 *StringZone++ = L':';
2588                 *StringZone++ = L'\0';
2589             }
2590             else
2591             {
2592
2593                 pNetResource->lpLocalName = NULL;
2594             }
2595
2596 #ifdef AFS_DEBUG_TRACE
2597             AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2598                          &uniRemoteName);
2599 #endif
2600
2601             // copy remote name
2602             pNetResource->lpRemoteName = StringZone;
2603
2604             CopyMemory( StringZone,
2605                         pConnectionCB->RemoteName,
2606                         pConnectionCB->RemoteNameLength);
2607
2608             StringZone += (pConnectionCB->RemoteNameLength / sizeof(WCHAR));
2609
2610             *StringZone++ = L'\0';
2611
2612             // copy comment
2613             if( pConnectionCB->CommentLength > 0)
2614             {
2615
2616                 pNetResource->lpComment = StringZone;
2617
2618                 CopyMemory( StringZone,
2619                             (void *)((char *)pConnectionCB + pConnectionCB->CommentOffset),
2620                             pConnectionCB->CommentLength);
2621
2622                 StringZone += (pConnectionCB->CommentLength / sizeof(WCHAR));
2623
2624                 *StringZone++ = L'\0';
2625             }
2626             else
2627             {
2628
2629                 pNetResource->lpComment = NULL;
2630             }
2631
2632             // copy provider name
2633             pNetResource->lpProvider = StringZone;
2634             StringCbCopy( StringZone,
2635                           cbProviderNameLength + sizeof( WCHAR),
2636                           wszProviderName);
2637
2638             StringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
2639
2640 #ifdef AFS_DEBUG_TRACE
2641             AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2642                          pNetResource,
2643                          GetScopeString(pNetResource->dwScope),
2644                          GetTypeString(pNetResource->dwType),
2645                          GetDisplayString(pNetResource->dwDisplayType),
2646                          GetUsageString(pNetResource->dwUsage),
2647                          pNetResource->lpLocalName,
2648                          pNetResource->lpRemoteName,
2649                          pNetResource->lpComment);
2650 #endif
2651
2652             // setup the new end of buffer
2653             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2654
2655             EntriesCopied++;
2656
2657             pNetResource++;
2658
2659             dwIndex++;
2660
2661             dwCopyBytes -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2662                            pConnectionCB->RemoteNameLength +
2663                            pConnectionCB->CommentLength;
2664
2665             if( dwCopyBytes == 0)
2666             {
2667
2668                 dwStatus = WN_SUCCESS;
2669
2670                 break;
2671             }
2672
2673             pConnectionCB = (AFSNetworkProviderConnectionCB *)((char *)pConnectionCB +
2674                             FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2675                             pConnectionCB->RemoteNameLength +
2676                             pConnectionCB->CommentLength);
2677         }
2678
2679         *lpcCount = EntriesCopied;
2680
2681         // update entry index
2682         pEnumCB->CurrentIndex = dwIndex;
2683
2684 #ifdef AFS_DEBUG_TRACE
2685         AFSDbgPrint( L"NPEnumResource Completed Count %d Index %d\n",
2686                      EntriesCopied,
2687                      dwIndex);
2688 #endif
2689
2690 try_exit:
2691
2692         if ( hControlDevice != NULL)
2693         {
2694
2695             CloseHandle( hControlDevice);
2696         }
2697
2698         if( pConnectionCBBase != NULL)
2699         {
2700
2701             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectionCBBase);
2702         }
2703     }
2704
2705     return dwStatus;
2706 }
2707
2708 /*++
2709
2710 Routine Description:
2711
2712     This routine closes the handle for enumeration of resources.
2713
2714 Arguments:
2715
2716     hEnum  - the enumeration handle
2717
2718 Return Value:
2719
2720     WN_SUCCESS if successful, otherwise the appropriate error
2721
2722 Notes:
2723
2724     The sample only supports the notion of enumerating connected shares
2725
2726 --*/
2727
2728 DWORD APIENTRY
2729 NPCloseEnum( HANDLE hEnum )
2730 {
2731
2732     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2733
2734 #ifdef AFS_DEBUG_TRACE
2735     AFSDbgPrint( L"NPCloseEnum\n");
2736 #endif
2737
2738     if( pEnumCB->RemoteName != NULL)
2739     {
2740
2741         HeapFree( GetProcessHeap( ), 0, (PVOID) pEnumCB->RemoteName);
2742     }
2743
2744     HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum );
2745
2746     return WN_SUCCESS;
2747 }
2748
2749 DWORD APIENTRY
2750 NPGetResourceParent( LPNETRESOURCE   lpNetResource,
2751                      LPVOID  lpBuffer,
2752                      LPDWORD lpBufferSize )
2753 {
2754
2755     DWORD    dwStatus = WN_ACCESS_DENIED;
2756     WCHAR   *pwchRemoteName = NULL, *pwchSearch = NULL, *pwchSystem = NULL;
2757     LPNETRESOURCE lpOutResource = (LPNETRESOURCE) lpBuffer;
2758
2759     if ( NPIsFSDisabled())
2760     {
2761
2762 #ifdef AFS_DEBUG_TRACE
2763         AFSDbgPrint( L"NPGetResourceParent AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
2764 #endif
2765
2766         return WN_BAD_NETNAME;
2767     }
2768
2769     if ( lpNetResource == NULL)
2770     {
2771 #ifdef AFS_DEBUG_TRACE
2772         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2773 #endif
2774         return WN_MORE_DATA;
2775     }
2776
2777     if( lpNetResource->lpRemoteName == NULL)
2778     {
2779 #ifdef AFS_DEBUG_TRACE
2780         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2781 #endif
2782         return WN_BAD_NETNAME;
2783     }
2784
2785     if ( lpNetResource->dwType != 0 &&
2786          lpNetResource->dwType != RESOURCETYPE_DISK)
2787     {
2788 #ifdef AFS_DEBUG_TRACE
2789         AFSDbgPrint( L"NPGetResourceParent Bad dwType\n");
2790 #endif
2791         return WN_BAD_VALUE;
2792     }
2793
2794     if ( lpBufferSize == NULL )
2795     {
2796
2797 #ifdef AFS_DEBUG_TRACE
2798         AFSDbgPrint( L"NPGetResourceParent Null lpBufferSize\n");
2799 #endif
2800         return WN_BAD_VALUE;
2801     }
2802
2803 #ifdef AFS_DEBUG_TRACE
2804     AFSDbgPrint( L"NPGetResourceParent For remote name %s\n",
2805                  lpNetResource->lpRemoteName);
2806 #endif
2807
2808     pwchRemoteName = lpNetResource->lpRemoteName;
2809
2810     //
2811     // The input will be of the form \\AFS\CELL\path.
2812     // \\AFS has no parent and by definition returns an empty NETRESOURCE.
2813     //
2814
2815     pwchSearch = pwchRemoteName + (wcslen( pwchRemoteName) - 1);
2816
2817     while( pwchSearch != pwchRemoteName)
2818     {
2819
2820         if( *pwchSearch == L'\\')
2821         {
2822
2823             *pwchSearch = L'\0';
2824
2825             break;
2826         }
2827
2828         pwchSearch--;
2829     }
2830
2831     if( pwchSearch != pwchRemoteName &&
2832         pwchSearch != pwchRemoteName + 1)
2833     {
2834
2835 #ifdef AFS_DEBUG_TRACE
2836         AFSDbgPrint( L"NPGetResourceParent Processing parent %s\n",
2837                      lpNetResource->lpRemoteName);
2838 #endif
2839
2840         dwStatus = NPGetResourceInformation( lpNetResource,
2841                                              lpBuffer,
2842                                              lpBufferSize,
2843                                              &pwchSystem);
2844     }
2845     else
2846     {
2847         if ( lpOutResource == NULL ||
2848              *lpBufferSize < sizeof( NETRESOURCE) )
2849         {
2850             *lpBufferSize = sizeof( NETRESOURCE);
2851
2852             return WN_MORE_DATA;
2853         }
2854
2855         memset( lpOutResource, 0, sizeof( NETRESOURCE));
2856
2857         return WN_SUCCESS;
2858
2859     }
2860
2861     return dwStatus;
2862 }
2863
2864 DWORD APIENTRY
2865 NPGetResourceInformation( LPNETRESOURCE   lpNetResource,
2866                           LPVOID  lpBuffer,
2867                           LPDWORD lpBufferSize,
2868                           LPWSTR  *lplpSystem )
2869 {
2870
2871     DWORD    dwStatus = WN_NOT_CONNECTED;
2872     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
2873     DWORD    dwError = 0;
2874     DWORD    dwBufferSize = 0;
2875     HANDLE   hControlDevice = NULL;
2876     NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
2877     PWCHAR   pStringZone = NULL;
2878     UNICODE_STRING uniRemoteName;
2879     DWORD    ulRequiredLen = 0;
2880     DWORD    dwPassedSize;
2881
2882
2883     __Enter
2884     {
2885         if ( lplpSystem)
2886         {
2887             *lplpSystem = NULL;
2888         }
2889
2890         ReadProviderNameString();
2891
2892         if ( NPIsFSDisabled())
2893         {
2894
2895 #ifdef AFS_DEBUG_TRACE
2896             AFSDbgPrint( L"NPGetResourceInformation AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
2897 #endif
2898
2899             try_return( dwStatus = WN_BAD_NETNAME);
2900         }
2901
2902         if ( lpNetResource == NULL ||
2903              lpBufferSize == NULL )
2904         {
2905
2906 #ifdef AFS_DEBUG_TRACE
2907             AFSDbgPrint( L"NPGetResourceInformaton Null lpNetResource or lpBufferSize\n");
2908 #endif
2909             return WN_BAD_VALUE;
2910         }
2911
2912         if( lpNetResource->lpRemoteName == NULL)
2913         {
2914 #ifdef AFS_DEBUG_TRACE
2915             AFSDbgPrint( L"NPGetResourceInformation No resource name\n");
2916 #endif
2917
2918             try_return( dwStatus = WN_NOT_CONNECTED);
2919         }
2920
2921         dwPassedSize = *lpBufferSize;
2922
2923         dwBufferSize = 0x1000;
2924
2925         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
2926
2927         if( pConnectCB == NULL)
2928         {
2929
2930             try_return( dwStatus = WN_OUT_OF_MEMORY);
2931         }
2932
2933         pConnectCB->RemoteNameLength = wcslen( lpNetResource->lpRemoteName) * sizeof( WCHAR);
2934
2935         StringCbCopy( pConnectCB->RemoteName,
2936                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
2937                       lpNetResource->lpRemoteName);
2938
2939         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
2940
2941         hControlDevice = OpenRedirector();
2942
2943         if( hControlDevice == NULL)
2944         {
2945
2946 #ifdef AFS_DEBUG_TRACE
2947             AFSDbgPrint( L"NPGetResourceInformation OpenRedirector failure, returning WN_NET_ERROR\n");
2948 #endif
2949
2950             try_return( dwStatus = WN_NET_ERROR);
2951         }
2952
2953         uniRemoteName.Length = (USHORT)pConnectCB->RemoteNameLength;
2954         uniRemoteName.MaximumLength = uniRemoteName.Length;
2955         uniRemoteName.Buffer = pConnectCB->RemoteName;
2956
2957 #ifdef AFS_DEBUG_TRACE
2958         AFSDbgPrint( L"NPGetResourceInformation For remote name %wZ Scope %08lX Type %08lX Usage %08lX\n",
2959                      &uniRemoteName,
2960                      pConnectCB->Scope,
2961                      pConnectCB->Type,
2962                      pConnectCB->Usage);
2963 #endif
2964
2965         dwError = DeviceIoControl( hControlDevice,
2966                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
2967                                    pConnectCB,
2968                                    dwBufferSize,
2969                                    pConnectCB,
2970                                    dwBufferSize,
2971                                    lpBufferSize,
2972                                    NULL);
2973
2974         if( !dwError)
2975         {
2976             dwStatus = GetLastError();
2977
2978 #ifdef AFS_DEBUG_TRACE
2979             AFSDbgPrint( L"NPGetResourceInformation Failed to get connection info from file system for local %s gle 0x%x\n",
2980                          lpNetResource->lpRemoteName, dwStatus);
2981 #endif
2982
2983             try_return( dwStatus);
2984         }
2985
2986         // Determine the space needed for this entry...
2987
2988         ulRequiredLen = sizeof( NETRESOURCE);
2989
2990         ulRequiredLen += pConnectCB->RemoteNameLength + sizeof( WCHAR);
2991
2992         ulRequiredLen += pConnectCB->CommentLength + sizeof( WCHAR);
2993
2994         ulRequiredLen += cbProviderNameLength + sizeof( WCHAR);
2995
2996         ulRequiredLen += pConnectCB->RemainingPathLength + sizeof( WCHAR);
2997
2998         if( pNetResource == NULL ||
2999             ulRequiredLen > dwPassedSize)
3000         {
3001
3002             *lpBufferSize = ulRequiredLen;
3003
3004             try_return( dwStatus = WN_MORE_DATA);
3005         }
3006
3007         pStringZone = (PWCHAR) ((char *)lpBuffer + sizeof( NETRESOURCE));
3008
3009         pNetResource->dwScope       = 0 /* pConnectCB->Scope*/;
3010         pNetResource->dwType        = 0 /* pConnectCB->Type */;
3011
3012         pNetResource->dwDisplayType = pConnectCB->DisplayType;
3013
3014         pNetResource->dwUsage       = pConnectCB->Usage;
3015
3016         pNetResource->lpLocalName = NULL;
3017
3018         // copy remote name
3019         pNetResource->lpRemoteName = pStringZone;
3020
3021         CopyMemory( pStringZone,
3022                     pConnectCB->RemoteName,
3023                     pConnectCB->RemoteNameLength);
3024
3025         pStringZone += (pConnectCB->RemoteNameLength / sizeof(WCHAR));
3026
3027         *pStringZone++ = L'\0';
3028
3029         // copy comment
3030         pNetResource->lpComment = pStringZone;
3031
3032         CopyMemory( pStringZone,
3033                     (void *)((char *)pConnectCB + pConnectCB->CommentOffset),
3034                     pConnectCB->CommentLength);
3035
3036         pStringZone += (pConnectCB->CommentLength / sizeof(WCHAR));
3037
3038         *pStringZone++ = L'\0';
3039
3040         // copy remaining path
3041         if (pConnectCB->RemainingPathLength > 0)
3042         {
3043             *lplpSystem = pStringZone;
3044
3045             CopyMemory( pStringZone,
3046                         (void *)((char *)pConnectCB + pConnectCB->RemainingPathOffset),
3047                         pConnectCB->RemainingPathLength);
3048
3049             pStringZone += (pConnectCB->RemainingPathLength / sizeof(WCHAR));
3050
3051             *pStringZone++ = L'\0';
3052
3053 #ifdef AFS_DEBUG_TRACE
3054             AFSDbgPrint( L"NPGetResourceInformation For remote name %s returning remaining path %s\n",
3055                          pNetResource->lpRemoteName,
3056                          *lplpSystem);
3057 #endif
3058         }
3059
3060         // copy provider name
3061         pNetResource->lpProvider = pStringZone;
3062
3063         StringCbCopy( pStringZone,
3064                       cbProviderNameLength + sizeof( WCHAR),
3065                       wszProviderName);
3066
3067         pStringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
3068
3069         *lpBufferSize = ulRequiredLen;
3070
3071         dwStatus = WN_SUCCESS;
3072
3073 try_exit:
3074
3075         if ( hControlDevice != NULL)
3076         {
3077
3078             CloseHandle( hControlDevice);
3079         }
3080
3081         if( pConnectCB != NULL)
3082         {
3083
3084             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3085         }
3086     }
3087
3088     return dwStatus;
3089 }
3090
3091 static VOID
3092 SeparateRemainingPath( WCHAR * lpConnectionName, WCHAR **lppRemainingPath)
3093 {
3094     WCHAR *pwch;
3095     WCHAR wch1, wch2;
3096     DWORD  dwCount;
3097
3098     //
3099     // at this point the lpConnectionName contains the full name.  We need to
3100     // truncate it to \\server\share and move the remaining path back one position.
3101     //
3102
3103     for ( pwch = lpConnectionName, dwCount = 0; *pwch; pwch++)
3104     {
3105         if ( *pwch == L'\\')
3106         {
3107             dwCount++;
3108         }
3109
3110         if ( dwCount == 4)
3111         {
3112             break;
3113         }
3114     }
3115
3116     if (*pwch == L'\\')
3117     {
3118         //
3119         // Found the remaining path that must be moved
3120         //
3121
3122         *lppRemainingPath = pwch + 1;
3123
3124         *pwch++ = 0;
3125
3126         //
3127         // Find the end
3128         //
3129         for ( ; *pwch; pwch++);
3130
3131         //
3132         // and work backwards moving the string
3133         // and then make sure that there is at least
3134         // a path separator.
3135         //
3136
3137         *(pwch + 1) = 0;
3138
3139         for ( ;pwch > *lppRemainingPath; pwch--)
3140         {
3141             *pwch = *(pwch - 1);
3142         }
3143
3144         *pwch = L'\\';
3145     }
3146 }
3147
3148 DWORD APIENTRY
3149 NPGetUniversalName( LPCWSTR lpLocalPath,
3150                     DWORD   dwInfoLevel,
3151                     LPVOID  lpBuffer,
3152                     LPDWORD lpBufferSize)
3153 {
3154
3155     DWORD dwBufferSize = *lpBufferSize;
3156     DWORD dwStatus;
3157
3158     dwStatus = NPGetUniversalNameCommon( lpLocalPath,
3159                                          dwInfoLevel,
3160                                          lpBuffer,
3161                                          &dwBufferSize,
3162                                          FALSE);
3163
3164     if ( dwStatus == WN_NOT_CONNECTED)
3165     {
3166
3167         dwStatus = NPGetUniversalNameCommon( lpLocalPath,
3168                                              dwInfoLevel,
3169                                              lpBuffer,
3170                                              lpBufferSize,
3171                                              TRUE);
3172     }
3173     else
3174     {
3175
3176         *lpBufferSize = dwBufferSize;
3177     }
3178
3179     return dwStatus;
3180 }
3181
3182 static DWORD APIENTRY
3183 NPGetUniversalNameCommon( LPCWSTR lpLocalPath,
3184                           DWORD   dwInfoLevel,
3185                           LPVOID  lpBuffer,
3186                           LPDWORD lpBufferSize,
3187                           BOOL    bDriveSubstOk)
3188 {
3189     DWORD    dwStatus = WN_NOT_CONNECTED;
3190     WCHAR    wchLocalName[3];
3191     WCHAR   *pwchSubstName = NULL;
3192     DWORD    dwSubstNameLength = 0;
3193     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3194     DWORD    dwError = 0;
3195     DWORD    dwBufferSize = 0;
3196     DWORD    dwPassedSize = *lpBufferSize;
3197     DWORD    dwRemainingLength = *lpBufferSize;
3198     HANDLE   hControlDevice = NULL;
3199     DWORD    dwLocalPathLength = 0;
3200     DWORD    dwRemainingPathLength = 0;
3201     CHAR    *pch;
3202
3203     __Enter
3204     {
3205
3206 #ifdef AFS_DEBUG_TRACE
3207         AFSDbgPrint( L"NPGetUniversalName local path %s level 0x%X\n",
3208                      lpLocalPath ? lpLocalPath : L"(Null)",
3209                      dwInfoLevel);
3210 #endif
3211
3212         if ( NPIsFSDisabled())
3213         {
3214
3215 #ifdef AFS_DEBUG_TRACE
3216             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
3217 #endif
3218
3219             try_return( dwStatus = WN_NOT_CONNECTED);
3220         }
3221
3222         dwLocalPathLength = lstrlen( lpLocalPath);
3223
3224         dwRemainingPathLength = dwLocalPathLength - 2;          // no drive letter
3225
3226         if( dwLocalPathLength == 0)
3227         {
3228
3229 #ifdef AFS_DEBUG_TRACE
3230             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_BAD_LOCALNAME\n");
3231 #endif
3232
3233             try_return( dwStatus = WN_BAD_LOCALNAME);
3234         }
3235
3236         if( lpBuffer == NULL ||
3237             lpBufferSize == NULL)
3238         {
3239 #ifdef AFS_DEBUG_TRACE
3240             AFSDbgPrint( L"NPGetUniversalName No output buffer or size\n");
3241 #endif
3242             try_return( dwStatus = WN_BAD_VALUE);
3243         }
3244
3245         dwSubstNameLength = 4096;
3246
3247         pwchSubstName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSubstNameLength);
3248
3249         if ( pwchSubstName == NULL)
3250         {
3251 #ifdef AFS_DEBUG_TRACE
3252             AFSDbgPrint( L"NPGetUniversalName unable to allocate substitution name buffer.\n");
3253 #endif
3254             try_return( dwStatus = WN_OUT_OF_MEMORY);
3255         }
3256
3257         memset(lpBuffer, 0, dwPassedSize);
3258
3259         if ( !bDriveSubstOk ||
3260              !DriveSubstitution( lpLocalPath, pwchSubstName, dwSubstNameLength, &dwStatus))
3261         {
3262             wchLocalName[0] = towupper(lpLocalPath[0]);
3263             wchLocalName[1] = L':';
3264             wchLocalName[2] = L'\0';
3265
3266 #ifdef AFS_DEBUG_TRACE
3267             AFSDbgPrint( L"NPGetUniversalName Requesting UNC for %s level 0x%X\n",
3268                          wchLocalName,
3269                          dwInfoLevel);
3270 #endif
3271         }
3272         else
3273         {
3274
3275             ReadServerNameString();
3276
3277             if ( pwchSubstName[0] != L'\\' &&
3278                  pwchSubstName[1] == L':')
3279             {
3280
3281                 wchLocalName[0] = towupper(pwchSubstName[0]);
3282                 wchLocalName[1] = L':';
3283                 wchLocalName[2] = L'\0';
3284
3285 #ifdef AFS_DEBUG_TRACE
3286                 AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n",
3287                              pwchSubstName,
3288                              wchLocalName);
3289 #endif
3290             }
3291             else if ( _wcsnicmp( pwchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
3292                       ( pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
3293                         pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
3294             {
3295                 HRESULT hr;
3296
3297 #ifdef AFS_DEBUG_TRACE
3298                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n",
3299                              pwchSubstName,
3300                              dwInfoLevel,
3301                              dwPassedSize);
3302 #endif
3303
3304                 dwBufferSize = (wcslen( pwchSubstName) + 1) * sizeof( WCHAR);
3305
3306                 switch( dwInfoLevel)
3307                 {
3308
3309                 case UNIVERSAL_NAME_INFO_LEVEL:
3310                 {
3311
3312                     UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3313
3314                     *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize;
3315
3316                     if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3317                     {
3318
3319 #ifdef AFS_DEBUG_TRACE
3320                         AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3321 #endif
3322
3323                         try_return( dwStatus = WN_MORE_DATA);
3324                     }
3325
3326                     dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3327
3328                     pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3329
3330                     memcpy( pUniversalInfo->lpUniversalName,
3331                             pwchSubstName,
3332                             min( dwBufferSize, dwRemainingLength));
3333
3334                     dwRemainingLength -= min( dwBufferSize, dwRemainingLength);
3335
3336 #ifdef AFS_DEBUG_TRACE
3337                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3338                                  lpBuffer,
3339                                  pUniversalInfo->lpUniversalName,
3340                                  pUniversalInfo->lpUniversalName);
3341 #endif
3342
3343                     if ( dwPassedSize < *lpBufferSize)
3344                     {
3345
3346                         try_return( dwStatus = WN_MORE_DATA);
3347                     }
3348
3349                     try_return( dwStatus = WN_SUCCESS);
3350                 }
3351
3352                 case REMOTE_NAME_INFO_LEVEL:
3353                 {
3354
3355                     REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3356
3357                     *lpBufferSize = sizeof( REMOTE_NAME_INFO) + 2 * dwBufferSize + sizeof( WCHAR);
3358
3359                     if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3360                     {
3361
3362 #ifdef AFS_DEBUG_TRACE
3363                         AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3364 #endif
3365
3366                         try_return( dwStatus = WN_MORE_DATA);
3367                     }
3368
3369                     dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3370
3371                     pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3372
3373                     memcpy( pRemoteInfo->lpUniversalName,
3374                             pwchSubstName,
3375                             min( dwRemainingLength, dwBufferSize));
3376
3377                     dwRemainingLength -= min( dwRemainingLength, dwBufferSize);
3378
3379 #ifdef AFS_DEBUG_TRACE
3380                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3381                                  lpBuffer,
3382                                  pRemoteInfo->lpUniversalName,
3383                                  pRemoteInfo->lpUniversalName);
3384 #endif
3385
3386                     if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3387                     {
3388                         pRemoteInfo->lpConnectionName = (LPTSTR)((char *)pRemoteInfo->lpUniversalName + dwBufferSize);
3389
3390                         memcpy( pRemoteInfo->lpConnectionName,
3391                                 pwchSubstName,
3392                                 min( dwRemainingLength, dwBufferSize));
3393
3394                         dwRemainingLength -= min( dwRemainingLength, dwBufferSize) - sizeof( WCHAR);
3395
3396                         SeparateRemainingPath( pRemoteInfo->lpConnectionName,
3397                                                &pRemoteInfo->lpRemainingPath);
3398                     }
3399
3400 #ifdef AFS_DEBUG_TRACE
3401                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3402                                  lpBuffer,
3403                                  pRemoteInfo->lpConnectionName,
3404                                  pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3405
3406                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3407                                  lpBuffer,
3408                                  pRemoteInfo->lpRemainingPath,
3409                                  pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3410 #endif
3411
3412                     if ( dwPassedSize < *lpBufferSize)
3413                     {
3414
3415                         try_return( dwStatus = WN_MORE_DATA);
3416                     }
3417
3418                     try_return( dwStatus = WN_SUCCESS);
3419                 }
3420
3421                 default:
3422 #ifdef AFS_DEBUG_TRACE
3423                     AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3424                                  dwInfoLevel);
3425 #endif
3426                     try_return( dwStatus = WN_BAD_VALUE);
3427                 }
3428             }
3429             else
3430             {
3431
3432 #ifdef AFS_DEBUG_TRACE
3433                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is not AFS\n",
3434                              pwchSubstName);
3435 #endif
3436                 try_return( dwStatus = WN_NOT_CONNECTED);
3437             }
3438         }
3439
3440         dwBufferSize = 0x1000;
3441
3442         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
3443
3444         if( pConnectCB == NULL)
3445         {
3446             try_return( dwStatus = WN_OUT_OF_MEMORY);
3447         }
3448
3449         pConnectCB->LocalName = towupper(wchLocalName[0]);
3450
3451         pConnectCB->RemoteNameLength = 0;
3452
3453         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
3454
3455         hControlDevice = OpenRedirector();
3456
3457         if( hControlDevice == NULL)
3458         {
3459
3460             try_return( dwStatus = WN_NET_ERROR);
3461         }
3462
3463         dwError = DeviceIoControl( hControlDevice,
3464                                    IOCTL_AFS_GET_CONNECTION,
3465                                    pConnectCB,
3466                                    dwBufferSize,
3467                                    pConnectCB,
3468                                    dwBufferSize,
3469                                    &dwBufferSize,
3470                                    NULL);
3471
3472         if( !dwError)
3473         {
3474 #ifdef AFS_DEBUG_TRACE
3475             DWORD gle = GetLastError();
3476
3477             AFSDbgPrint( L"NPGetUniversalName Failed to get connection from file system for local %s gle 0x%x\n",
3478                          wchLocalName, gle);
3479 #endif
3480             try_return( dwStatus = WN_NOT_CONNECTED);
3481         }
3482
3483         switch( dwInfoLevel)
3484         {
3485
3486             case UNIVERSAL_NAME_INFO_LEVEL:
3487             {
3488
3489                 UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3490
3491                 *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize + sizeof( WCHAR);
3492
3493                 *lpBufferSize += dwRemainingPathLength * sizeof( WCHAR);
3494
3495                 if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3496                 {
3497
3498 #ifdef AFS_DEBUG_TRACE
3499                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3500 #endif
3501
3502                     try_return( dwStatus = WN_MORE_DATA);
3503                 }
3504
3505                 dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3506
3507                 pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3508
3509                 pch = (char *)pUniversalInfo->lpUniversalName;
3510
3511                 memcpy( pch,
3512                         pConnectCB,
3513                         min( dwBufferSize, dwRemainingLength));
3514
3515                 pch += min( dwBufferSize, dwRemainingLength);
3516
3517                 dwRemainingLength -= min( dwBufferSize + sizeof(WCHAR), dwRemainingLength);
3518
3519                 memcpy( pch,
3520                         &lpLocalPath[2],
3521                         min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength));
3522
3523                 pch += min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength);
3524
3525                 dwRemainingLength -= min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength);
3526
3527 #ifdef AFS_DEBUG_TRACE
3528                 AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3529                              lpBuffer,
3530                              pUniversalInfo->lpUniversalName,
3531                              pUniversalInfo->lpUniversalName);
3532 #endif
3533
3534                 if ( dwPassedSize < *lpBufferSize)
3535                 {
3536
3537                     try_return( dwStatus = WN_MORE_DATA);
3538                 }
3539
3540                 try_return( dwStatus = WN_SUCCESS);
3541             }
3542
3543             case REMOTE_NAME_INFO_LEVEL:
3544             {
3545
3546                 REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3547
3548                 *lpBufferSize = sizeof( REMOTE_NAME_INFO) + (2 * dwBufferSize + sizeof( WCHAR)) + 2 * sizeof( WCHAR);
3549
3550                 *lpBufferSize += 2 * dwRemainingPathLength * sizeof( WCHAR);
3551
3552                 if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3553                 {
3554
3555 #ifdef AFS_DEBUG_TRACE
3556                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3557 #endif
3558
3559                     try_return( dwStatus = WN_MORE_DATA);
3560                 }
3561
3562                 dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3563
3564                 pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3565
3566                 pch = (char *)pRemoteInfo->lpUniversalName;
3567
3568                 memcpy( pch,
3569                         pConnectCB,
3570                         min( dwBufferSize, dwRemainingLength));
3571
3572                 pch += min( dwBufferSize, dwRemainingLength);
3573
3574                 dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3575
3576                 memcpy( pch,
3577                         &lpLocalPath[2],
3578                         min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength));
3579
3580                 pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3581
3582                 dwRemainingLength -= min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3583
3584 #ifdef AFS_DEBUG_TRACE
3585                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3586                              lpBuffer,
3587                              pRemoteInfo->lpUniversalName,
3588                              pRemoteInfo->lpUniversalName);
3589 #endif
3590
3591                 if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3592                 {
3593                     pRemoteInfo->lpConnectionName = (LPWSTR)pch;
3594
3595                     memcpy( pch,
3596                             pConnectCB,
3597                             min( dwBufferSize, dwRemainingLength));
3598
3599                     pch += min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3600
3601                     dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3602                 }
3603
3604
3605                 if ( dwRemainingLength > dwRemainingPathLength + sizeof( WCHAR))
3606                 {
3607                     pRemoteInfo->lpRemainingPath = (LPWSTR)pch;
3608
3609                     memcpy( pch,
3610                             &lpLocalPath[2],
3611                             min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength));
3612
3613                     pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3614
3615                     dwRemainingLength -= min((dwLocalPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3616                 }
3617
3618 #ifdef AFS_DEBUG_TRACE
3619                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3620                              lpBuffer,
3621                              pRemoteInfo->lpConnectionName,
3622                              pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3623
3624                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3625                              lpBuffer,
3626                              pRemoteInfo->lpRemainingPath,
3627                              pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3628 #endif
3629
3630                 if ( dwPassedSize < *lpBufferSize)
3631                 {
3632
3633                     try_return( dwStatus = WN_MORE_DATA);
3634                 }
3635
3636                 try_return( dwStatus = WN_SUCCESS);
3637             }
3638
3639             default:
3640 #ifdef AFS_DEBUG_TRACE
3641                 AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3642                              dwInfoLevel);
3643 #endif
3644                 try_return( dwStatus = WN_BAD_VALUE);
3645         }
3646
3647 try_exit:
3648
3649 #ifdef AFS_DEBUG_TRACE
3650         AFSDbgPrint( L"NPGetUniversalName BufferSize 0x%X\n",
3651                      *lpBufferSize);
3652 #endif
3653         if ( hControlDevice != NULL)
3654         {
3655
3656             CloseHandle( hControlDevice);
3657         }
3658
3659         if ( pwchSubstName)
3660         {
3661
3662             HeapFree( GetProcessHeap(), 0, (PVOID) pwchSubstName);
3663         }
3664
3665         if( pConnectCB != NULL)
3666         {
3667
3668             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3669         }
3670     }
3671
3672     return dwStatus;
3673 }
3674
3675
3676 static LPCWSTR
3677 GetFormatFlags( DWORD dwFlags)
3678 {
3679     static WCHAR Buffer[128] = L"";
3680
3681     //
3682     // WNFMT_MULTILINE         0x01
3683     // WNFMT_ABBREVIATED       0x02
3684     // WNFMT_INENUM            0x10
3685     // WNFMT_CONNECTION        0x20
3686     //
3687
3688     Buffer[0] = L'\0';
3689
3690     if ( dwFlags == 0)
3691     {
3692         return L"NONE";
3693     }
3694
3695     if ( dwFlags & WNFMT_MULTILINE )
3696     {
3697         StringCbCat( Buffer, sizeof(Buffer), L"MULTILINE|");
3698     }
3699
3700     if ( dwFlags & WNFMT_INENUM )
3701     {
3702         StringCbCat( Buffer, sizeof(Buffer), L"ABBREVIATED|");
3703     }
3704
3705     if ( dwFlags & WNFMT_INENUM )
3706     {
3707         StringCbCat( Buffer, sizeof(Buffer), L"INENUM|");
3708     }
3709
3710     if ( dwFlags & WNFMT_CONNECTION )
3711     {
3712         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTION|");
3713     }
3714
3715     if ( dwFlags & ~(WNFMT_MULTILINE|WNFMT_ABBREVIATED|WNFMT_INENUM|WNFMT_CONNECTION) )
3716     {
3717         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
3718     }
3719
3720     Buffer[lstrlen(Buffer)-1] = L'\0';
3721
3722     return Buffer;
3723 }
3724
3725 DWORD
3726 NPFormatNetworkName( LPTSTR  lpRemoteName,
3727                      LPTSTR  lpFormattedName,
3728                      LPDWORD lpnLength,
3729                      DWORD dwFlags,
3730                      DWORD dwAveCharPerLine)
3731 {
3732
3733     DWORD dwLen = 0, dwCurrentLen = 0;
3734     LPTSTR pCurrentName = lpRemoteName;
3735
3736 #ifdef AFS_DEBUG_TRACE
3737     AFSDbgPrint( L"NPFormatNetworkName Remote %s Flags %s (0x%x) CharsPerLine %u\n",
3738                  lpRemoteName,
3739                  GetFormatFlags( dwFlags),
3740                  dwFlags,
3741                  dwAveCharPerLine);
3742 #endif
3743
3744
3745     //
3746     // Walk back in the name until we hit a \
3747     //
3748
3749     dwLen = wcslen( lpRemoteName);
3750
3751     pCurrentName += (dwLen - 1);
3752
3753     if ( pCurrentName[ 0] != L'\\')
3754     {
3755
3756         while( dwLen > 0)
3757         {
3758
3759             if( pCurrentName[ 0] == L'\\')
3760             {
3761
3762                 pCurrentName++;
3763
3764                 break;
3765             }
3766
3767             pCurrentName--;
3768
3769             dwLen--;
3770
3771             dwCurrentLen++;
3772         }
3773     }
3774
3775     if( *lpnLength  < dwCurrentLen * sizeof( WCHAR))
3776     {
3777
3778         *lpnLength = dwCurrentLen * sizeof( WCHAR);
3779
3780 #ifdef AFS_DEBUG_TRACE
3781         AFSDbgPrint( L"NPFormatNetworkName remote name %s WN_MORE_DATA\n",
3782                      lpRemoteName);
3783 #endif
3784
3785         return WN_MORE_DATA;
3786     }
3787
3788     StringCbCopy( lpFormattedName,
3789                   *lpnLength,
3790                   pCurrentName);
3791
3792     *lpnLength = dwCurrentLen * sizeof( WCHAR);
3793
3794 #ifdef AFS_DEBUG_TRACE
3795     AFSDbgPrint( L"NPFormatNetworkName remote name %s as %s\n",
3796                  lpRemoteName,
3797                  lpFormattedName);
3798 #endif
3799
3800     return WN_SUCCESS;
3801 }
3802
3803 /************************************************************
3804 /       Unsupported entry points
3805 /************************************************************/
3806
3807 //
3808 // AuthGroup processing is implemented in src/WINNT/afsd/afslogon.c
3809 //
3810 DWORD APIENTRY
3811 NPLogonNotify(
3812     PLUID   lpLogonId,
3813     LPCWSTR lpAuthentInfoType,
3814     LPVOID  lpAuthentInfo,
3815     LPCWSTR lpPreviousAuthentInfoType,
3816     LPVOID  lpPreviousAuthentInfo,
3817     LPWSTR  lpStationName,
3818     LPVOID  StationHandle,
3819     LPWSTR  *lpLogonScript)
3820 {
3821
3822 #ifdef AFS_DEBUG_TRACE
3823     AFSDbgPrint( L"NPLogonNotify, returning WN_NOT_SUPPORTED\n");
3824 #endif
3825
3826     return WN_NOT_SUPPORTED;
3827 }
3828
3829 DWORD APIENTRY
3830 NPPasswordChangeNotify (
3831     LPCWSTR    lpAuthentInfoType,
3832     LPVOID    lpAuthentInfo,
3833     LPCWSTR    lpPreviousAuthentInfoType,
3834     LPVOID    lpPreviousAuthentInfo,
3835     LPWSTR    lpStationName,
3836     LPVOID    StationHandle,
3837     DWORD    dwChangeInfo )
3838 {
3839
3840 #ifdef AFS_DEBUG_TRACE
3841     AFSDbgPrint( L"NPPasswordChangeNotify, returning WN_NOT_SUPPORTED\n");
3842 #endif
3843
3844     SetLastError( WN_NOT_SUPPORTED );
3845
3846     return WN_NOT_SUPPORTED;
3847 }
3848
3849 DWORD APIENTRY
3850 NPGetUser( LPTSTR lpName,
3851            LPTSTR lpUserName,
3852            LPDWORD lpBufferSize)
3853 {
3854
3855     DWORD rc = WN_NOT_SUPPORTED;
3856
3857     AFSDbgPrint( L"NPGetUser Entry Name %s\n", lpName);
3858
3859     return rc;
3860 }
3861
3862
3863 DWORD
3864 APIENTRY
3865 NPGetReconnectFlags( LPWSTR  lpRemoteName,
3866                      unsigned char *Parameter2)
3867 {
3868
3869     DWORD    dwStatus = WN_NOT_SUPPORTED;
3870
3871     AFSDbgPrint( L"NPGetReconnectFlags RemoteName %s\n",
3872                  lpRemoteName);
3873
3874     return dwStatus;
3875 }
3876
3877
3878 DWORD
3879 APIENTRY
3880 I_SystemFocusDialog( VOID)
3881 {
3882
3883     DWORD    dwStatus = WN_NOT_SUPPORTED;
3884
3885     AFSDbgPrint( L"I_SystemFocusDialog\n");
3886
3887     return dwStatus;
3888 }
3889
3890 /************************************************************
3891 /       END Unsupported entry points
3892 /************************************************************/
3893
3894
3895 HANDLE
3896 OpenRedirector()
3897 {
3898
3899     HANDLE hControlDevice = NULL;
3900
3901     hControlDevice = CreateFile( AFS_SYMLINK_W,
3902                                  GENERIC_READ | GENERIC_WRITE,
3903                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
3904                                  NULL,
3905                                  OPEN_EXISTING,
3906                                  0,
3907                                  NULL );
3908
3909     if( hControlDevice == INVALID_HANDLE_VALUE)
3910     {
3911
3912         hControlDevice = NULL;
3913 #ifdef AFS_DEBUG_TRACE
3914         AFSDbgPrint( L"Failed to open control device error: %d\n",
3915                      GetLastError());
3916 #endif
3917     }
3918
3919     return hControlDevice;
3920 }
3921
3922 static DWORD
3923 Debug(void)
3924 {
3925     static int init = 0;
3926     static DWORD debug = 0;
3927
3928     if ( !init ) {
3929         HKEY hk;
3930
3931         if (RegOpenKey (HKEY_LOCAL_MACHINE,
3932                          TEXT("SYSTEM\\CurrentControlSet\\Services\\AFSRedirector\\NetworkProvider"), &hk) == 0)
3933         {
3934             DWORD dwSize = sizeof(BOOL);
3935             DWORD dwType = REG_DWORD;
3936             RegQueryValueEx (hk, TEXT("Debug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
3937             RegCloseKey (hk);
3938         }
3939         init = 1;
3940     }
3941
3942     return debug;
3943 }
3944
3945 static char *
3946 cm_Utf16ToUtf8Alloc(const WCHAR * s, int cch_src, int *pcch_dest)
3947 {
3948     int cch_dest;
3949     char * dest;
3950
3951     if (s == NULL || cch_src == 0 || *s == L'\0') {
3952         if (pcch_dest)
3953             *pcch_dest = ((cch_src != 0)?1:0);
3954         return NULL;
3955     }
3956
3957     cch_dest = WideCharToMultiByte(CP_UTF8, 0, s, cch_src, NULL, 0, NULL, FALSE);
3958
3959     if (cch_dest == 0) {
3960         if (pcch_dest)
3961             *pcch_dest = cch_dest;
3962         return NULL;
3963     }
3964
3965     dest = HeapAlloc( GetProcessHeap(), 0, (cch_dest + 1) * sizeof(char));
3966
3967     WideCharToMultiByte(CP_UTF8, 0, s, cch_src, dest, cch_dest, NULL, FALSE);
3968     dest[cch_dest] = 0;
3969
3970     if (pcch_dest)
3971         *pcch_dest = cch_dest;
3972
3973     return dest;
3974 }
3975
3976 static void
3977 AppendDebugStringToLogFile(WCHAR *wszbuffer)
3978 {
3979     HANDLE hFile;
3980     int len;
3981     char * buffer;
3982     DWORD dwWritten;
3983     BOOL bRet;
3984
3985     if ( !wszbuffer || !wszbuffer[0] )
3986         return;
3987
3988     len = (int)wcslen(wszbuffer);
3989
3990     buffer = cm_Utf16ToUtf8Alloc(wszbuffer, len, &len);
3991
3992     if (!buffer)
3993         return;
3994
3995     hFile = CreateFileW( L"C:\\TEMP\\AFSRDFSProvider.log",
3996                          FILE_APPEND_DATA,
3997                          FILE_SHARE_WRITE,
3998                          NULL,
3999                          OPEN_ALWAYS,
4000                          FILE_ATTRIBUTE_NORMAL,
4001                          NULL);
4002
4003     if ( hFile == INVALID_HANDLE_VALUE ) {
4004         OutputDebugString(L"C:\\AFSRDFSProvider.log cannot be opened.\n");
4005         return;
4006     }
4007
4008     bRet = WriteFile( hFile, buffer, len, &dwWritten, NULL);
4009
4010     bRet = CloseHandle(hFile);
4011
4012     HeapFree(GetProcessHeap(), 0, buffer);
4013 }
4014
4015 ULONG
4016 _cdecl
4017 AFSDbgPrint(
4018     PWCHAR Format,
4019     ...
4020     )
4021 {
4022     HRESULT rc = S_OK;
4023     WCHAR wszbuffer[512];
4024     va_list marker;
4025     DWORD debug = Debug();
4026
4027     if (debug == 0)
4028         return 0;
4029
4030     va_start( marker, Format );
4031     {
4032         StringCbPrintf( wszbuffer, sizeof(wszbuffer), L"[%d-%08X] ",
4033 #ifdef AMD64
4034                            64,
4035 #else
4036                            32,
4037 #endif
4038                            GetCurrentThreadId());
4039
4040         rc = StringCbVPrintfW( &wszbuffer[ 14], sizeof(wszbuffer) - 14 * sizeof(WCHAR), Format, marker);
4041
4042         if (SUCCEEDED(rc)) {
4043             if (debug & 1)
4044                 OutputDebugString( wszbuffer );
4045             if (debug & 2)
4046                 AppendDebugStringToLogFile(wszbuffer);
4047         } else {
4048             OutputDebugString(L"AFSDbgPrint Failed to create string\n");
4049         }
4050     }
4051     return SUCCEEDED(rc) ? 1 : 0;
4052 }