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