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