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