Windows: NPAddConnection3 debugging
[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 ( lpNetResource == NULL)
3012     {
3013 #ifdef AFS_DEBUG_TRACE
3014         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
3015 #endif
3016         return WN_MORE_DATA;
3017     }
3018
3019     if( lpNetResource->lpRemoteName == NULL)
3020     {
3021 #ifdef AFS_DEBUG_TRACE
3022         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
3023 #endif
3024         return WN_BAD_NETNAME;
3025     }
3026
3027     if ( lpNetResource->dwType != 0 &&
3028          lpNetResource->dwType != RESOURCETYPE_DISK)
3029     {
3030 #ifdef AFS_DEBUG_TRACE
3031         AFSDbgPrint( L"NPGetResourceParent Bad dwType\n");
3032 #endif
3033         return WN_BAD_VALUE;
3034     }
3035
3036     if ( lpBufferSize == NULL )
3037     {
3038
3039 #ifdef AFS_DEBUG_TRACE
3040         AFSDbgPrint( L"NPGetResourceParent Null lpBufferSize\n");
3041 #endif
3042         return WN_BAD_VALUE;
3043     }
3044
3045 #ifdef AFS_DEBUG_TRACE
3046     AFSDbgPrint( L"NPGetResourceParent For remote name %s\n",
3047                  lpNetResource->lpRemoteName);
3048 #endif
3049
3050     pwchRemoteName = lpNetResource->lpRemoteName;
3051
3052     pwchSearch = pwchRemoteName + (wcslen( pwchRemoteName) - 1);
3053
3054     while( pwchSearch != pwchRemoteName)
3055     {
3056
3057         if( *pwchSearch == L'\\')
3058         {
3059
3060             *pwchSearch = L'\0';
3061
3062             break;
3063         }
3064
3065         pwchSearch--;
3066     }
3067
3068     if( pwchSearch != pwchRemoteName)
3069     {
3070
3071 #ifdef AFS_DEBUG_TRACE
3072         AFSDbgPrint( L"NPGetResourceParent Processing parent %s\n",
3073                      lpNetResource->lpRemoteName);
3074 #endif
3075
3076         dwStatus = NPGetResourceInformation( lpNetResource,
3077                                              lpBuffer,
3078                                              lpBufferSize,
3079                                              &pwchSystem);
3080     }
3081     else
3082     {
3083         if ( lpOutResource == NULL ||
3084              *lpBufferSize < sizeof( NETRESOURCE) )
3085         {
3086             *lpBufferSize = sizeof( NETRESOURCE);
3087
3088             return WN_MORE_DATA;
3089         }
3090
3091         memset( lpOutResource, 0, sizeof( NETRESOURCE));
3092
3093         return WN_SUCCESS;
3094
3095     }
3096
3097     return dwStatus;
3098 }
3099
3100 DWORD APIENTRY
3101 NPGetResourceInformation( LPNETRESOURCE   lpNetResource,
3102                           LPVOID  lpBuffer,
3103                           LPDWORD lpBufferSize,
3104                           LPWSTR  *lplpSystem )
3105 {
3106
3107     DWORD    dwStatus = WN_NOT_CONNECTED;
3108     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3109     DWORD    dwError = 0;
3110     DWORD    dwBufferSize = 0;
3111     HANDLE   hControlDevice = NULL;
3112     NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
3113     PWCHAR   pStringZone = NULL;
3114     UNICODE_STRING uniRemoteName;
3115     DWORD    ulRequiredLen = 0;
3116     DWORD    dwPassedSize;
3117
3118
3119     __Enter
3120     {
3121         if ( lplpSystem)
3122         {
3123             *lplpSystem = NULL;
3124         }
3125
3126         ReadProviderNameString();
3127
3128         if ( NPIsFSDisabled())
3129         {
3130
3131 #ifdef AFS_DEBUG_TRACE
3132             AFSDbgPrint( L"NPGetResourceInformation AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
3133 #endif
3134
3135             try_return( dwStatus = WN_BAD_NETNAME);
3136         }
3137
3138         if ( lpNetResource == NULL ||
3139              lpBufferSize == NULL )
3140         {
3141
3142 #ifdef AFS_DEBUG_TRACE
3143             AFSDbgPrint( L"NPGetResourceInformaton Null lpNetResource or lpBufferSize\n");
3144 #endif
3145             return WN_BAD_VALUE;
3146         }
3147
3148         if( lpNetResource->lpRemoteName == NULL)
3149         {
3150 #ifdef AFS_DEBUG_TRACE
3151             AFSDbgPrint( L"NPGetResourceInformation No resource name\n");
3152 #endif
3153
3154             try_return( dwStatus = WN_NOT_CONNECTED);
3155         }
3156
3157         dwPassedSize = *lpBufferSize;
3158
3159         dwBufferSize = 0x1000;
3160
3161         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
3162
3163         if( pConnectCB == NULL)
3164         {
3165
3166             try_return( dwStatus = WN_OUT_OF_MEMORY);
3167         }
3168
3169         pConnectCB->RemoteNameLength = wcslen( lpNetResource->lpRemoteName) * sizeof( WCHAR);
3170
3171         StringCbCopy( pConnectCB->RemoteName,
3172                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
3173                       lpNetResource->lpRemoteName);
3174
3175         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
3176
3177         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
3178
3179 #ifdef AFS_DEBUG_TRACE
3180         AFSDbgPrint( L"NPGetResourceInformation Retrieved authentication id %08lX-%08lX\n",
3181                      pConnectCB->AuthenticationId.HighPart,
3182                      pConnectCB->AuthenticationId.LowPart);
3183 #endif
3184
3185         hControlDevice = OpenRedirector();
3186
3187         if( hControlDevice == NULL)
3188         {
3189
3190 #ifdef AFS_DEBUG_TRACE
3191             AFSDbgPrint( L"NPGetResourceInformation OpenRedirector failure, returning WN_NET_ERROR\n");
3192 #endif
3193
3194             try_return( dwStatus = WN_NET_ERROR);
3195         }
3196
3197         dwError = DeviceIoControl( hControlDevice,
3198                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
3199                                    pConnectCB,
3200                                    dwBufferSize,
3201                                    pConnectCB,
3202                                    dwBufferSize,
3203                                    lpBufferSize,
3204                                    NULL);
3205
3206         if( !dwError)
3207         {
3208 #ifdef AFS_DEBUG_TRACE
3209             DWORD gle = GetLastError();
3210
3211             AFSDbgPrint( L"NPGetResourceInformation Failed to get connection info from file system for local %s gle 0x%x\n",
3212                          lpNetResource->lpRemoteName, gle);
3213 #endif
3214             try_return( dwStatus = WN_BAD_NETNAME);
3215         }
3216
3217         uniRemoteName.Length = (USHORT)pConnectCB->RemoteNameLength;
3218         uniRemoteName.MaximumLength = uniRemoteName.Length;
3219         uniRemoteName.Buffer = pConnectCB->RemoteName;
3220
3221 #ifdef AFS_DEBUG_TRACE
3222         AFSDbgPrint( L"NPGetResourceInformation For remote name %wZ Scope %08lX Type %08lX Usage %08lX\n",
3223                      &uniRemoteName,
3224                      pConnectCB->Scope,
3225                      pConnectCB->Type,
3226                      pConnectCB->Usage);
3227 #endif
3228
3229         // Determine the space needed for this entry...
3230
3231         ulRequiredLen = sizeof( NETRESOURCE);
3232
3233         ulRequiredLen += pConnectCB->RemoteNameLength + sizeof( WCHAR);
3234
3235         ulRequiredLen += pConnectCB->CommentLength + sizeof( WCHAR);
3236
3237         ulRequiredLen += cbProviderNameLength + sizeof( WCHAR);
3238
3239         ulRequiredLen += pConnectCB->RemainingPathLength + sizeof( WCHAR);
3240
3241         if( pNetResource == NULL ||
3242             ulRequiredLen > dwPassedSize)
3243         {
3244
3245             *lpBufferSize = ulRequiredLen;
3246
3247             try_return( dwStatus = WN_MORE_DATA);
3248         }
3249
3250         pStringZone = (PWCHAR) ((char *)lpBuffer + sizeof( NETRESOURCE));
3251
3252         pNetResource->dwScope       = 0 /* pConnectCB->Scope*/;
3253         pNetResource->dwType        = 0 /* pConnectCB->Type */;
3254
3255         pNetResource->dwDisplayType = pConnectCB->DisplayType;
3256
3257         pNetResource->dwUsage       = pConnectCB->Usage;
3258
3259         pNetResource->lpLocalName = NULL;
3260
3261         // copy remote name
3262         pNetResource->lpRemoteName = pStringZone;
3263
3264         CopyMemory( pStringZone,
3265                     pConnectCB->RemoteName,
3266                     pConnectCB->RemoteNameLength);
3267
3268         pStringZone += (pConnectCB->RemoteNameLength / sizeof(WCHAR));
3269
3270         *pStringZone++ = L'\0';
3271
3272         // copy comment
3273         pNetResource->lpComment = pStringZone;
3274
3275         CopyMemory( pStringZone,
3276                     (void *)((char *)pConnectCB + pConnectCB->CommentOffset),
3277                     pConnectCB->CommentLength);
3278
3279         pStringZone += (pConnectCB->CommentLength / sizeof(WCHAR));
3280
3281         *pStringZone++ = L'\0';
3282
3283         // copy remaining path
3284         if (pConnectCB->RemainingPathLength > 0)
3285         {
3286             *lplpSystem = pStringZone;
3287
3288             CopyMemory( pStringZone,
3289                         (void *)((char *)pConnectCB + pConnectCB->RemainingPathOffset),
3290                         pConnectCB->RemainingPathLength);
3291
3292             pStringZone += (pConnectCB->RemainingPathLength / sizeof(WCHAR));
3293
3294             *pStringZone++ = L'\0';
3295
3296 #ifdef AFS_DEBUG_TRACE
3297             AFSDbgPrint( L"NPGetResourceInformation For remote name %s returning remaining path %s\n",
3298                          pNetResource->lpRemoteName,
3299                          *lplpSystem);
3300 #endif
3301         }
3302
3303         // copy provider name
3304         pNetResource->lpProvider = pStringZone;
3305
3306         StringCbCopy( pStringZone,
3307                       cbProviderNameLength + sizeof( WCHAR),
3308                       wszProviderName);
3309
3310         pStringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
3311
3312         *lpBufferSize = ulRequiredLen;
3313
3314         dwStatus = WN_SUCCESS;
3315
3316 try_exit:
3317
3318         if ( hControlDevice != NULL)
3319         {
3320
3321             CloseHandle( hControlDevice);
3322         }
3323
3324         if( pConnectCB != NULL)
3325         {
3326
3327             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3328         }
3329     }
3330
3331     return dwStatus;
3332 }
3333
3334 static VOID
3335 SeparateRemainingPath( WCHAR * lpConnectionName, WCHAR **lppRemainingPath)
3336 {
3337     WCHAR *pwch;
3338     WCHAR wch1, wch2;
3339     DWORD  dwCount;
3340
3341     //
3342     // at this point the lpConnectionName contains the full name.  We need to
3343     // truncate it to \\server\share and move the remaining path back one position.
3344     //
3345
3346     for ( pwch = lpConnectionName, dwCount = 0; *pwch; pwch++)
3347     {
3348         if ( *pwch == L'\\')
3349         {
3350             dwCount++;
3351         }
3352
3353         if ( dwCount == 4)
3354         {
3355             break;
3356         }
3357     }
3358
3359     if (*pwch == L'\\')
3360     {
3361         //
3362         // Found the remaining path that must be moved
3363         //
3364
3365         *lppRemainingPath = pwch + 1;
3366
3367         *pwch++ = 0;
3368
3369         //
3370         // Find the end
3371         //
3372         for ( ; *pwch; pwch++);
3373
3374         //
3375         // and work backwards moving the string
3376         // and then make sure that there is at least
3377         // a path separator.
3378         //
3379
3380         *(pwch + 1) = 0;
3381
3382         for ( ;pwch > *lppRemainingPath; pwch--)
3383         {
3384             *pwch = *(pwch - 1);
3385         }
3386
3387         *pwch = L'\\';
3388     }
3389 }
3390
3391 DWORD APIENTRY
3392 NPGetUniversalName( LPCWSTR lpLocalPath,
3393                     DWORD   dwInfoLevel,
3394                     LPVOID  lpBuffer,
3395                     LPDWORD lpBufferSize)
3396 {
3397
3398     DWORD dwBufferSize = *lpBufferSize;
3399     DWORD dwStatus;
3400
3401     dwStatus = NPGetUniversalNameCommon( lpLocalPath,
3402                                          dwInfoLevel,
3403                                          lpBuffer,
3404                                          &dwBufferSize,
3405                                          FALSE);
3406
3407     if ( dwStatus == WN_NOT_CONNECTED)
3408     {
3409
3410         dwStatus = NPGetUniversalNameCommon( lpLocalPath,
3411                                              dwInfoLevel,
3412                                              lpBuffer,
3413                                              lpBufferSize,
3414                                              TRUE);
3415     }
3416     else
3417     {
3418
3419         *lpBufferSize = dwBufferSize;
3420     }
3421
3422     return dwStatus;
3423 }
3424
3425 static DWORD APIENTRY
3426 NPGetUniversalNameCommon( LPCWSTR lpLocalPath,
3427                           DWORD   dwInfoLevel,
3428                           LPVOID  lpBuffer,
3429                           LPDWORD lpBufferSize,
3430                           BOOL    bDriveSubstOk)
3431 {
3432     DWORD    dwStatus = WN_NOT_CONNECTED;
3433     WCHAR    wchLocalName[3];
3434     WCHAR   *pwchSubstName = NULL;
3435     DWORD    dwSubstNameLength = 0;
3436     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3437     DWORD    dwError = 0;
3438     DWORD    dwBufferSize = 0;
3439     DWORD    dwPassedSize = *lpBufferSize;
3440     DWORD    dwRemainingLength = *lpBufferSize;
3441     HANDLE   hControlDevice = NULL;
3442     DWORD    dwLocalPathLength = 0;
3443     DWORD    dwRemainingPathLength = 0;
3444     CHAR    *pch;
3445
3446     __Enter
3447     {
3448
3449 #ifdef AFS_DEBUG_TRACE
3450         AFSDbgPrint( L"NPGetUniversalName local path %s level 0x%X\n",
3451                      lpLocalPath ? lpLocalPath : L"(Null)",
3452                      dwInfoLevel);
3453 #endif
3454
3455         if ( NPIsFSDisabled())
3456         {
3457
3458 #ifdef AFS_DEBUG_TRACE
3459             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
3460 #endif
3461
3462             try_return( dwStatus = WN_NOT_CONNECTED);
3463         }
3464
3465         dwLocalPathLength = lstrlen( lpLocalPath);
3466
3467         dwRemainingPathLength = dwLocalPathLength - 2;          // no drive letter
3468
3469         if( dwLocalPathLength == 0)
3470         {
3471
3472 #ifdef AFS_DEBUG_TRACE
3473             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_BAD_LOCALNAME\n");
3474 #endif
3475
3476             try_return( dwStatus = WN_BAD_LOCALNAME);
3477         }
3478
3479         if( lpBuffer == NULL ||
3480             lpBufferSize == NULL)
3481         {
3482 #ifdef AFS_DEBUG_TRACE
3483             AFSDbgPrint( L"NPGetUniversalName No output buffer or size\n");
3484 #endif
3485             try_return( dwStatus = WN_BAD_VALUE);
3486         }
3487
3488         dwSubstNameLength = 4096;
3489
3490         pwchSubstName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSubstNameLength);
3491
3492         if ( pwchSubstName == NULL)
3493         {
3494 #ifdef AFS_DEBUG_TRACE
3495             AFSDbgPrint( L"NPGetUniversalName unable to allocate substitution name buffer.\n");
3496 #endif
3497             try_return( dwStatus = WN_OUT_OF_MEMORY);
3498         }
3499
3500         memset(lpBuffer, 0, dwPassedSize);
3501
3502         if ( !bDriveSubstOk ||
3503              !DriveSubstitution( lpLocalPath, pwchSubstName, dwSubstNameLength, &dwStatus))
3504         {
3505             wchLocalName[0] = towupper(lpLocalPath[0]);
3506             wchLocalName[1] = L':';
3507             wchLocalName[2] = L'\0';
3508
3509 #ifdef AFS_DEBUG_TRACE
3510             AFSDbgPrint( L"NPGetUniversalName Requesting UNC for %s level 0x%X\n",
3511                          wchLocalName,
3512                          dwInfoLevel);
3513 #endif
3514         }
3515         else
3516         {
3517
3518             ReadServerNameString();
3519
3520             if ( pwchSubstName[0] != L'\\' &&
3521                  pwchSubstName[1] == L':')
3522             {
3523
3524                 wchLocalName[0] = towupper(pwchSubstName[0]);
3525                 wchLocalName[1] = L':';
3526                 wchLocalName[2] = L'\0';
3527
3528 #ifdef AFS_DEBUG_TRACE
3529                 AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n",
3530                              pwchSubstName,
3531                              wchLocalName);
3532 #endif
3533             }
3534             else if ( _wcsnicmp( pwchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
3535                       ( pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
3536                         pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
3537             {
3538                 HRESULT hr;
3539
3540 #ifdef AFS_DEBUG_TRACE
3541                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n",
3542                              pwchSubstName,
3543                              dwInfoLevel,
3544                              dwPassedSize);
3545 #endif
3546
3547                 dwBufferSize = (wcslen( pwchSubstName) + 1) * sizeof( WCHAR);
3548
3549                 switch( dwInfoLevel)
3550                 {
3551
3552                 case UNIVERSAL_NAME_INFO_LEVEL:
3553                 {
3554
3555                     UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3556
3557                     *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize;
3558
3559                     if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3560                     {
3561
3562 #ifdef AFS_DEBUG_TRACE
3563                         AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3564 #endif
3565
3566                         try_return( dwStatus = WN_MORE_DATA);
3567                     }
3568
3569                     dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3570
3571                     pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3572
3573                     memcpy( pUniversalInfo->lpUniversalName,
3574                             pwchSubstName,
3575                             min( dwBufferSize, dwRemainingLength));
3576
3577                     dwRemainingLength -= min( dwBufferSize, dwRemainingLength);
3578
3579 #ifdef AFS_DEBUG_TRACE
3580                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3581                                  lpBuffer,
3582                                  pUniversalInfo->lpUniversalName,
3583                                  pUniversalInfo->lpUniversalName);
3584 #endif
3585
3586                     if ( dwPassedSize < *lpBufferSize)
3587                     {
3588
3589                         try_return( dwStatus = WN_MORE_DATA);
3590                     }
3591
3592                     try_return( dwStatus = WN_SUCCESS);
3593                 }
3594
3595                 case REMOTE_NAME_INFO_LEVEL:
3596                 {
3597
3598                     REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3599
3600                     *lpBufferSize = sizeof( REMOTE_NAME_INFO) + 2 * dwBufferSize + sizeof( WCHAR);
3601
3602                     if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3603                     {
3604
3605 #ifdef AFS_DEBUG_TRACE
3606                         AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3607 #endif
3608
3609                         try_return( dwStatus = WN_MORE_DATA);
3610                     }
3611
3612                     dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3613
3614                     pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3615
3616                     memcpy( pRemoteInfo->lpUniversalName,
3617                             pwchSubstName,
3618                             min( dwRemainingLength, dwBufferSize));
3619
3620                     dwRemainingLength -= min( dwRemainingLength, dwBufferSize);
3621
3622 #ifdef AFS_DEBUG_TRACE
3623                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3624                                  lpBuffer,
3625                                  pRemoteInfo->lpUniversalName,
3626                                  pRemoteInfo->lpUniversalName);
3627 #endif
3628
3629                     if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3630                     {
3631                         pRemoteInfo->lpConnectionName = (LPTSTR)((char *)pRemoteInfo->lpUniversalName + dwBufferSize);
3632
3633                         memcpy( pRemoteInfo->lpConnectionName,
3634                                 pwchSubstName,
3635                                 min( dwRemainingLength, dwBufferSize));
3636
3637                         dwRemainingLength -= min( dwRemainingLength, dwBufferSize) - sizeof( WCHAR);
3638
3639                         SeparateRemainingPath( pRemoteInfo->lpConnectionName,
3640                                                &pRemoteInfo->lpRemainingPath);
3641                     }
3642
3643 #ifdef AFS_DEBUG_TRACE
3644                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3645                                  lpBuffer,
3646                                  pRemoteInfo->lpConnectionName,
3647                                  pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3648
3649                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3650                                  lpBuffer,
3651                                  pRemoteInfo->lpRemainingPath,
3652                                  pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3653 #endif
3654
3655                     if ( dwPassedSize < *lpBufferSize)
3656                     {
3657
3658                         try_return( dwStatus = WN_MORE_DATA);
3659                     }
3660
3661                     try_return( dwStatus = WN_SUCCESS);
3662                 }
3663
3664                 default:
3665 #ifdef AFS_DEBUG_TRACE
3666                     AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3667                                  dwInfoLevel);
3668 #endif
3669                     try_return( dwStatus = WN_BAD_VALUE);
3670                 }
3671             }
3672             else
3673             {
3674
3675 #ifdef AFS_DEBUG_TRACE
3676                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is not AFS\n",
3677                              pwchSubstName);
3678 #endif
3679                 try_return( dwStatus = WN_NOT_CONNECTED);
3680             }
3681         }
3682
3683         dwBufferSize = 0x1000;
3684
3685         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
3686
3687         if( pConnectCB == NULL)
3688         {
3689             try_return( dwStatus = WN_OUT_OF_MEMORY);
3690         }
3691
3692         pConnectCB->LocalName = towupper(wchLocalName[0]);
3693
3694         pConnectCB->RemoteNameLength = 0;
3695
3696         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
3697
3698         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
3699
3700 #ifdef AFS_DEBUG_TRACE
3701         AFSDbgPrint( L"NPGetUniversalName Retrieved authentication id %08lX-%08lX\n",
3702                      pConnectCB->AuthenticationId.HighPart,
3703                      pConnectCB->AuthenticationId.LowPart);
3704 #endif
3705
3706         hControlDevice = OpenRedirector();
3707
3708         if( hControlDevice == NULL)
3709         {
3710
3711             try_return( dwStatus = WN_NET_ERROR);
3712         }
3713
3714         dwError = DeviceIoControl( hControlDevice,
3715                                    IOCTL_AFS_GET_CONNECTION,
3716                                    pConnectCB,
3717                                    dwBufferSize,
3718                                    pConnectCB,
3719                                    dwBufferSize,
3720                                    &dwBufferSize,
3721                                    NULL);
3722
3723         if( !dwError)
3724         {
3725 #ifdef AFS_DEBUG_TRACE
3726             DWORD gle = GetLastError();
3727
3728             AFSDbgPrint( L"NPGetUniversalName Failed to get connection from file system for local %s gle 0x%x\n",
3729                          wchLocalName, gle);
3730 #endif
3731             try_return( dwStatus = WN_NOT_CONNECTED);
3732         }
3733
3734         switch( dwInfoLevel)
3735         {
3736
3737             case UNIVERSAL_NAME_INFO_LEVEL:
3738             {
3739
3740                 UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3741
3742                 *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize + sizeof( WCHAR);
3743
3744                 *lpBufferSize += dwRemainingPathLength * sizeof( WCHAR);
3745
3746                 if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3747                 {
3748
3749 #ifdef AFS_DEBUG_TRACE
3750                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3751 #endif
3752
3753                     try_return( dwStatus = WN_MORE_DATA);
3754                 }
3755
3756                 dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3757
3758                 pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3759
3760                 pch = (char *)pUniversalInfo->lpUniversalName;
3761
3762                 memcpy( pch,
3763                         pConnectCB,
3764                         min( dwBufferSize, dwRemainingLength));
3765
3766                 pch += min( dwBufferSize, dwRemainingLength);
3767
3768                 dwRemainingLength -= min( dwBufferSize + sizeof(WCHAR), dwRemainingLength);
3769
3770                 memcpy( pch,
3771                         &lpLocalPath[2],
3772                         min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength));
3773
3774                 pch += min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength);
3775
3776                 dwRemainingLength -= min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength);
3777
3778 #ifdef AFS_DEBUG_TRACE
3779                 AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3780                              lpBuffer,
3781                              pUniversalInfo->lpUniversalName,
3782                              pUniversalInfo->lpUniversalName);
3783 #endif
3784
3785                 if ( dwPassedSize < *lpBufferSize)
3786                 {
3787
3788                     try_return( dwStatus = WN_MORE_DATA);
3789                 }
3790
3791                 try_return( dwStatus = WN_SUCCESS);
3792             }
3793
3794             case REMOTE_NAME_INFO_LEVEL:
3795             {
3796
3797                 REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3798
3799                 *lpBufferSize = sizeof( REMOTE_NAME_INFO) + (2 * dwBufferSize + sizeof( WCHAR)) + 2 * sizeof( WCHAR);
3800
3801                 *lpBufferSize += 2 * dwRemainingPathLength * sizeof( WCHAR);
3802
3803                 if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3804                 {
3805
3806 #ifdef AFS_DEBUG_TRACE
3807                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3808 #endif
3809
3810                     try_return( dwStatus = WN_MORE_DATA);
3811                 }
3812
3813                 dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3814
3815                 pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3816
3817                 pch = (char *)pRemoteInfo->lpUniversalName;
3818
3819                 memcpy( pch,
3820                         pConnectCB,
3821                         min( dwBufferSize, dwRemainingLength));
3822
3823                 pch += min( dwBufferSize, dwRemainingLength);
3824
3825                 dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3826
3827                 memcpy( pch,
3828                         &lpLocalPath[2],
3829                         min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength));
3830
3831                 pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3832
3833                 dwRemainingLength -= min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3834
3835 #ifdef AFS_DEBUG_TRACE
3836                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3837                              lpBuffer,
3838                              pRemoteInfo->lpUniversalName,
3839                              pRemoteInfo->lpUniversalName);
3840 #endif
3841
3842                 if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3843                 {
3844                     pRemoteInfo->lpConnectionName = (LPWSTR)pch;
3845
3846                     memcpy( pch,
3847                             pConnectCB,
3848                             min( dwBufferSize, dwRemainingLength));
3849
3850                     pch += min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3851
3852                     dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3853                 }
3854
3855
3856                 if ( dwRemainingLength > dwRemainingPathLength + sizeof( WCHAR))
3857                 {
3858                     pRemoteInfo->lpRemainingPath = (LPWSTR)pch;
3859
3860                     memcpy( pch,
3861                             &lpLocalPath[2],
3862                             min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength));
3863
3864                     pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3865
3866                     dwRemainingLength -= min((dwLocalPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3867                 }
3868
3869 #ifdef AFS_DEBUG_TRACE
3870                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3871                              lpBuffer,
3872                              pRemoteInfo->lpConnectionName,
3873                              pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3874
3875                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3876                              lpBuffer,
3877                              pRemoteInfo->lpRemainingPath,
3878                              pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3879 #endif
3880
3881                 if ( dwPassedSize < *lpBufferSize)
3882                 {
3883
3884                     try_return( dwStatus = WN_MORE_DATA);
3885                 }
3886
3887                 try_return( dwStatus = WN_SUCCESS);
3888             }
3889
3890             default:
3891 #ifdef AFS_DEBUG_TRACE
3892                 AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3893                              dwInfoLevel);
3894 #endif
3895                 try_return( dwStatus = WN_BAD_VALUE);
3896         }
3897
3898 try_exit:
3899
3900 #ifdef AFS_DEBUG_TRACE
3901         AFSDbgPrint( L"NPGetUniversalName BufferSize 0x%X\n",
3902                      *lpBufferSize);
3903 #endif
3904         if ( hControlDevice != NULL)
3905         {
3906
3907             CloseHandle( hControlDevice);
3908         }
3909
3910         if ( pwchSubstName)
3911         {
3912
3913             HeapFree( GetProcessHeap(), 0, (PVOID) pwchSubstName);
3914         }
3915
3916         if( pConnectCB != NULL)
3917         {
3918
3919             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3920         }
3921     }
3922
3923     return dwStatus;
3924 }
3925
3926
3927 static LPCWSTR
3928 GetFormatFlags( DWORD dwFlags)
3929 {
3930     static WCHAR Buffer[128] = L"";
3931
3932     //
3933     // WNFMT_MULTILINE         0x01
3934     // WNFMT_ABBREVIATED       0x02
3935     // WNFMT_INENUM            0x10
3936     // WNFMT_CONNECTION        0x20
3937     //
3938
3939     Buffer[0] = L'\0';
3940
3941     if ( dwFlags == 0)
3942     {
3943         return L"NONE";
3944     }
3945
3946     if ( dwFlags & WNFMT_MULTILINE )
3947     {
3948         StringCbCat( Buffer, sizeof(Buffer), L"MULTILINE|");
3949     }
3950
3951     if ( dwFlags & WNFMT_INENUM )
3952     {
3953         StringCbCat( Buffer, sizeof(Buffer), L"ABBREVIATED|");
3954     }
3955
3956     if ( dwFlags & WNFMT_INENUM )
3957     {
3958         StringCbCat( Buffer, sizeof(Buffer), L"INENUM|");
3959     }
3960
3961     if ( dwFlags & WNFMT_CONNECTION )
3962     {
3963         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTION|");
3964     }
3965
3966     if ( dwFlags & ~(WNFMT_MULTILINE|WNFMT_ABBREVIATED|WNFMT_INENUM|WNFMT_CONNECTION) )
3967     {
3968         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
3969     }
3970
3971     Buffer[lstrlen(Buffer)-1] = L'\0';
3972
3973     return Buffer;
3974 }
3975
3976 DWORD
3977 NPFormatNetworkName( LPTSTR  lpRemoteName,
3978                      LPTSTR  lpFormattedName,
3979                      LPDWORD lpnLength,
3980                      DWORD dwFlags,
3981                      DWORD dwAveCharPerLine)
3982 {
3983
3984     DWORD dwLen = 0, dwCurrentLen = 0;
3985     LPTSTR pCurrentName = lpRemoteName;
3986
3987 #ifdef AFS_DEBUG_TRACE
3988     AFSDbgPrint( L"NPFormatNetworkName Remote %s Flags %s (0x%x) CharsPerLine %u\n",
3989                  lpRemoteName,
3990                  GetFormatFlags( dwFlags),
3991                  dwFlags,
3992                  dwAveCharPerLine);
3993 #endif
3994
3995
3996     //
3997     // Walk back in the name until we hit a \
3998     //
3999
4000     dwLen = wcslen( lpRemoteName);
4001
4002     pCurrentName += (dwLen - 1);
4003
4004     if ( pCurrentName[ 0] != L'\\')
4005     {
4006
4007         while( dwLen > 0)
4008         {
4009
4010             if( pCurrentName[ 0] == L'\\')
4011             {
4012
4013                 pCurrentName++;
4014
4015                 break;
4016             }
4017
4018             pCurrentName--;
4019
4020             dwLen--;
4021
4022             dwCurrentLen++;
4023         }
4024     }
4025
4026     if( *lpnLength  < dwCurrentLen * sizeof( WCHAR))
4027     {
4028
4029         *lpnLength = dwCurrentLen * sizeof( WCHAR);
4030
4031 #ifdef AFS_DEBUG_TRACE
4032         AFSDbgPrint( L"NPFormatNetworkName remote name %s WN_MORE_DATA\n",
4033                      lpRemoteName);
4034 #endif
4035
4036         return WN_MORE_DATA;
4037     }
4038
4039     StringCbCopy( lpFormattedName,
4040                   *lpnLength,
4041                   pCurrentName);
4042
4043     *lpnLength = dwCurrentLen * sizeof( WCHAR);
4044
4045 #ifdef AFS_DEBUG_TRACE
4046     AFSDbgPrint( L"NPFormatNetworkName remote name %s as %s\n",
4047                  lpRemoteName,
4048                  lpFormattedName);
4049 #endif
4050
4051     return WN_SUCCESS;
4052 }
4053
4054 /************************************************************
4055 /       Unsupported entry points
4056 /************************************************************/
4057
4058 //
4059 // AuthGroup processing is implemented in src/WINNT/afsd/afslogon.c
4060 //
4061 DWORD APIENTRY
4062 NPLogonNotify(
4063     PLUID   lpLogonId,
4064     LPCWSTR lpAuthentInfoType,
4065     LPVOID  lpAuthentInfo,
4066     LPCWSTR lpPreviousAuthentInfoType,
4067     LPVOID  lpPreviousAuthentInfo,
4068     LPWSTR  lpStationName,
4069     LPVOID  StationHandle,
4070     LPWSTR  *lpLogonScript)
4071 {
4072
4073 #ifdef AFS_DEBUG_TRACE
4074     AFSDbgPrint( L"NPLogonNotify, returning WN_NOT_SUPPORTED\n");
4075 #endif
4076
4077     return WN_NOT_SUPPORTED;
4078 }
4079
4080 DWORD APIENTRY
4081 NPPasswordChangeNotify (
4082     LPCWSTR    lpAuthentInfoType,
4083     LPVOID    lpAuthentInfo,
4084     LPCWSTR    lpPreviousAuthentInfoType,
4085     LPVOID    lpPreviousAuthentInfo,
4086     LPWSTR    lpStationName,
4087     LPVOID    StationHandle,
4088     DWORD    dwChangeInfo )
4089 {
4090
4091 #ifdef AFS_DEBUG_TRACE
4092     AFSDbgPrint( L"NPPasswordChangeNotify, returning WN_NOT_SUPPORTED\n");
4093 #endif
4094
4095     SetLastError( WN_NOT_SUPPORTED );
4096
4097     return WN_NOT_SUPPORTED;
4098 }
4099
4100 DWORD APIENTRY
4101 NPGetUser( LPTSTR lpName,
4102            LPTSTR lpUserName,
4103            LPDWORD lpBufferSize)
4104 {
4105
4106     DWORD rc = WN_NOT_SUPPORTED;
4107
4108     AFSDbgPrint( L"NPGetUser Entry Name %s\n", lpName);
4109
4110     return rc;
4111 }
4112
4113
4114 DWORD
4115 APIENTRY
4116 NPGetReconnectFlags( LPWSTR  lpRemoteName,
4117                      unsigned char *Parameter2)
4118 {
4119
4120     DWORD    dwStatus = WN_NOT_SUPPORTED;
4121
4122     AFSDbgPrint( L"NPGetReconnectFlags RemoteName %s\n",
4123                  lpRemoteName);
4124
4125     return dwStatus;
4126 }
4127
4128
4129 DWORD
4130 APIENTRY
4131 I_SystemFocusDialog( VOID)
4132 {
4133
4134     DWORD    dwStatus = WN_NOT_SUPPORTED;
4135
4136     AFSDbgPrint( L"I_SystemFocusDialog\n");
4137
4138     return dwStatus;
4139 }
4140
4141 /************************************************************
4142 /       END Unsupported entry points
4143 /************************************************************/
4144
4145
4146 HANDLE
4147 OpenRedirector()
4148 {
4149
4150     HANDLE hControlDevice = NULL;
4151
4152     hControlDevice = CreateFile( AFS_SYMLINK_W,
4153                                  GENERIC_READ | GENERIC_WRITE,
4154                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
4155                                  NULL,
4156                                  OPEN_EXISTING,
4157                                  0,
4158                                  NULL );
4159
4160     if( hControlDevice == INVALID_HANDLE_VALUE)
4161     {
4162
4163         hControlDevice = NULL;
4164 #ifdef AFS_DEBUG_TRACE
4165         AFSDbgPrint( L"Failed to open control device error: %d\n",
4166                      GetLastError());
4167 #endif
4168     }
4169 #if 0
4170     //
4171     // only do this if you want network shares to fail to mount
4172     // when the file system is not yet ready
4173     //
4174     else {
4175
4176         AFSDriverStatusRespCB   respCB;
4177         DWORD                   dwBytes;
4178
4179         memset( &respCB, '\0', sizeof( AFSDriverStatusRespCB));
4180
4181         if ( !DeviceIoControl( hControlDevice,
4182                                IOCTL_AFS_STATUS_REQUEST,
4183                                NULL,
4184                                0,
4185                                (void *)&respCB,
4186                                sizeof( AFSDriverStatusRespCB),
4187                                &dwBytes,
4188                                NULL) ||
4189              dwBytes != sizeof(AFSDriverStatusRespCB) ||
4190              respCB.Status != AFS_DRIVER_STATUS_READY )
4191         {
4192
4193             CloseHandle( hControlDevice);
4194
4195             hControlDevice = NULL;
4196         }
4197     }
4198 #endif
4199
4200     return hControlDevice;
4201 }
4202
4203 LARGE_INTEGER
4204 AFSRetrieveAuthId()
4205 {
4206
4207     LARGE_INTEGER liAuthId = {0,0};
4208     HANDLE hToken = NULL;
4209     TOKEN_STATISTICS stTokenInfo;
4210     DWORD dwCopyBytes = 0;
4211
4212     if ( !OpenThreadToken( GetCurrentThread(),
4213                            TOKEN_QUERY,
4214                            FALSE,       // Impersonation
4215                            &hToken))
4216     {
4217         if( !OpenProcessToken( GetCurrentProcess(),
4218                                TOKEN_QUERY,
4219                                &hToken))
4220         {
4221
4222 #ifdef AFS_DEBUG_TRACE
4223             AFSDbgPrint( L"AFSRetrieveAuthId Failed to retrieve Thread and Process tokens 0x%X\n",
4224                          GetLastError());
4225 #endif
4226         }
4227         else
4228         {
4229
4230 #ifdef AFS_DEBUG_TRACE
4231             AFSDbgPrint( L"AFSRetrieveAuthId Retrieved Process Token\n");
4232 #endif
4233         }
4234     }
4235     else
4236     {
4237
4238 #ifdef AFS_DEBUG_TRACE
4239         AFSDbgPrint( L"AFSRetrieveAuthId Retrieved Thread Token\n");
4240 #endif
4241     }
4242
4243     if ( hToken != NULL)
4244     {
4245
4246         if( !GetTokenInformation( hToken,
4247                                   TokenStatistics,
4248                                   &stTokenInfo,
4249                                   sizeof( TOKEN_STATISTICS),
4250                                   &dwCopyBytes))
4251         {
4252
4253 #ifdef AFS_DEBUG_TRACE
4254             AFSDbgPrint( L"AFSRetrieveAuthId Failed to retrieve token information 0x%X\n",
4255                          GetLastError());
4256 #endif
4257         }
4258         else
4259         {
4260
4261             liAuthId.HighPart = stTokenInfo.AuthenticationId.HighPart;
4262             liAuthId.LowPart = stTokenInfo.AuthenticationId.LowPart;
4263         }
4264
4265         CloseHandle( hToken);
4266     }
4267
4268     return liAuthId;
4269 }
4270
4271 static DWORD
4272 Debug(void)
4273 {
4274     static int init = 0;
4275     static DWORD debug = 0;
4276
4277     if ( !init ) {
4278         HKEY hk;
4279
4280         if (RegOpenKey (HKEY_LOCAL_MACHINE,
4281                          TEXT("SYSTEM\\CurrentControlSet\\Services\\AFSRedirector\\NetworkProvider"), &hk) == 0)
4282         {
4283             DWORD dwSize = sizeof(BOOL);
4284             DWORD dwType = REG_DWORD;
4285             RegQueryValueEx (hk, TEXT("Debug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
4286             RegCloseKey (hk);
4287         }
4288         init = 1;
4289     }
4290
4291     return debug;
4292 }
4293
4294 static char *
4295 cm_Utf16ToUtf8Alloc(const WCHAR * s, int cch_src, int *pcch_dest)
4296 {
4297     int cch_dest;
4298     char * dest;
4299
4300     if (s == NULL || cch_src == 0 || *s == L'\0') {
4301         if (pcch_dest)
4302             *pcch_dest = ((cch_src != 0)?1:0);
4303         return NULL;
4304     }
4305
4306     cch_dest = WideCharToMultiByte(CP_UTF8, 0, s, cch_src, NULL, 0, NULL, FALSE);
4307
4308     if (cch_dest == 0) {
4309         if (pcch_dest)
4310             *pcch_dest = cch_dest;
4311         return NULL;
4312     }
4313
4314     dest = HeapAlloc( GetProcessHeap(), 0, (cch_dest + 1) * sizeof(char));
4315
4316     WideCharToMultiByte(CP_UTF8, 0, s, cch_src, dest, cch_dest, NULL, FALSE);
4317     dest[cch_dest] = 0;
4318
4319     if (pcch_dest)
4320         *pcch_dest = cch_dest;
4321
4322     return dest;
4323 }
4324
4325 static void
4326 AppendDebugStringToLogFile(WCHAR *wszbuffer)
4327 {
4328     HANDLE hFile;
4329     int len;
4330     char * buffer;
4331     DWORD dwWritten;
4332     BOOL bRet;
4333
4334     if ( !wszbuffer || !wszbuffer[0] )
4335         return;
4336
4337     len = (int)wcslen(wszbuffer);
4338
4339     buffer = cm_Utf16ToUtf8Alloc(wszbuffer, len, &len);
4340
4341     if (!buffer)
4342         return;
4343
4344     hFile = CreateFileW( L"C:\\TEMP\\AFSRDFSProvider.log",
4345                          FILE_APPEND_DATA,
4346                          FILE_SHARE_WRITE,
4347                          NULL,
4348                          OPEN_ALWAYS,
4349                          FILE_ATTRIBUTE_NORMAL,
4350                          NULL);
4351
4352     if ( hFile == INVALID_HANDLE_VALUE ) {
4353         OutputDebugString(L"C:\\AFSRDFSProvider.log cannot be opened.\n");
4354         return;
4355     }
4356
4357     bRet = WriteFile( hFile, buffer, len, &dwWritten, NULL);
4358
4359     bRet = CloseHandle(hFile);
4360
4361     HeapFree(GetProcessHeap(), 0, buffer);
4362 }
4363
4364 ULONG
4365 _cdecl
4366 AFSDbgPrint(
4367     PWCHAR Format,
4368     ...
4369     )
4370 {
4371     HRESULT rc = S_OK;
4372     WCHAR wszbuffer[512];
4373     va_list marker;
4374     DWORD debug = Debug();
4375
4376     if (debug == 0)
4377         return 0;
4378
4379     va_start( marker, Format );
4380     {
4381         StringCbPrintf( wszbuffer, sizeof(wszbuffer), L"[%d-%08X] ",
4382 #ifdef AMD64
4383                            64,
4384 #else
4385                            32,
4386 #endif
4387                            GetCurrentThreadId());
4388
4389         rc = StringCbVPrintfW( &wszbuffer[ 14], sizeof(wszbuffer) - 14 * sizeof(WCHAR), Format, marker);
4390
4391         if (SUCCEEDED(rc)) {
4392             if (debug & 1)
4393                 OutputDebugString( wszbuffer );
4394             if (debug & 2)
4395                 AppendDebugStringToLogFile(wszbuffer);
4396         } else {
4397             OutputDebugString(L"AFSDbgPrint Failed to create string\n");
4398         }
4399     }
4400     return SUCCEEDED(rc) ? 1 : 0;
4401 }