Windows: DriveSubstitution handle too small buffer
[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, DWORD * pStatus)
261 {
262     WCHAR drive[3];
263     WCHAR device[MAX_PATH + 26];
264     HRESULT hr = S_OK;
265
266     *pStatus = WN_SUCCESS;
267
268     memset( subststr, 0, substlen);
269     drive[0] = drivestr[0];
270     drive[1] = drivestr[1];
271     drive[2] = 0;
272
273     if ( substlen < 3 * sizeof( WCHAR))
274     {
275         //
276         // Cannot represent "D:"
277         //
278         return FALSE;
279     }
280
281     if ( QueryDosDevice(drive, device, MAX_PATH + 26) )
282     {
283 #ifdef AFS_DEBUG_TRACE
284         AFSDbgPrint( L"DriveSubstitution QueryDosDevice %s [%s -> %s]\n",
285                      drivestr,
286                      drive,
287                      device);
288 #endif
289         if ( device[0] == L'\\' &&
290              device[1] == L'?' &&
291              device[2] == L'?' &&
292              device[3] == L'\\' &&
293              iswalpha(device[4]) &&
294              device[5] == L':')
295         {
296             drive[0] = device[4];
297             drive[1] = L':';
298             drive[2] = L'\0';
299
300             if ( !DriveSubstitution(drive, subststr, substlen, pStatus) )
301             {
302
303                 subststr[0] = drive[0];
304                 subststr[1] = L':';
305                 subststr[2] = L'\0';
306             }
307
308             hr = S_OK;
309
310             if ( device[6] )
311             {
312                 hr = StringCbCat( subststr, substlen, &device[6]);
313             }
314             if ( SUCCEEDED(hr) && drivestr[2] )
315             {
316                 hr = StringCbCat( subststr, substlen, &drivestr[2]);
317             }
318
319             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
320             {
321
322                 if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER )
323                     *pStatus = WN_MORE_DATA;
324
325 #ifdef AFS_DEBUG_TRACE
326                     AFSDbgPrint( L"DriveSubstitution (hr = %X) %s -> %s\n",
327                                  hr,
328                                  drivestr,
329                                  subststr);
330 #endif
331                 return TRUE;
332             }
333         }
334         else if ( device[0] == L'\\' &&
335                   device[1] == L'?' &&
336                   device[2] == L'?' &&
337                   device[3] == L'\\' &&
338                   device[4] == L'U' &&
339                   device[5] == L'N' &&
340                   device[6] == L'C' &&
341                   device[7] == L'\\')
342         {
343
344             subststr[0] = L'\\';
345
346             hr = StringCbCopyN(&subststr[1], substlen - sizeof(WCHAR), &device[7], sizeof(device) - 7 * sizeof(WCHAR));
347
348             if ( SUCCEEDED(hr) && drivestr[2] )
349             {
350                 hr = StringCbCat( subststr, substlen, &drivestr[2]);
351             }
352
353             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
354             {
355
356                 if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER )
357                     *pStatus = WN_MORE_DATA;
358
359 #ifdef AFS_DEBUG_TRACE
360                     AFSDbgPrint( L"DriveSubstitution (hr = %X) %s -> %s\n",
361                                  hr,
362                                  drivestr,
363                                  subststr);
364 #endif
365                 return TRUE;
366             }
367
368 #ifdef AFS_DEBUG_TRACE
369             AFSDbgPrint( L"DriveSubstitution StringCbCopyN 1 hr 0x%X\n",
370                          hr);
371 #endif
372         }
373         else if ( _wcsnicmp( AFS_RDR_DEVICE_NAME, device, sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR) - 1) == 0)
374         {
375             //
376             // \Device\AFSRedirector\;X:\\afs\cellname
377             //
378
379             hr = StringCbCopy( subststr, substlen,
380                                &device[3 + sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR)]);
381
382             if ( SUCCEEDED(hr) && drivestr[2] )
383             {
384                 hr = StringCbCat( subststr, substlen, &drivestr[2]);
385             }
386
387             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
388             {
389
390                 if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER )
391                     *pStatus = WN_MORE_DATA;
392
393 #ifdef AFS_DEBUG_TRACE
394                 AFSDbgPrint( L"DriveSubstitution (hr = %X) %s -> %s\n",
395                              hr,
396                              drivestr,
397                              subststr);
398 #endif
399                 return TRUE;
400             }
401
402 #ifdef AFS_DEBUG_TRACE
403             AFSDbgPrint( L"DriveSubstitution StringCbCopyN 2 hr 0x%X\n",
404                          hr);
405 #endif
406         }
407
408 #ifdef AFS_DEBUG_TRACE
409         AFSDbgPrint( L"DriveSubstitution no substitution or match %s !! %s\n",
410                      drivestr,
411                      device);
412 #endif
413     }
414     else
415     {
416 #ifdef AFS_DEBUG_TRACE
417         AFSDbgPrint( L"DriveSubstitution QueryDosDevice failed %s gle 0x%X\n",
418                      drivestr,
419                      GetLastError());
420 #endif
421     }
422
423     return FALSE;
424 }
425
426
427 static const WCHAR *
428 NPGetCapsQueryString( DWORD nIndex)
429 {
430     switch ( nIndex) {
431     case WNNC_SPEC_VERSION:
432         return L"WNNC_SPEC_VERSION";
433
434     case WNNC_NET_TYPE:
435         return L"WNNC_NET_TYPE";
436
437     case WNNC_DRIVER_VERSION:
438         return L"WNNC_DRIVER_VERSION";
439
440     case WNNC_USER:
441         return L"WNNC_USER";
442
443     case WNNC_CONNECTION:
444         return L"WNNC_CONNECTION";
445
446     case WNNC_DIALOG:
447         return L"WNNC_DIALOG";
448
449     case WNNC_ADMIN:
450         return L"WNNC_ADMIN";
451
452     case WNNC_ENUMERATION:
453         return L"WNNC_ENUMERATION";
454
455     case WNNC_START:
456         return L"WNNC_START";
457
458     case WNNC_CONNECTION_FLAGS:
459         return L"WNNC_CONNECTION_FLAGS";
460
461     default:
462         return L"UNKNOWN";
463     }
464 }
465
466 //
467 // This is the only function which must be exported, everything else is optional
468 //
469
470 DWORD
471 APIENTRY
472 NPGetCaps( DWORD nIndex )
473 {
474
475     DWORD rc = 0;
476
477 #ifdef AFS_DEBUG_TRACE
478     AFSDbgPrint( L"NPGetCaps Index %u %s\n", nIndex,
479                  NPGetCapsQueryString( nIndex));
480 #endif
481     switch( nIndex)
482     {
483         case WNNC_SPEC_VERSION:
484         {
485
486             rc = WNNC_SPEC_VERSION51;
487             break;
488         }
489
490         case WNNC_NET_TYPE:
491         {
492             rc = WNNC_NET_OPENAFS;
493             break;
494         }
495
496         case WNNC_DRIVER_VERSION:
497         {
498
499             rc = WNNC_DRIVER(1, 0);
500             break;
501         }
502
503         case WNNC_CONNECTION:
504         {
505
506             //
507             // No support for:
508             //   WNNC_CON_GETPERFORMANCE
509             //   WNNC_CON_DEFER
510             //
511
512             rc = WNNC_CON_GETCONNECTIONS |
513                  WNNC_CON_CANCELCONNECTION |
514                  WNNC_CON_ADDCONNECTION |
515                  WNNC_CON_ADDCONNECTION3;
516
517             break;
518         }
519
520         case WNNC_ENUMERATION:
521         {
522             rc = WNNC_ENUM_LOCAL |
523                  WNNC_ENUM_CONTEXT |
524                  WNNC_ENUM_GLOBAL |
525                  WNNC_ENUM_SHAREABLE;
526             break;
527         }
528
529         case WNNC_START:
530         {
531
532             rc = WNNC_WAIT_FOR_START;
533
534             break;
535         }
536
537         case WNNC_DIALOG:
538         {
539
540             //
541             // No support for:
542             //    WNNC_DLG_DEVICEMODE
543             //    WNNC_DLG_PROPERTYDIALOG
544             //    WNNC_DLG_SEARCHDIALOG
545             //    WNNC_DLG_PERMISSIONEDITOR
546             //
547
548             rc = WNNC_DLG_FORMATNETWORKNAME |
549                  WNNC_DLG_GETRESOURCEINFORMATION |
550                  WNNC_DLG_GETRESOURCEPARENT;
551
552             break;
553         }
554
555         case WNNC_USER:
556         {
557             //
558             // No support for:
559             //    WNNC_USR_GETUSER
560             //
561
562             break;
563         }
564
565         case WNNC_ADMIN:
566         {
567             //
568             // No support for:
569             //    WNNC_ADM_GETDIRECTORYTYPE
570             //    WNNC_ADM_DIRECTORYNOTIFY
571             // used by the old File Manager
572             //
573             break;
574         }
575     }
576
577     return rc;
578 }
579
580 DWORD
581 APIENTRY
582 NPAddConnection( LPNETRESOURCE   lpNetResource,
583                  LPWSTR          lpPassword,
584                  LPWSTR          lpUserName )
585 {
586
587 #ifdef AFS_DEBUG_TRACE
588     AFSDbgPrint( L"NPAddConnection forwarding to NPAddConnection3\n");
589 #endif
590     return NPAddConnection3( NULL, lpNetResource, lpPassword, lpUserName, 0 );
591 }
592
593 DWORD
594 APIENTRY
595 NPAddConnection3( HWND            hwndOwner,
596                   LPNETRESOURCE   lpNetResource,
597                   LPWSTR          lpPassword,
598                   LPWSTR          lpUserName,
599                   DWORD           dwFlags )
600 {
601
602     DWORD    dwStatus = WN_SUCCESS;
603     WCHAR    wchRemoteName[MAX_PATH+1];
604     WCHAR    wchLocalName[3];
605     DWORD    dwCopyBytes = 0;
606     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
607     DWORD    dwError = 0;
608     DWORD    dwBufferSize = 0;
609     HANDLE   hControlDevice = NULL;
610     HANDLE   hToken = NULL;
611     LARGE_INTEGER liAuthId = {0,0};
612     HRESULT  hr;
613
614     __Enter
615     {
616         if ( NPIsFSDisabled())
617         {
618
619 #ifdef AFS_DEBUG_TRACE
620             AFSDbgPrint( L"NPAddConnection3 AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
621 #endif
622
623             return WN_BAD_NETNAME;
624         }
625
626         if ((lpNetResource->lpRemoteName == NULL) ||
627             (lpNetResource->lpRemoteName[0] != L'\\') ||
628             (lpNetResource->lpRemoteName[1] != L'\\') ||
629             ((lpNetResource->dwType != RESOURCETYPE_DISK) &&
630              (lpNetResource->dwType != RESOURCETYPE_ANY)))
631         {
632
633 #ifdef AFS_DEBUG_TRACE
634             AFSDbgPrint( L"NPAddConnection3 invalid input, returning WN_BAD_NETNAME\n");
635 #endif
636             return WN_BAD_NETNAME;
637         }
638
639 #ifdef AFS_DEBUG_TRACE
640         AFSDbgPrint( L"NPAddConnection3 processing\n");
641 #endif
642         if( lpNetResource->lpLocalName != NULL)
643         {
644
645             wchLocalName[0] = towupper(lpNetResource->lpLocalName[0]);
646             wchLocalName[1] = L':';
647             wchLocalName[2] = L'\0';
648         }
649
650         hr = StringCbCopy(wchRemoteName, sizeof( wchRemoteName), lpNetResource->lpRemoteName);
651         if ( FAILED(hr))
652         {
653
654 #ifdef AFS_DEBUG_TRACE
655             AFSDbgPrint( L"NPAddConnection3 lpRemoteName longer than MAX_PATH, returning WN_BAD_NETNAME\n");
656 #endif
657             return WN_BAD_NETNAME;
658         }
659
660         //
661         // Allocate our buffer to pass to the redirector filter
662         //
663
664         dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + (wcslen( wchRemoteName) * sizeof( WCHAR));
665
666         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
667
668         if( pConnectCB == NULL)
669         {
670
671             try_return( dwStatus = WN_OUT_OF_MEMORY);
672         }
673
674         if( lpNetResource->lpLocalName != NULL)
675         {
676
677             pConnectCB->LocalName = towupper(wchLocalName[0]);
678
679 #ifdef AFS_DEBUG_TRACE
680             AFSDbgPrint( L"NPAddConnection3 Adding mapping for drive %s remote name %s\n",
681                          wchLocalName,
682                          wchRemoteName);
683 #endif
684         }
685         else
686         {
687
688             pConnectCB->LocalName = L'\0';
689
690 #ifdef AFS_DEBUG_TRACE
691             AFSDbgPrint( L"NPAddConnection3 Adding mapping for NO drive remote name %s\n",
692                          wchRemoteName);
693 #endif
694         }
695
696         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
697
698         pConnectCB->RemoteNameLength = wcslen( wchRemoteName) * sizeof( WCHAR);
699
700         memcpy( pConnectCB->RemoteName,
701                 wchRemoteName,
702                 pConnectCB->RemoteNameLength);
703
704         pConnectCB->Type = lpNetResource->dwType;
705
706         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
707
708 #ifdef AFS_DEBUG_TRACE
709         AFSDbgPrint( L"NPAddConnection3 Retrieved authentication id %08lX-%08lX\n",
710                      pConnectCB->AuthenticationId.HighPart,
711                      pConnectCB->AuthenticationId.LowPart);
712 #endif
713
714         hControlDevice = OpenRedirector();
715
716         if( hControlDevice == NULL)
717         {
718
719 #ifdef AFS_DEBUG_TRACE
720             AFSDbgPrint( L"NPAddConnection3 OpenRedirector failure, returning WN_NET_ERROR\n");
721 #endif
722
723             try_return( dwStatus = WN_NET_ERROR);
724         }
725
726         dwError = DeviceIoControl( hControlDevice,
727                                    IOCTL_AFS_ADD_CONNECTION,
728                                    pConnectCB,
729                                    dwBufferSize,
730                                    &dwStatus,
731                                    sizeof( DWORD),
732                                    &dwCopyBytes,
733                                    NULL);
734
735         if( !dwError)
736         {
737 #ifdef AFS_DEBUG_TRACE
738             AFSDbgPrint( L"NPAddConnection3 Failed to add connection to file system %d\n", GetLastError());
739 #endif
740             try_return( dwStatus = WN_OUT_OF_MEMORY);
741         }
742
743         //
744         // The status returned from the driver will indicate how it was handled
745         //
746
747         if( dwStatus == WN_SUCCESS &&
748             lpNetResource->lpLocalName != NULL)
749         {
750
751             WCHAR TempBuf[MAX_PATH+26];
752
753             if( !QueryDosDeviceW( wchLocalName,
754                                   TempBuf,
755                                   MAX_PATH+26))
756             {
757
758                 if( GetLastError() != ERROR_FILE_NOT_FOUND)
759                 {
760
761 #ifdef AFS_DEBUG_TRACE
762                     AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW failed with file not found\n");
763 #endif
764                     NPCancelConnection( wchLocalName, TRUE);
765
766                     dwStatus = ERROR_ALREADY_ASSIGNED;
767                 }
768                 else
769                 {
770
771                     UNICODE_STRING uniConnectionName;
772
773                     //
774                     // Create a symbolic link object to the device we are redirecting
775                     //
776
777                     uniConnectionName.MaximumLength = (USHORT)( wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR) +
778                                                                 pConnectCB->RemoteNameLength +
779                                                                 8 +              // Local name and \;
780                                                                 sizeof(WCHAR));   //  Space for NULL-termination.
781
782                     //
783                     //  Don't include NULL-termination.
784                     //
785
786                     uniConnectionName.Length = uniConnectionName.MaximumLength - sizeof(WCHAR);
787
788                     uniConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT,
789                                                            uniConnectionName.MaximumLength);
790
791                     if( uniConnectionName.Buffer == NULL)
792                     {
793
794                         try_return( dwStatus = GetLastError());
795                     }
796
797                     hr = StringCbCopyW( uniConnectionName.Buffer,
798                                         uniConnectionName.MaximumLength,
799                                         AFS_RDR_DEVICE_NAME);
800                     if ( FAILED(hr))
801                     {
802 #ifdef AFS_DEBUG_TRACE
803                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
804 #endif
805                         try_return( dwStatus = WN_OUT_OF_MEMORY);
806                     }
807
808                     hr = StringCbCatW( uniConnectionName.Buffer,
809                                        uniConnectionName.MaximumLength,
810                                        L"\\;" );
811                     if ( FAILED(hr))
812                     {
813 #ifdef AFS_DEBUG_TRACE
814                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
815 #endif
816                         try_return( dwStatus = WN_OUT_OF_MEMORY);
817                     }
818
819                     hr = StringCbCatW( uniConnectionName.Buffer,
820                                        uniConnectionName.MaximumLength,
821                                        wchLocalName);
822                     if ( FAILED(hr))
823                     {
824 #ifdef AFS_DEBUG_TRACE
825                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
826 #endif
827                         try_return( dwStatus = WN_OUT_OF_MEMORY);
828                     }
829
830                     hr = StringCbCatW( uniConnectionName.Buffer,
831                                        uniConnectionName.MaximumLength,
832                                        wchRemoteName);
833                     if ( FAILED(hr))
834                     {
835 #ifdef AFS_DEBUG_TRACE
836                         AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
837 #endif
838                         try_return( dwStatus = WN_OUT_OF_MEMORY);
839                     }
840
841 #ifdef AFS_DEBUG_TRACE
842                     AFSDbgPrint( L"NPAddConnection3 DefineDosDevice Local %s connection name %s\n",
843                                  wchLocalName,
844                                  uniConnectionName.Buffer);
845 #endif
846
847                     if( !DefineDosDeviceW( DDD_RAW_TARGET_PATH |
848                                            DDD_NO_BROADCAST_SYSTEM,
849                                            wchLocalName,
850                                            uniConnectionName.Buffer))
851                     {
852 #ifdef AFS_DEBUG_TRACE
853                         AFSDbgPrint( L"NPAddConnection3 Failed to assign drive\n");
854 #endif
855                         dwStatus = GetLastError();
856                     }
857                     else
858                     {
859
860 #ifdef AFS_DEBUG_TRACE
861                         AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW assigned drive %s\n", wchLocalName);
862 #endif
863
864                         dwStatus = WN_SUCCESS;
865                     }
866
867                     LocalFree( uniConnectionName.Buffer);
868                 }
869             }
870             else
871             {
872
873 #ifdef AFS_DEBUG_TRACE
874                 AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW %Z already existed\n", TempBuf);
875 #endif
876                 NPCancelConnection( wchLocalName, TRUE);
877
878                 dwStatus = ERROR_ALREADY_ASSIGNED;
879             }
880         }
881
882 try_exit:
883
884         if ( hControlDevice != NULL)
885         {
886
887             CloseHandle( hControlDevice);
888         }
889
890         if( pConnectCB != NULL)
891         {
892
893             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
894         }
895     }
896
897     return dwStatus;
898 }
899
900 DWORD
901 APIENTRY
902 NPCancelConnection( LPWSTR  lpName,
903                     BOOL    fForce)
904 {
905
906     WCHAR    wchRemoteName[MAX_PATH+1];
907     DWORD    dwRemoteNameLength = (MAX_PATH+1) * sizeof(WCHAR);
908     DWORD    dwStatus = WN_NOT_CONNECTED;
909     DWORD    dwCopyBytes = 0;
910     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
911     AFSCancelConnectionResultCB stCancelConn;
912     DWORD    dwError = 0;
913     DWORD    dwBufferSize = 0;
914     BOOL     bLocalName = TRUE;
915     HANDLE   hControlDevice = NULL;
916     WCHAR    wchLocalName[ 3];
917     WCHAR   *pwchLocalName = NULL;
918     HRESULT hr;
919
920     __Enter
921     {
922
923         if ( NPIsFSDisabled())
924         {
925
926 #ifdef AFS_DEBUG_TRACE
927             AFSDbgPrint( L"NPCancelConnection AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
928 #endif
929
930             try_return( dwStatus = WN_NOT_CONNECTED);
931         }
932
933         if( *lpName == L'\\' &&
934             *(lpName + 1) == L'\\')
935         {
936
937             bLocalName = FALSE;
938
939             wchLocalName[0] = L'\0';
940
941             hr = StringCbCopyW( wchRemoteName, sizeof( wchRemoteName), lpName);
942
943             if ( FAILED(hr))
944             {
945 #ifdef AFS_DEBUG_TRACE
946                 AFSDbgPrint( L"NPCancelConnection lpName longer than MAX_PATH\n");
947 #endif
948                 try_return( dwStatus = WN_OUT_OF_MEMORY);
949             }
950
951             dwRemoteNameLength = (wcslen( wchRemoteName) * sizeof( WCHAR));
952         }
953         else
954         {
955
956             wchLocalName[0] = towupper(lpName[0]);
957             wchLocalName[1] = L':';
958             wchLocalName[2] = L'\0';
959
960             //
961             // Get the remote name for the connection, if we are handling it
962             //
963
964             dwStatus = NPGetConnectionCommon( wchLocalName,
965                                               wchRemoteName,
966                                               &dwRemoteNameLength,
967                                               FALSE);
968
969             if( dwStatus != WN_SUCCESS ||
970                 dwRemoteNameLength == 0)
971             {
972
973 #ifdef AFS_DEBUG_TRACE
974                 AFSDbgPrint( L"NPCancelConnection Status 0x%x NameLength %u, returning WN_NOT_CONNECTED\n",
975                              dwStatus, dwRemoteNameLength);
976 #endif
977                 try_return( dwStatus = WN_NOT_CONNECTED);
978             }
979
980             //
981             // NPGetConnection returns the buffer size not the length without NUL
982             //
983             dwRemoteNameLength -= sizeof( WCHAR);
984         }
985
986         wchRemoteName[ dwRemoteNameLength/sizeof( WCHAR)] = L'\0';
987
988 #ifdef AFS_DEBUG_TRACE
989         AFSDbgPrint( L"NPCancelConnection Attempting to cancel '%s' -> '%s'\n",
990                      wchLocalName, wchRemoteName);
991 #endif
992
993         dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + dwRemoteNameLength;
994
995         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
996
997         if( pConnectCB == NULL)
998         {
999
1000             try_return( dwStatus = WN_OUT_OF_MEMORY);
1001         }
1002
1003         if( bLocalName)
1004         {
1005
1006             pConnectCB->LocalName = wchLocalName[0];
1007         }
1008         else
1009         {
1010
1011             pConnectCB->LocalName = L'\0';
1012         }
1013
1014         pConnectCB->RemoteNameLength = (USHORT)dwRemoteNameLength;
1015
1016         StringCbCopyW( pConnectCB->RemoteName,
1017                        dwRemoteNameLength + sizeof( WCHAR),
1018                        wchRemoteName);
1019
1020         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1021
1022         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1023
1024 #ifdef AFS_DEBUG_TRACE
1025         AFSDbgPrint( L"NPCancelConnection Retrieved authentication id %08lX-%08lX\n",
1026                      pConnectCB->AuthenticationId.HighPart,
1027                      pConnectCB->AuthenticationId.LowPart);
1028 #endif
1029
1030         hControlDevice = OpenRedirector();
1031
1032         if( hControlDevice == NULL)
1033         {
1034
1035 #ifdef AFS_DEBUG_TRACE
1036             AFSDbgPrint( L"NPCancelConnection OpenRedirector failure, returning WN_NET_ERROR\n");
1037 #endif
1038
1039             try_return( dwStatus = WN_NET_ERROR);
1040         }
1041
1042         memset( &stCancelConn,
1043                 '\0',
1044                 sizeof( AFSCancelConnectionResultCB));
1045
1046         dwError = DeviceIoControl( hControlDevice,
1047                                    IOCTL_AFS_CANCEL_CONNECTION,
1048                                    pConnectCB,
1049                                    dwBufferSize,
1050                                    &stCancelConn,
1051                                    sizeof( AFSCancelConnectionResultCB),
1052                                    &dwCopyBytes,
1053                                    NULL);
1054
1055         if( !dwError)
1056         {
1057 #ifdef AFS_DEBUG_TRACE
1058             DWORD gle = GetLastError();
1059
1060             AFSDbgPrint( L"NPCancelConnection DeviceIoControl failed - gle 0x%x\n", gle);
1061 #endif
1062             try_return( dwStatus = WN_NOT_CONNECTED);
1063         }
1064
1065         dwStatus = stCancelConn.Status;
1066
1067 #ifdef AFS_DEBUG_TRACE
1068         if ( dwStatus == WN_NOT_CONNECTED )
1069         {
1070
1071             AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status WN_NOT_CONNECTED\n",
1072                          lpName);
1073         }
1074         else
1075         {
1076
1077             AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status %08lX\n",
1078                          lpName,
1079                          dwStatus);
1080         }
1081 #endif
1082
1083         if( dwStatus == WN_SUCCESS &&
1084             ( bLocalName ||
1085               stCancelConn.LocalName != L'\0'))
1086         {
1087
1088             UNICODE_STRING uniConnectionName;
1089
1090             //
1091             // Create a symbolic link object to the device we are redirecting
1092             //
1093
1094             uniConnectionName.MaximumLength = (USHORT)( wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR) +
1095                                                         dwRemoteNameLength +
1096                                                         8 +             // Local name and \;
1097                                                         sizeof(WCHAR)); //  Space for NULL-termination.
1098
1099             //
1100             //  Don't include NULL-termination.
1101             //
1102
1103             uniConnectionName.Length = uniConnectionName.MaximumLength - sizeof(WCHAR);
1104
1105             uniConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT,
1106                                                    uniConnectionName.MaximumLength);
1107
1108             if( uniConnectionName.Buffer == NULL)
1109             {
1110
1111                 try_return( dwStatus = GetLastError());
1112             }
1113
1114             hr = StringCbCopyW( uniConnectionName.Buffer,
1115                                 uniConnectionName.MaximumLength,
1116                                 AFS_RDR_DEVICE_NAME);
1117
1118             if ( FAILED(hr))
1119             {
1120 #ifdef AFS_DEBUG_TRACE
1121                 AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (1)\n");
1122 #endif
1123                 try_return( dwStatus = WN_OUT_OF_MEMORY);
1124             }
1125
1126             hr = StringCbCatW( uniConnectionName.Buffer,
1127                                uniConnectionName.MaximumLength,
1128                                L"\\;" );
1129
1130             if ( FAILED(hr))
1131             {
1132 #ifdef AFS_DEBUG_TRACE
1133                 AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (2)\n");
1134 #endif
1135                 try_return( dwStatus = WN_OUT_OF_MEMORY);
1136             }
1137
1138             if( !bLocalName)
1139             {
1140
1141                 wchLocalName[ 0] = stCancelConn.LocalName;
1142
1143                 wchLocalName[ 1] = L':';
1144
1145                 wchLocalName[ 2] = L'\0';
1146
1147                 hr = StringCbCatW( uniConnectionName.Buffer,
1148                                    uniConnectionName.MaximumLength,
1149                                    wchLocalName);
1150
1151                 if ( FAILED(hr))
1152                 {
1153 #ifdef AFS_DEBUG_TRACE
1154                     AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (3)\n");
1155 #endif
1156                     try_return( dwStatus = WN_OUT_OF_MEMORY);
1157                 }
1158
1159                 pwchLocalName = wchLocalName;
1160             }
1161             else
1162             {
1163
1164                 hr = StringCbCatW( uniConnectionName.Buffer,
1165                                    uniConnectionName.MaximumLength,
1166                                    lpName);
1167
1168                 if ( FAILED(hr))
1169                 {
1170 #ifdef AFS_DEBUG_TRACE
1171                     AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (4)\n");
1172 #endif
1173                     try_return( dwStatus = WN_OUT_OF_MEMORY);
1174                 }
1175
1176                 pwchLocalName = lpName;
1177             }
1178
1179             hr = StringCbCatW( uniConnectionName.Buffer,
1180                                uniConnectionName.MaximumLength,
1181                                wchRemoteName);
1182
1183             if ( FAILED(hr))
1184             {
1185 #ifdef AFS_DEBUG_TRACE
1186                 AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (5)\n");
1187 #endif
1188                 try_return( dwStatus = WN_OUT_OF_MEMORY);
1189             }
1190
1191             if( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
1192                                   pwchLocalName,
1193                                   uniConnectionName.Buffer))
1194             {
1195
1196 #ifdef AFS_DEBUG_TRACE
1197                 DWORD gle = GetLastError();
1198
1199                 AFSDbgPrint( L"NPCancelConnection Failed to cancel connection to system - gle 0x%x Name %s connection %wZ\n",
1200                              gle,
1201                              pwchLocalName,
1202                              &uniConnectionName);
1203 #endif
1204             }
1205             else
1206             {
1207 #ifdef AFS_DEBUG_TRACE
1208
1209                 AFSDbgPrint( L"NPCancelConnection Canceled connection to system - Name %s connection %wZ\n",
1210                              pwchLocalName,
1211                              &uniConnectionName);
1212 #endif
1213             }
1214         }
1215
1216 try_exit:
1217
1218         if ( hControlDevice != NULL)
1219         {
1220
1221             CloseHandle( hControlDevice);
1222         }
1223
1224
1225         if( pConnectCB != NULL)
1226         {
1227
1228             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1229         }
1230
1231     }
1232
1233     return dwStatus;
1234 }
1235
1236 DWORD
1237 APIENTRY
1238 NPGetConnection( LPWSTR  lpLocalName,
1239                  LPWSTR  lpRemoteName,
1240                  LPDWORD lpBufferSize)
1241 {
1242
1243     return NPGetConnectionCommon( lpLocalName,
1244                                   lpRemoteName,
1245                                   lpBufferSize,
1246                                   TRUE);
1247 }
1248
1249 DWORD
1250 APIENTRY
1251 NPGetConnectionCommon( LPWSTR  lpLocalName,
1252                        LPWSTR  lpRemoteName,
1253                        LPDWORD lpBufferSize,
1254                        BOOL    bDriveSubstOk)
1255 {
1256
1257     DWORD    dwStatus = WN_NOT_CONNECTED;
1258     WCHAR    wchLocalName[3];
1259     WCHAR    wchSubstName[1024 + 26];
1260     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
1261     DWORD    dwError = 0;
1262     DWORD    dwBufferSize = 0;
1263     HANDLE   hControlDevice = NULL;
1264     DWORD    dwPassedSize;
1265
1266     __Enter
1267     {
1268
1269         if ( NPIsFSDisabled())
1270         {
1271
1272 #ifdef AFS_DEBUG_TRACE
1273             AFSDbgPrint( L"NPGetConnection AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
1274 #endif
1275
1276             try_return( dwStatus = WN_NOT_CONNECTED);
1277         }
1278
1279         if( lstrlen( lpLocalName) == 0)
1280         {
1281 #ifdef AFS_DEBUG_TRACE
1282             AFSDbgPrint( L"NPGetConnection No local name, returning WN_BAD_LOCALNAME\n");
1283 #endif
1284             try_return( dwStatus = WN_BAD_LOCALNAME);
1285         }
1286
1287         if ( lpBufferSize == NULL)
1288         {
1289 #ifdef AFS_DEBUG_TRACE
1290             AFSDbgPrint( L"NPGetConnection No output size, returning WN_BAD_LOCALNAME\n");
1291 #endif
1292             try_return( dwStatus = WN_BAD_VALUE);
1293         }
1294
1295         dwPassedSize = *lpBufferSize;
1296
1297         if ( !bDriveSubstOk ||
1298              !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName), &dwStatus))
1299         {
1300             wchLocalName[0] = towupper(lpLocalName[0]);
1301             wchLocalName[1] = L':';
1302             wchLocalName[2] = L'\0';
1303
1304 #ifdef AFS_DEBUG_TRACE
1305             AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n",
1306                          wchLocalName);
1307 #endif
1308         }
1309         else
1310         {
1311             ReadServerNameString();
1312
1313             if ( wchSubstName[0] != L'\\' &&
1314                  wchSubstName[1] == L':')
1315             {
1316
1317                 wchLocalName[0] = towupper(wchSubstName[0]);
1318                 wchLocalName[1] = L':';
1319                 wchLocalName[2] = L'\0';
1320
1321 #ifdef AFS_DEBUG_TRACE
1322                 AFSDbgPrint( L"NPGetConnection Requesting connection for drive substitution %s -> %s\n",
1323                              wchSubstName,
1324                              wchLocalName);
1325 #endif
1326             }
1327             else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
1328                       ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
1329                         wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
1330             {
1331                 HRESULT hr;
1332                 WCHAR  *pwch;
1333                 DWORD   dwCount = 0;
1334                 DWORD   dwRequiredSize;
1335
1336 #ifdef AFS_DEBUG_TRACE
1337                 AFSDbgPrint( L"NPGetConnection drive substitution %s is AFS\n",
1338                              wchSubstName);
1339 #endif
1340
1341                 dwRequiredSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
1342
1343                 if ( lpRemoteName == NULL ||
1344                      dwPassedSize == 0 ||
1345                      dwRequiredSize > *lpBufferSize)
1346                 {
1347
1348                     *lpBufferSize = dwRequiredSize;
1349
1350                     try_return( dwStatus = WN_MORE_DATA);
1351
1352                 }
1353
1354                 hr = StringCbCopyN(lpRemoteName, *lpBufferSize, wchSubstName, sizeof( wchSubstName));
1355
1356                 if ( SUCCEEDED(hr))
1357                 {
1358
1359                     for ( dwCount = 0, pwch = lpRemoteName; *pwch && pwch < lpRemoteName + (*lpBufferSize); pwch++ )
1360                     {
1361                         if ( *pwch == L'\\' )
1362                         {
1363                             dwCount++;
1364
1365                             if ( dwCount == 4)
1366                             {
1367                                 *pwch = L'\0';
1368
1369                                 break;
1370                             }
1371                         }
1372
1373                     }
1374
1375                     *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR);
1376
1377                     try_return( dwStatus = WN_SUCCESS);
1378                 }
1379                 else if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER)
1380                 {
1381
1382                     *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
1383
1384                     for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ )
1385                     {
1386                         if ( *pwch == L'\\' )
1387                         {
1388                             dwCount++;
1389
1390                             if ( dwCount == 4)
1391                             {
1392                                 *pwch = L'\0';
1393
1394                                 *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR);
1395
1396                                 try_return( dwStatus = WN_SUCCESS);
1397                             }
1398                         }
1399
1400                     }
1401
1402                     try_return( dwStatus = WN_MORE_DATA);
1403                 }
1404                 else
1405                 {
1406
1407 #ifdef AFS_DEBUG_TRACE
1408                     AFSDbgPrint( L"NPGetConnection StringCbCopyN failure 0x%X\n",
1409                                  hr);
1410 #endif
1411                     try_return( dwStatus = WN_NET_ERROR);
1412                 }
1413             }
1414             else
1415             {
1416
1417 #ifdef AFS_DEBUG_TRACE
1418                 AFSDbgPrint( L"NPGetConnection drive substitution %s is not AFS\n",
1419                              wchSubstName);
1420 #endif
1421                 try_return( dwStatus = WN_NOT_CONNECTED);
1422             }
1423         }
1424
1425 #ifdef AFS_DEBUG_TRACE
1426         AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n",
1427                      wchLocalName);
1428 #endif
1429
1430         dwBufferSize = 0x1000;
1431
1432         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1433
1434         if( pConnectCB == NULL)
1435         {
1436
1437             try_return( dwStatus = WN_OUT_OF_MEMORY);
1438         }
1439
1440         pConnectCB->LocalName = towupper(wchLocalName[0]);
1441
1442         pConnectCB->RemoteNameLength = 0;
1443
1444         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1445
1446         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1447
1448 #ifdef AFS_DEBUG_TRACE
1449         AFSDbgPrint( L"NPGetConnection Retrieved authentication id %08lX-%08lX\n",
1450                      pConnectCB->AuthenticationId.HighPart,
1451                      pConnectCB->AuthenticationId.LowPart);
1452 #endif
1453
1454         hControlDevice = OpenRedirector();
1455
1456         if( hControlDevice == NULL)
1457         {
1458
1459 #ifdef AFS_DEBUG_TRACE
1460             AFSDbgPrint( L"NPGetConnection OpenRedirector failure, returning WN_NET_ERROR\n");
1461 #endif
1462
1463             try_return( dwStatus = WN_NET_ERROR);
1464         }
1465
1466         dwError = DeviceIoControl( hControlDevice,
1467                                    IOCTL_AFS_GET_CONNECTION,
1468                                    pConnectCB,
1469                                    dwBufferSize,
1470                                    pConnectCB,
1471                                    dwBufferSize,
1472                                    lpBufferSize,
1473                                    NULL);
1474
1475         if( !dwError)
1476         {
1477 #ifdef AFS_DEBUG_TRACE
1478             DWORD gle = GetLastError();
1479
1480             AFSDbgPrint( L"NPGetConnection Failed to get connection from file system for local %s gle 0x%x\n",
1481                          wchLocalName, gle);
1482 #endif
1483             try_return( dwStatus = WN_NOT_CONNECTED);
1484         }
1485
1486         //
1487         // IOCTL_AFS_GET_CONNECTION returns a counted string
1488         //
1489
1490         if( lpRemoteName == NULL ||
1491             *lpBufferSize + sizeof( WCHAR) > dwPassedSize)
1492         {
1493
1494             *lpBufferSize += sizeof( WCHAR);
1495
1496             try_return( dwStatus = WN_MORE_DATA);
1497         }
1498
1499         memcpy( lpRemoteName,
1500                 (void *)pConnectCB,
1501                 *lpBufferSize);
1502
1503         lpRemoteName[ *lpBufferSize/sizeof( WCHAR)] = L'\0';
1504
1505         *lpBufferSize += sizeof( WCHAR);
1506
1507 #ifdef AFS_DEBUG_TRACE
1508         AFSDbgPrint( L"NPGetConnection local %s remote %s\n",
1509                      wchLocalName,
1510                      lpRemoteName);
1511 #endif
1512         dwStatus = WN_SUCCESS;
1513
1514 try_exit:
1515
1516         if ( hControlDevice != NULL)
1517         {
1518
1519             CloseHandle( hControlDevice);
1520         }
1521
1522         if( pConnectCB != NULL)
1523         {
1524
1525             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1526         }
1527     }
1528
1529     return dwStatus;
1530 }
1531
1532 DWORD
1533 APIENTRY
1534 NPGetConnection3( IN     LPCWSTR lpLocalName,
1535                   IN     DWORD dwLevel,
1536                   OUT    LPVOID lpBuffer,
1537                   IN OUT LPDWORD lpBufferSize)
1538 {
1539
1540     DWORD    dwStatus = WN_NOT_CONNECTED;
1541     WCHAR    wchLocalName[3];
1542     WCHAR    wchSubstName[1024 + 26];
1543     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
1544     DWORD    dwError = 0;
1545     DWORD    dwBufferSize = 0;
1546     HANDLE   hControlDevice = NULL;
1547     DWORD    dwPassedSize;
1548     DWORD   *pConnectState =(DWORD *)lpBuffer;
1549
1550     __Enter
1551     {
1552
1553         if ( NPIsFSDisabled())
1554         {
1555
1556 #ifdef AFS_DEBUG_TRACE
1557             AFSDbgPrint( L"NPGetConnection3 AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
1558 #endif
1559
1560             try_return( dwStatus = WN_NOT_CONNECTED);
1561         }
1562
1563         if( lstrlen( lpLocalName) == 0)
1564         {
1565 #ifdef AFS_DEBUG_TRACE
1566             AFSDbgPrint( L"NPGetConnection3 No local name, returning WN_BAD_LOCALNAME\n");
1567 #endif
1568             try_return( dwStatus = WN_BAD_LOCALNAME);
1569         }
1570
1571         //
1572         // LanMan NPGetConnection3 only responds to level 1
1573         //
1574
1575         if ( dwLevel != 0x1)
1576         {
1577 #ifdef AFS_DEBUG_TRACE
1578             AFSDbgPrint( L"NPGetConnection3 Level 0x%X returning WN_BAD_LEVEL\n", dwLevel);
1579 #endif
1580             try_return( dwStatus = WN_BAD_LEVEL);
1581         }
1582
1583         if ( lpBufferSize == NULL)
1584         {
1585 #ifdef AFS_DEBUG_TRACE
1586             AFSDbgPrint( L"NPGetConnection3 No output size, returning WN_BAD_VALUE\n");
1587 #endif
1588             try_return( dwStatus = WN_BAD_VALUE);
1589         }
1590
1591         dwPassedSize = *lpBufferSize;
1592
1593         if ( dwPassedSize == 0 ||
1594              lpBuffer == NULL)
1595         {
1596
1597             *lpBufferSize = sizeof( DWORD);
1598
1599             try_return( dwStatus = WN_MORE_DATA);
1600         }
1601
1602         if ( !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName), &dwStatus))
1603         {
1604             wchLocalName[0] = towupper(lpLocalName[0]);
1605             wchLocalName[1] = L':';
1606             wchLocalName[2] = L'\0';
1607
1608 #ifdef AFS_DEBUG_TRACE
1609             AFSDbgPrint( L"NPGetConnection3 Requesting connection for %s level 0x%X\n",
1610                          wchLocalName,
1611                          dwLevel);
1612 #endif
1613         }
1614         else
1615         {
1616
1617             ReadServerNameString();
1618
1619             if ( wchSubstName[0] != L'\\' &&
1620                  wchSubstName[1] == L':')
1621             {
1622
1623                 wchLocalName[0] = towupper(wchSubstName[0]);
1624                 wchLocalName[1] = L':';
1625                 wchLocalName[2] = L'\0';
1626
1627 #ifdef AFS_DEBUG_TRACE
1628                 AFSDbgPrint( L"NPGetConnection3 Requesting connection for drive substitution %s -> %s level 0x%x\n",
1629                              wchSubstName,
1630                              wchLocalName,
1631                              dwLevel);
1632 #endif
1633             }
1634             else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
1635                       ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
1636                         wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
1637             {
1638
1639 #ifdef AFS_DEBUG_TRACE
1640                 AFSDbgPrint( L"NPGetConnection3 drive substitution %s is AFS return connected\n",
1641                              wchSubstName);
1642 #endif
1643                 *pConnectState = WNGETCON_CONNECTED;
1644
1645                 *lpBufferSize = sizeof( DWORD);
1646
1647                 try_return( dwStatus = WN_SUCCESS);
1648             }
1649             else
1650             {
1651
1652 #ifdef AFS_DEBUG_TRACE
1653                 AFSDbgPrint( L"NPGetConnection3 drive substitution %s is not AFS return not connected\n",
1654                              wchSubstName);
1655 #endif
1656                 try_return( dwStatus = WN_NOT_CONNECTED);
1657             }
1658         }
1659
1660         dwBufferSize = 0x1000;
1661
1662         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1663
1664         if( pConnectCB == NULL)
1665         {
1666
1667             try_return( dwStatus = WN_OUT_OF_MEMORY);
1668         }
1669
1670         pConnectCB->LocalName = towupper(wchLocalName[0]);
1671
1672         pConnectCB->RemoteNameLength = 0;
1673
1674         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1675
1676         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1677
1678 #ifdef AFS_DEBUG_TRACE
1679         AFSDbgPrint( L"NPGetConnection3 Retrieved authentication id %08lX-%08lX\n",
1680                      pConnectCB->AuthenticationId.HighPart,
1681                      pConnectCB->AuthenticationId.LowPart);
1682 #endif
1683
1684         hControlDevice = OpenRedirector();
1685
1686         if( hControlDevice == NULL)
1687         {
1688
1689 #ifdef AFS_DEBUG_TRACE
1690             AFSDbgPrint( L"NPGetConnection3 OpenRedirector failure, returning WN_NET_ERROR\n");
1691 #endif
1692
1693             try_return( dwStatus = WN_NET_ERROR);
1694         }
1695
1696         dwError = DeviceIoControl( hControlDevice,
1697                                    IOCTL_AFS_GET_CONNECTION,
1698                                    pConnectCB,
1699                                    dwBufferSize,
1700                                    pConnectCB,
1701                                    dwBufferSize,
1702                                    &dwBufferSize,
1703                                    NULL);
1704
1705         if( !dwError)
1706         {
1707 #ifdef AFS_DEBUG_TRACE
1708             DWORD gle = GetLastError();
1709
1710             AFSDbgPrint( L"NPGetConnection3 Failed to get connection from file system for local %s gle 0x%x\n",
1711                          wchLocalName, gle);
1712 #endif
1713             try_return( dwStatus = WN_NOT_CONNECTED);
1714         }
1715
1716         *lpBufferSize = sizeof( DWORD);
1717
1718         if( sizeof( DWORD) > dwPassedSize)
1719         {
1720
1721             try_return( dwStatus = WN_MORE_DATA);
1722         }
1723
1724         *pConnectState = WNGETCON_CONNECTED;
1725
1726 #ifdef AFS_DEBUG_TRACE
1727         AFSDbgPrint( L"NPGetConnection3 local %s connect-state 0x%x\n",
1728                      wchLocalName,
1729                      *pConnectState);
1730 #endif
1731         dwStatus = WN_SUCCESS;
1732
1733 try_exit:
1734
1735         if ( hControlDevice != NULL)
1736         {
1737
1738             CloseHandle( hControlDevice);
1739         }
1740
1741         if( pConnectCB != NULL)
1742         {
1743
1744             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1745         }
1746     }
1747
1748     return dwStatus;
1749 }
1750
1751 DWORD
1752 APIENTRY
1753 NPGetConnectionPerformance( LPCWSTR lpRemoteName,
1754                             LPNETCONNECTINFOSTRUCT lpNetConnectInfo)
1755 {
1756
1757     DWORD dwReturn = WN_SUCCESS;
1758     AFSNetworkProviderConnectionCB *pConnectCB = NULL;
1759     DWORD dwBufferSize = 0;
1760     HANDLE hControlDevice = NULL;
1761     DWORD dwError = 0;
1762
1763     __Enter
1764     {
1765
1766         if ( NPIsFSDisabled())
1767         {
1768
1769 #ifdef AFS_DEBUG_TRACE
1770             AFSDbgPrint( L"NPGetConnectionPerformance AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
1771 #endif
1772
1773             return WN_NO_NETWORK;
1774         }
1775
1776         AFSDbgPrint( L"NPGetConnectionPerformance Entry for remote connection %S\n",
1777                      lpRemoteName);
1778
1779         dwBufferSize = 0x1000;
1780
1781         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1782
1783         if( pConnectCB == NULL)
1784         {
1785             try_return( dwReturn = WN_OUT_OF_MEMORY);
1786         }
1787
1788         pConnectCB->RemoteNameLength = wcslen( lpRemoteName) * sizeof( WCHAR);
1789
1790         StringCbCopy( pConnectCB->RemoteName,
1791                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
1792                       lpRemoteName);
1793
1794         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1795
1796         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1797
1798         hControlDevice = OpenRedirector();
1799
1800         if( hControlDevice == NULL)
1801         {
1802             AFSDbgPrint( L"NPGetConnectionPerformance OpenRedirector failure, returning WN_NET_ERROR\n");
1803
1804             try_return( dwReturn = WN_NET_ERROR);
1805         }
1806
1807         dwError = DeviceIoControl( hControlDevice,
1808                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
1809                                    pConnectCB,
1810                                    dwBufferSize,
1811                                    pConnectCB,
1812                                    dwBufferSize,
1813                                    &dwBufferSize,
1814                                    NULL);
1815
1816         if( !dwError)
1817         {
1818 #ifdef AFS_DEBUG_TRACE
1819             DWORD gle = GetLastError();
1820
1821             AFSDbgPrint( L"NPGetConnectionPerformance Failed to get connection info from file system for remote %S gle 0x%x\n",
1822                          lpRemoteName,
1823                          gle);
1824 #endif
1825             try_return( dwReturn = WN_NOT_CONNECTED);
1826         }
1827
1828         lpNetConnectInfo->dwFlags = WNCON_DYNAMIC;
1829
1830         lpNetConnectInfo->dwSpeed = 500;
1831
1832         lpNetConnectInfo->dwDelay = 0;
1833
1834         lpNetConnectInfo->dwOptDataSize = 0x1000;
1835
1836         AFSDbgPrint( L"NPGetConnectionPerformance Successfully returned information for remote connection %S\n",
1837                      lpRemoteName);
1838
1839 try_exit:
1840
1841         if ( hControlDevice != NULL)
1842         {
1843             CloseHandle( hControlDevice);
1844         }
1845
1846         if( pConnectCB != NULL)
1847         {
1848             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1849         }
1850     }
1851
1852     return dwReturn;
1853 }
1854
1855 static LPCWSTR
1856 GetUsageString( DWORD dwUsage)
1857 {
1858     static WCHAR Buffer[128] = L"";
1859     //
1860     // RESOURCEUSAGE_CONNECTABLE   0x00000001
1861     // RESOURCEUSAGE_CONTAINER     0x00000002
1862     // RESOURCEUSAGE_NOLOCALDEVICE 0x00000004
1863     // RESOURCEUSAGE_SIBLING       0x00000008
1864     // RESOURCEUSAGE_ATTACHED      0x00000010
1865     // RESOURCEUSAGE_ALL           (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED)
1866     // RESOURCEUSAGE_RESERVED      0x80000000
1867     //
1868
1869     Buffer[0] = L'\0';
1870
1871     if ( dwUsage == RESOURCEUSAGE_ALL )
1872     {
1873         return L"ALL";
1874     }
1875
1876     if ( dwUsage == 0 )
1877     {
1878         return L"NONE";
1879     }
1880
1881     if ( dwUsage & RESOURCEUSAGE_CONNECTABLE )
1882     {
1883         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTABLE|");
1884     }
1885
1886     if ( dwUsage & RESOURCEUSAGE_CONTAINER )
1887     {
1888         StringCbCat( Buffer, sizeof(Buffer), L"CONTAINER|");
1889     }
1890
1891     if ( dwUsage & RESOURCEUSAGE_NOLOCALDEVICE )
1892     {
1893         StringCbCat( Buffer, sizeof(Buffer), L"NOLOCALDEVICE|");
1894     }
1895
1896     if ( dwUsage & RESOURCEUSAGE_SIBLING )
1897     {
1898         StringCbCat( Buffer, sizeof(Buffer), L"SIBLING|");
1899     }
1900
1901     if ( dwUsage & RESOURCEUSAGE_ATTACHED )
1902     {
1903         StringCbCat( Buffer, sizeof(Buffer), L"ATTACHED|");
1904     }
1905
1906     if ( dwUsage & RESOURCEUSAGE_RESERVED )
1907     {
1908         StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|");
1909     }
1910
1911     if ( dwUsage & ~(RESOURCEUSAGE_ALL|RESOURCEUSAGE_NOLOCALDEVICE|RESOURCEUSAGE_SIBLING|RESOURCEUSAGE_RESERVED) )
1912     {
1913         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
1914     }
1915
1916     Buffer[lstrlen(Buffer)-1] = L'\0';
1917
1918     return Buffer;
1919 }
1920
1921 static LPCWSTR
1922 GetTypeString( DWORD dwType)
1923 {
1924     static WCHAR Buffer[128] = L"";
1925
1926     //
1927     // RESOURCETYPE_ANY        0x00000000
1928     // RESOURCETYPE_DISK       0x00000001
1929     // RESOURCETYPE_PRINT      0x00000002
1930     // RESOURCETYPE_RESERVED   0x00000008
1931     // RESOURCETYPE_UNKNOWN    0xFFFFFFFF
1932     //
1933
1934     Buffer[0] = L'\0';
1935
1936     if ( dwType == RESOURCETYPE_ANY )
1937     {
1938         return L"ANY";
1939     }
1940
1941     if ( dwType == RESOURCETYPE_UNKNOWN )
1942     {
1943         return L"UNKNOWN";
1944     }
1945
1946     if ( dwType & RESOURCETYPE_DISK )
1947     {
1948         StringCbCat( Buffer, sizeof(Buffer), L"DISK|");
1949     }
1950
1951     if ( dwType & RESOURCETYPE_PRINT )
1952     {
1953         StringCbCat( Buffer, sizeof(Buffer), L"PRINT|");
1954     }
1955
1956     if ( dwType & RESOURCETYPE_RESERVED )
1957     {
1958         StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|");
1959     }
1960
1961     if ( dwType & ~(RESOURCETYPE_DISK|RESOURCETYPE_PRINT|RESOURCETYPE_RESERVED) )
1962     {
1963         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
1964     }
1965
1966     Buffer[lstrlen(Buffer)-1] = L'\0';
1967
1968     return Buffer;
1969 }
1970
1971 static LPCWSTR
1972 GetScopeString( DWORD dwScope)
1973 {
1974     static WCHAR Buffer[128] = L"";
1975
1976     //
1977     // RESOURCE_CONNECTED      0x00000001
1978     // RESOURCE_GLOBALNET      0x00000002
1979     // RESOURCE_REMEMBERED     0x00000003
1980     // RESOURCE_RECENT         0x00000004
1981     // RESOURCE_CONTEXT        0x00000005
1982     //
1983
1984     Buffer[0] = L'\0';
1985
1986     if ( dwScope == RESOURCE_CONNECTED )
1987     {
1988         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTED|");
1989     }
1990
1991     if ( dwScope == RESOURCE_GLOBALNET )
1992     {
1993         StringCbCat( Buffer, sizeof(Buffer), L"GLOBALNET|");
1994     }
1995
1996     if ( dwScope == RESOURCE_REMEMBERED )
1997     {
1998         StringCbCat( Buffer, sizeof(Buffer), L"REMEMBERED|");
1999     }
2000
2001     if ( dwScope == RESOURCE_RECENT )
2002     {
2003         StringCbCat( Buffer, sizeof(Buffer), L"RECENT|");
2004     }
2005
2006     if ( dwScope == RESOURCE_CONTEXT )
2007     {
2008         StringCbCat( Buffer, sizeof(Buffer), L"CONTEXT|");
2009     }
2010
2011     if ( dwScope & ~(RESOURCE_CONNECTED|RESOURCE_GLOBALNET|RESOURCE_REMEMBERED|RESOURCE_RECENT|RESOURCE_CONTEXT) )
2012     {
2013         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
2014     }
2015
2016     Buffer[lstrlen(Buffer)-1] = L'\0';
2017
2018     return Buffer;
2019 }
2020
2021 static LPCWSTR
2022 GetDisplayString( DWORD dwDisplay)
2023 {
2024     //
2025     // RESOURCEDISPLAYTYPE_GENERIC        0x00000000
2026     // RESOURCEDISPLAYTYPE_DOMAIN         0x00000001
2027     // RESOURCEDISPLAYTYPE_SERVER         0x00000002
2028     // RESOURCEDISPLAYTYPE_SHARE          0x00000003
2029     // RESOURCEDISPLAYTYPE_FILE           0x00000004
2030     // RESOURCEDISPLAYTYPE_GROUP          0x00000005
2031     // RESOURCEDISPLAYTYPE_NETWORK        0x00000006
2032     // RESOURCEDISPLAYTYPE_ROOT           0x00000007
2033     // RESOURCEDISPLAYTYPE_SHAREADMIN     0x00000008
2034     // RESOURCEDISPLAYTYPE_DIRECTORY      0x00000009
2035     // RESOURCEDISPLAYTYPE_TREE           0x0000000A
2036     // RESOURCEDISPLAYTYPE_NDSCONTAINER   0x0000000B
2037     //
2038
2039     switch ( dwDisplay ) {
2040     case RESOURCEDISPLAYTYPE_GENERIC:
2041         return L"GENERIC";
2042     case RESOURCEDISPLAYTYPE_DOMAIN:
2043         return L"DOMAIN";
2044     case RESOURCEDISPLAYTYPE_SERVER:
2045         return L"SERVER";
2046     case RESOURCEDISPLAYTYPE_SHARE:
2047         return L"SHARE";
2048     case RESOURCEDISPLAYTYPE_FILE:
2049         return L"FILE";
2050     case RESOURCEDISPLAYTYPE_GROUP:
2051         return L"GROUP";
2052     case RESOURCEDISPLAYTYPE_NETWORK:
2053         return L"NETWORK";
2054     case RESOURCEDISPLAYTYPE_ROOT:
2055         return L"ROOT";
2056     case RESOURCEDISPLAYTYPE_SHAREADMIN:
2057         return L"SHAREADMIN";
2058     case RESOURCEDISPLAYTYPE_DIRECTORY:
2059         return L"DIRECTORY";
2060     case RESOURCEDISPLAYTYPE_TREE:
2061         return L"TREE";
2062     case RESOURCEDISPLAYTYPE_NDSCONTAINER:
2063         return L"NDSCONTAINER";
2064     default:
2065         return L"UNKNOWN";
2066     }
2067 }
2068
2069 DWORD
2070 APIENTRY
2071 NPOpenEnum( DWORD          dwScope,
2072             DWORD          dwType,
2073             DWORD          dwUsage,
2074             LPNETRESOURCE  lpNetResource,
2075             LPHANDLE       lphEnum )
2076 {
2077
2078     DWORD   dwStatus = WN_SUCCESS;
2079     AFSEnumerationCB *pEnumCB = NULL;
2080
2081 #ifdef AFS_DEBUG_TRACE
2082     if ( lpNetResource == NULL)
2083     {
2084         AFSDbgPrint( L"NPOpenEnum Scope %s Type %s Usage %s NetResource: (Null)\n",
2085                      GetScopeString(dwScope), GetTypeString(dwType), GetUsageString(dwUsage));
2086     }
2087     else
2088     {
2089         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",
2090                      GetScopeString(dwScope),
2091                      GetTypeString(dwType),
2092                      GetUsageString(dwUsage),
2093                      lpNetResource,
2094                      GetScopeString(lpNetResource->dwScope),
2095                      GetTypeString(lpNetResource->dwType),
2096                      GetDisplayString(lpNetResource->dwDisplayType),
2097                      GetUsageString(lpNetResource->dwUsage),
2098                      lpNetResource->lpLocalName,
2099                      lpNetResource->lpRemoteName,
2100                      lpNetResource->lpComment);
2101     }
2102 #endif
2103
2104     if ( dwUsage == 0 )
2105     {
2106         dwUsage = RESOURCEUSAGE_ALL;
2107     }
2108
2109 #if 0
2110     if ( dwType == 0 || dwType == RESOURCEUSAGE_ATTACHED)
2111     {
2112         dwType |= RESOURCETYPE_DISK | RESOURCETYPE_PRINT;
2113     }
2114 #endif
2115
2116     *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( AFSEnumerationCB));
2117
2118     if( *lphEnum == NULL)
2119     {
2120
2121         return WN_OUT_OF_MEMORY;
2122     }
2123
2124     pEnumCB = (AFSEnumerationCB *)*lphEnum;
2125
2126     pEnumCB->CurrentIndex = 0;
2127
2128     pEnumCB->Type = dwType;
2129
2130     switch( dwScope )
2131     {
2132         case RESOURCE_CONNECTED:
2133         {
2134
2135             pEnumCB->Scope = RESOURCE_CONNECTED;
2136
2137             break;
2138         }
2139
2140         case RESOURCE_CONTEXT:
2141         {
2142
2143             pEnumCB->Scope = RESOURCE_CONTEXT;
2144
2145             break;
2146         }
2147
2148         case RESOURCE_GLOBALNET:
2149         {
2150
2151             if( lpNetResource != NULL &&
2152                 lpNetResource->lpRemoteName != NULL)
2153             {
2154
2155                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2156
2157                 if( pEnumCB->RemoteName == NULL)
2158                 {
2159
2160                     dwStatus = WN_OUT_OF_MEMORY;
2161                     HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2162                     *lphEnum = NULL;
2163                 }
2164                 else
2165                 {
2166
2167                     StringCbCopy( pEnumCB->RemoteName,
2168                                   0x1000,
2169                                   lpNetResource->lpRemoteName);
2170
2171                 }
2172             }
2173
2174             pEnumCB->Scope = RESOURCE_GLOBALNET;
2175
2176             break;
2177         }
2178
2179         default:
2180
2181 #ifdef AFS_DEBUG_TRACE
2182             AFSDbgPrint( L"NPOpenEnum Processing (Scope %s 0x%x) Type %s Usage %s, returning WN_NOT_SUPPORTED\n",
2183                          GetScopeString(dwScope), dwScope, GetTypeString(dwType), GetUsageString(dwUsage));
2184 #endif
2185
2186             dwStatus  = WN_NOT_SUPPORTED;
2187             HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2188             *lphEnum = NULL;
2189
2190             break;
2191     }
2192
2193     return dwStatus;
2194 }
2195
2196
2197 DWORD
2198 APIENTRY
2199 NPEnumResource( HANDLE  hEnum,
2200                 LPDWORD lpcCount,
2201                 LPVOID  lpBuffer,
2202                 LPDWORD lpBufferSize)
2203 {
2204
2205     DWORD            dwStatus = WN_NO_MORE_ENTRIES; //WN_SUCCESS;
2206     ULONG            dwCopyBytes;
2207     ULONG            EntriesCopied;
2208     ULONG            EntriesRequested;
2209     ULONG            dwIndex;
2210     LPNETRESOURCE    pNetResource;
2211     ULONG            SpaceNeeded;
2212     ULONG            SpaceAvailable;
2213     PWCHAR           StringZone;
2214     AFSNetworkProviderConnectionCB *pConnectionCB = NULL;
2215     void            *pConnectionCBBase = NULL;
2216     DWORD            dwError = 0;
2217     UNICODE_STRING   uniRemoteName;
2218     HANDLE           hControlDevice = NULL;
2219     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2220
2221     __Enter
2222     {
2223
2224         if ( lpBufferSize == NULL)
2225         {
2226 #ifdef AFS_DEBUG_TRACE
2227             AFSDbgPrint( L"NPEnumResource No output size, returning WN_BAD_VALUE\n");
2228 #endif
2229             try_return( dwStatus = WN_BAD_VALUE);
2230         }
2231
2232         ReadProviderNameString();
2233
2234         pNetResource = (LPNETRESOURCE) lpBuffer;
2235         SpaceAvailable = *lpBufferSize;
2236         EntriesRequested = *lpcCount;
2237         *lpcCount = EntriesCopied = 0;
2238         StringZone = (PWCHAR) ((char *)lpBuffer + *lpBufferSize);
2239
2240 #ifdef AFS_DEBUG_TRACE
2241         AFSDbgPrint( L"NPEnumResource Processing Remote name %s Scope %s Type %s Usage %s Index %d SpaceAvailable 0x%lX RequestedEntries %lu\n",
2242                      pEnumCB->RemoteName ? pEnumCB->RemoteName : L"(Null)",
2243                      GetScopeString(pEnumCB->Scope),
2244                      GetTypeString(pEnumCB->Type),
2245                      GetUsageString(pEnumCB->Type),
2246                      pEnumCB->CurrentIndex,
2247                      SpaceAvailable,
2248                      EntriesRequested);
2249 #endif
2250
2251         if ( NPIsFSDisabled())
2252         {
2253
2254 #ifdef AFS_DEBUG_TRACE
2255             AFSDbgPrint( L"NPEnumResource AFSRDFS is disabled, returning WN_NO_MORE_ENTRIES\n");
2256 #endif
2257
2258             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2259         }
2260
2261         pConnectionCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
2262
2263         if( pConnectionCB == NULL)
2264         {
2265
2266 #ifdef AFS_DEBUG_TRACE
2267             AFSDbgPrint( L"NPEnumResource Out of Memory\n");
2268 #endif
2269
2270             try_return( dwStatus = WN_OUT_OF_MEMORY);
2271         }
2272
2273         pConnectionCBBase = (void *)pConnectionCB;
2274
2275         hControlDevice = OpenRedirector();
2276
2277         if( hControlDevice == NULL)
2278         {
2279
2280 #ifdef AFS_DEBUG_TRACE
2281             AFSDbgPrint( L"NPEnumResource OpenRedirector failure, returning WN_NET_ERROR\n");
2282 #endif
2283
2284             try_return( dwStatus = WN_NET_ERROR);
2285         }
2286
2287         if( pEnumCB->Type != RESOURCETYPE_ANY && pEnumCB->Type != RESOURCETYPE_DISK)
2288         {
2289
2290 #ifdef AFS_DEBUG_TRACE
2291             AFSDbgPrint( L"NPEnumResource Non-DISK queries are not supported, returning WN_NO_MORE_ENTRIES\n");
2292 #endif
2293             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2294         }
2295
2296         //
2297         // Handle the special cases here
2298         //   0. Provider Network Root
2299         //   1. Server Root
2300         //
2301
2302 #if 0
2303         if ( pEnumCB->Scope == RESOURCE_GLOBALNET)
2304         {
2305
2306             ReadServerNameString();
2307
2308             if ( pEnumCB->CurrentIndex == 0 &&
2309                  pEnumCB->RemoteName == NULL)
2310             {
2311
2312                 // Determine the space needed for this entry...
2313
2314                 SpaceNeeded = 2 * ( cbProviderNameLength + sizeof( WCHAR));
2315
2316                 uniRemoteName.Length = (USHORT)cbProviderNameLength;
2317                 uniRemoteName.MaximumLength = uniRemoteName.Length;
2318                 uniRemoteName.Buffer = wszProviderName;
2319
2320                 if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2321                 {
2322
2323                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2324
2325 #ifdef AFS_DEBUG_TRACE
2326                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2327                                  &uniRemoteName,
2328                                  *lpBufferSize);
2329 #endif
2330                     try_return( dwStatus = WN_MORE_DATA);
2331                 }
2332
2333 #ifdef AFS_DEBUG_TRACE
2334                 AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2335                              &uniRemoteName);
2336 #endif
2337
2338                 SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2339
2340                 pNetResource->dwScope       = RESOURCE_GLOBALNET;
2341                 pNetResource->dwType        = RESOURCETYPE_ANY;
2342                 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
2343                 pNetResource->dwUsage       = RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_RESERVED;
2344
2345                 // setup string area at opposite end of buffer
2346                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2347
2348                 pNetResource->lpLocalName = NULL;
2349
2350                 // copy remote name
2351                 pNetResource->lpRemoteName = StringZone;
2352
2353                 StringCbCopy( StringZone,
2354                               cbProviderNameLength + sizeof( WCHAR),
2355                               wszProviderName);
2356
2357                 StringZone += cbProviderNameLength / sizeof(WCHAR) + 1;
2358
2359                 pNetResource->lpComment = NULL;
2360
2361                 // copy provider name
2362                 pNetResource->lpProvider = StringZone;
2363                 StringCbCopy( StringZone,
2364                               cbProviderNameLength + sizeof( WCHAR),
2365                               wszProviderName);
2366
2367                 StringZone += cbProviderNameLength / sizeof( WCHAR) + 1;
2368
2369 #ifdef AFS_DEBUG_TRACE
2370                 AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2371                              pNetResource,
2372                              GetScopeString(pNetResource->dwScope),
2373                              GetTypeString(pNetResource->dwType),
2374                              GetDisplayString(pNetResource->dwDisplayType),
2375                              GetUsageString(pNetResource->dwUsage),
2376                              pNetResource->lpLocalName,
2377                              pNetResource->lpRemoteName,
2378                              pNetResource->lpComment);
2379 #endif
2380
2381                 // setup the new end of buffer
2382                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2383
2384                 EntriesCopied++;
2385
2386                 pNetResource++;
2387
2388                 // do not change the index since we did not query the redirector
2389                 pEnumCB->CurrentIndex = 0;
2390
2391                 // remember that we returned the provider name
2392                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2393
2394                 if( pEnumCB->RemoteName == NULL)
2395                 {
2396
2397                     try_return( dwStatus = WN_OUT_OF_MEMORY);
2398                 }
2399                 else
2400                 {
2401
2402                     StringCbCopy( pEnumCB->RemoteName,
2403                                    0x1000,
2404                                    wszProviderName);
2405                 }
2406             }
2407
2408             if ( pEnumCB->CurrentIndex == 0 &&
2409                  lstrlen( pEnumCB->RemoteName) == cbProviderNameLength / sizeof( WCHAR) &&
2410                  _wcsnicmp( pEnumCB->RemoteName, wszProviderName, cbProviderNameLength / sizeof( WCHAR)) == 0 &&
2411                  EntriesCopied < EntriesRequested)
2412             {
2413
2414                 //
2415                 // After the network provider entry comes the server entry
2416                 //
2417
2418                 // Determine the space needed for this entry...
2419
2420                 SpaceNeeded = cbProviderNameLength + cbServerNameUNCLength + cbServerCommentLength + 3 * sizeof( WCHAR);
2421
2422                 uniRemoteName.Length = (USHORT)cbServerNameUNCLength;
2423                 uniRemoteName.MaximumLength = uniRemoteName.Length;
2424                 uniRemoteName.Buffer = wszServerNameUNC;
2425
2426                 if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2427                 {
2428
2429                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2430
2431 #ifdef AFS_DEBUG_TRACE
2432                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2433                                  &uniRemoteName,
2434                                  *lpBufferSize);
2435 #endif
2436                     try_return( dwStatus = WN_MORE_DATA);
2437                 }
2438
2439 #ifdef AFS_DEBUG_TRACE
2440                 AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2441                              &uniRemoteName);
2442 #endif
2443
2444                 SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2445
2446                 pNetResource->dwScope       = 0;
2447                 pNetResource->dwType        = RESOURCETYPE_ANY;
2448                 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2449                 pNetResource->dwUsage       = RESOURCEUSAGE_CONTAINER;
2450
2451                 // setup string area at opposite end of buffer
2452                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2453
2454                 pNetResource->lpLocalName = NULL;
2455
2456                 // copy remote name
2457                 pNetResource->lpRemoteName = StringZone;
2458
2459                 StringCbCopy( StringZone,
2460                               cbServerNameUNCLength + sizeof( WCHAR),
2461                               wszServerNameUNC);
2462
2463                 StringZone += cbServerNameUNCLength / sizeof(WCHAR) + 1;
2464
2465                 // copy comment
2466                 pNetResource->lpComment = StringZone;
2467
2468                 StringCbCopy( StringZone,
2469                               cbServerCommentLength + sizeof( WCHAR),
2470                               wszServerComment);
2471
2472                 StringZone += cbServerCommentLength / sizeof( WCHAR) + 1;
2473
2474                 // copy provider name
2475                 pNetResource->lpProvider = StringZone;
2476                 StringCbCopy( StringZone,
2477                               cbProviderNameLength + sizeof( WCHAR),
2478                               wszProviderName);
2479
2480                 StringZone += cbProviderNameLength / sizeof( WCHAR) + 1;
2481
2482 #ifdef AFS_DEBUG_TRACE
2483                 AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2484                              pNetResource,
2485                              GetScopeString(pNetResource->dwScope),
2486                              GetTypeString(pNetResource->dwType),
2487                              GetDisplayString(pNetResource->dwDisplayType),
2488                              GetUsageString(pNetResource->dwUsage),
2489                              pNetResource->lpLocalName,
2490                              pNetResource->lpRemoteName,
2491                              pNetResource->lpComment);
2492 #endif
2493
2494                 // setup the new end of buffer
2495                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2496
2497                 EntriesCopied++;
2498
2499                 pNetResource++;
2500
2501                 // do not update the index because we did not query the redirector
2502                 pEnumCB->CurrentIndex = 0;
2503
2504                 // remember that we returned the server
2505                 StringCbCopy( pEnumCB->RemoteName,
2506                               0x1000,
2507                               wszServerNameUNC);
2508             }
2509         }
2510 #endif
2511
2512         //
2513         // Setup what we are going to ask for
2514         //
2515
2516         pConnectionCB->Scope = pEnumCB->Scope;
2517
2518         pConnectionCB->Type = pEnumCB->Type;
2519
2520         pConnectionCB->CurrentIndex = pEnumCB->CurrentIndex;
2521
2522         pConnectionCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
2523
2524         //
2525         // If this is a RESOURCE_GLOBALNET enumeration then pass down the remote name if
2526         // there is one
2527         //
2528
2529         pConnectionCB->RemoteNameLength = 0;
2530
2531         if( pEnumCB->Scope == RESOURCE_GLOBALNET &&
2532             pEnumCB->RemoteName != NULL)
2533         {
2534
2535             pConnectionCB->RemoteNameLength = wcslen( pEnumCB->RemoteName) * sizeof( WCHAR);
2536
2537             StringCbCopy( pConnectionCB->RemoteName,
2538                           (0x1000 - sizeof(AFSNetworkProviderConnectionCB)) + sizeof(WCHAR),
2539                           pEnumCB->RemoteName);
2540         }
2541
2542         pConnectionCB->AuthenticationId = AFSRetrieveAuthId();
2543
2544 #ifdef AFS_DEBUG_TRACE
2545         AFSDbgPrint( L"NPEnumResource Retrieved authentication id %08lX-%08lX\n",
2546                      pConnectionCB->AuthenticationId.HighPart,
2547                      pConnectionCB->AuthenticationId.LowPart);
2548 #endif
2549
2550         dwError = DeviceIoControl( hControlDevice,
2551                                    IOCTL_AFS_LIST_CONNECTIONS,
2552                                    pConnectionCB,
2553                                    0x1000,
2554                                    pConnectionCB,
2555                                    0x1000,
2556                                    &dwCopyBytes,
2557                                    NULL);
2558
2559         if( !dwError)
2560         {
2561 #ifdef AFS_DEBUG_TRACE
2562             DWORD gle = GetLastError();
2563
2564             AFSDbgPrint( L"NPEnumResource Failed to list connections from file system - gle 0x%x\n",
2565                          gle);
2566 #endif
2567             try_return( dwStatus = WN_NOT_CONNECTED);
2568         }
2569
2570         if( dwCopyBytes == 0)
2571         {
2572
2573 #ifdef AFS_DEBUG_TRACE
2574             AFSDbgPrint( L"NPEnumResource No More Entries\n");
2575 #endif
2576             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2577         }
2578
2579         dwIndex = pEnumCB->CurrentIndex;
2580
2581         while( EntriesCopied < EntriesRequested)
2582         {
2583
2584             uniRemoteName.Length = (USHORT)pConnectionCB->RemoteNameLength;
2585             uniRemoteName.MaximumLength = uniRemoteName.Length;
2586             uniRemoteName.Buffer = pConnectionCB->RemoteName;
2587
2588             // Determine the space needed for this entry...
2589
2590             SpaceNeeded  = 0;
2591
2592             if( pConnectionCB->LocalName != 0)
2593             {
2594
2595                 SpaceNeeded += 3 * sizeof(WCHAR);                // local name
2596             }
2597
2598             SpaceNeeded += pConnectionCB->RemoteNameLength + sizeof( WCHAR);        // remote name
2599
2600             if( pConnectionCB->CommentLength > 0)
2601             {
2602
2603                 SpaceNeeded += pConnectionCB->CommentLength + sizeof( WCHAR);           // comment
2604             }
2605
2606             SpaceNeeded += cbProviderNameLength + sizeof( WCHAR);           // provider name
2607
2608             if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2609             {
2610
2611                 if (EntriesCopied == 0) {
2612
2613                     dwStatus = WN_MORE_DATA;
2614
2615                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2616
2617 #ifdef AFS_DEBUG_TRACE
2618                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2619                                  &uniRemoteName,
2620                                  *lpBufferSize);
2621 #endif
2622
2623                 } else {
2624
2625 #ifdef AFS_DEBUG_TRACE
2626                     AFSDbgPrint( L"NPEnumResource Return SUCCESS but more entries Index %d\n",
2627                                  dwIndex);
2628 #endif
2629
2630                     dwStatus = WN_SUCCESS;
2631                 }
2632
2633                 break;
2634             }
2635
2636             SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2637
2638             pNetResource->dwScope       = pConnectionCB->Scope;
2639             pNetResource->dwType        = pConnectionCB->Type;
2640
2641             pNetResource->dwDisplayType = pConnectionCB->DisplayType;
2642
2643             if ( pNetResource->dwType == RESOURCETYPE_ANY &&
2644                  pNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE)
2645             {
2646
2647                 pNetResource->dwType = RESOURCETYPE_DISK;
2648             }
2649
2650             if ( pEnumCB->Scope == RESOURCE_CONNECTED)
2651             {
2652
2653                 pNetResource->dwUsage       = 0;
2654             }
2655             else
2656             {
2657
2658                 pNetResource->dwUsage       = pConnectionCB->Usage;
2659             }
2660
2661             // setup string area at opposite end of buffer
2662             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2663
2664             // copy local name
2665             if( pConnectionCB->LocalName != 0)
2666             {
2667
2668                 pNetResource->lpLocalName = StringZone;
2669                 *StringZone++ = towupper(pConnectionCB->LocalName);
2670                 *StringZone++ = L':';
2671                 *StringZone++ = L'\0';
2672             }
2673             else
2674             {
2675
2676                 pNetResource->lpLocalName = NULL;
2677             }
2678
2679 #ifdef AFS_DEBUG_TRACE
2680             AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2681                          &uniRemoteName);
2682 #endif
2683
2684             // copy remote name
2685             pNetResource->lpRemoteName = StringZone;
2686
2687             CopyMemory( StringZone,
2688                         pConnectionCB->RemoteName,
2689                         pConnectionCB->RemoteNameLength);
2690
2691             StringZone += (pConnectionCB->RemoteNameLength / sizeof(WCHAR));
2692
2693             *StringZone++ = L'\0';
2694
2695             // copy comment
2696             if( pConnectionCB->CommentLength > 0)
2697             {
2698
2699                 pNetResource->lpComment = StringZone;
2700
2701                 CopyMemory( StringZone,
2702                             (void *)((char *)pConnectionCB + pConnectionCB->CommentOffset),
2703                             pConnectionCB->CommentLength);
2704
2705                 StringZone += (pConnectionCB->CommentLength / sizeof(WCHAR));
2706
2707                 *StringZone++ = L'\0';
2708             }
2709             else
2710             {
2711
2712                 pNetResource->lpComment = NULL;
2713             }
2714
2715             // copy provider name
2716             pNetResource->lpProvider = StringZone;
2717             StringCbCopy( StringZone,
2718                           cbProviderNameLength + sizeof( WCHAR),
2719                           wszProviderName);
2720
2721             StringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
2722
2723 #ifdef AFS_DEBUG_TRACE
2724             AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2725                          pNetResource,
2726                          GetScopeString(pNetResource->dwScope),
2727                          GetTypeString(pNetResource->dwType),
2728                          GetDisplayString(pNetResource->dwDisplayType),
2729                          GetUsageString(pNetResource->dwUsage),
2730                          pNetResource->lpLocalName,
2731                          pNetResource->lpRemoteName,
2732                          pNetResource->lpComment);
2733 #endif
2734
2735             // setup the new end of buffer
2736             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2737
2738             EntriesCopied++;
2739
2740             pNetResource++;
2741
2742             dwIndex++;
2743
2744             dwCopyBytes -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2745                            pConnectionCB->RemoteNameLength +
2746                            pConnectionCB->CommentLength;
2747
2748             if( dwCopyBytes == 0)
2749             {
2750
2751                 dwStatus = WN_SUCCESS;
2752
2753                 break;
2754             }
2755
2756             pConnectionCB = (AFSNetworkProviderConnectionCB *)((char *)pConnectionCB +
2757                             FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2758                             pConnectionCB->RemoteNameLength +
2759                             pConnectionCB->CommentLength);
2760         }
2761
2762         *lpcCount = EntriesCopied;
2763
2764         // update entry index
2765         pEnumCB->CurrentIndex = dwIndex;
2766
2767 #ifdef AFS_DEBUG_TRACE
2768         AFSDbgPrint( L"NPEnumResource Completed Count %d Index %d\n",
2769                      EntriesCopied,
2770                      dwIndex);
2771 #endif
2772
2773 try_exit:
2774
2775         if ( hControlDevice != NULL)
2776         {
2777
2778             CloseHandle( hControlDevice);
2779         }
2780
2781         if( pConnectionCBBase != NULL)
2782         {
2783
2784             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectionCBBase);
2785         }
2786     }
2787
2788     return dwStatus;
2789 }
2790
2791 /*++
2792
2793 Routine Description:
2794
2795     This routine closes the handle for enumeration of resources.
2796
2797 Arguments:
2798
2799     hEnum  - the enumeration handle
2800
2801 Return Value:
2802
2803     WN_SUCCESS if successful, otherwise the appropriate error
2804
2805 Notes:
2806
2807     The sample only supports the notion of enumerating connected shares
2808
2809 --*/
2810
2811 DWORD APIENTRY
2812 NPCloseEnum( HANDLE hEnum )
2813 {
2814
2815     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2816
2817 #ifdef AFS_DEBUG_TRACE
2818     AFSDbgPrint( L"NPCloseEnum\n");
2819 #endif
2820
2821     if( pEnumCB->RemoteName != NULL)
2822     {
2823
2824         HeapFree( GetProcessHeap( ), 0, (PVOID) pEnumCB->RemoteName);
2825     }
2826
2827     HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum );
2828
2829     return WN_SUCCESS;
2830 }
2831
2832 DWORD APIENTRY
2833 NPGetResourceParent( LPNETRESOURCE   lpNetResource,
2834                      LPVOID  lpBuffer,
2835                      LPDWORD lpBufferSize )
2836 {
2837
2838     DWORD    dwStatus = WN_ACCESS_DENIED;
2839     WCHAR   *pwchRemoteName = NULL, *pwchSearch = NULL, *pwchSystem = NULL;
2840     LPNETRESOURCE lpOutResource = (LPNETRESOURCE) lpBuffer;
2841
2842     if ( lpNetResource == NULL)
2843     {
2844 #ifdef AFS_DEBUG_TRACE
2845         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2846 #endif
2847         return WN_MORE_DATA;
2848     }
2849
2850     if( lpNetResource->lpRemoteName == NULL)
2851     {
2852 #ifdef AFS_DEBUG_TRACE
2853         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2854 #endif
2855         return WN_BAD_NETNAME;
2856     }
2857
2858     if ( lpNetResource->dwType != 0 &&
2859          lpNetResource->dwType != RESOURCETYPE_DISK)
2860     {
2861 #ifdef AFS_DEBUG_TRACE
2862         AFSDbgPrint( L"NPGetResourceParent Bad dwType\n");
2863 #endif
2864         return WN_BAD_VALUE;
2865     }
2866
2867     if ( lpBufferSize == NULL )
2868     {
2869
2870 #ifdef AFS_DEBUG_TRACE
2871         AFSDbgPrint( L"NPGetResourceParent Null lpBufferSize\n");
2872 #endif
2873         return WN_BAD_VALUE;
2874     }
2875
2876 #ifdef AFS_DEBUG_TRACE
2877     AFSDbgPrint( L"NPGetResourceParent For remote name %s\n",
2878                  lpNetResource->lpRemoteName);
2879 #endif
2880
2881     pwchRemoteName = lpNetResource->lpRemoteName;
2882
2883     pwchSearch = pwchRemoteName + (wcslen( pwchRemoteName) - 1);
2884
2885     while( pwchSearch != pwchRemoteName)
2886     {
2887
2888         if( *pwchSearch == L'\\')
2889         {
2890
2891             *pwchSearch = L'\0';
2892
2893             break;
2894         }
2895
2896         pwchSearch--;
2897     }
2898
2899     if( pwchSearch != pwchRemoteName)
2900     {
2901
2902 #ifdef AFS_DEBUG_TRACE
2903         AFSDbgPrint( L"NPGetResourceParent Processing parent %s\n",
2904                      lpNetResource->lpRemoteName);
2905 #endif
2906
2907         dwStatus = NPGetResourceInformation( lpNetResource,
2908                                              lpBuffer,
2909                                              lpBufferSize,
2910                                              &pwchSystem);
2911     }
2912     else
2913     {
2914         if ( lpOutResource == NULL ||
2915              *lpBufferSize < sizeof( NETRESOURCE) )
2916         {
2917             *lpBufferSize = sizeof( NETRESOURCE);
2918
2919             return WN_MORE_DATA;
2920         }
2921
2922         memset( lpOutResource, 0, sizeof( NETRESOURCE));
2923
2924         return WN_SUCCESS;
2925
2926     }
2927
2928     return dwStatus;
2929 }
2930
2931 DWORD APIENTRY
2932 NPGetResourceInformation( LPNETRESOURCE   lpNetResource,
2933                           LPVOID  lpBuffer,
2934                           LPDWORD lpBufferSize,
2935                           LPWSTR  *lplpSystem )
2936 {
2937
2938     DWORD    dwStatus = WN_NOT_CONNECTED;
2939     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
2940     DWORD    dwError = 0;
2941     DWORD    dwBufferSize = 0;
2942     HANDLE   hControlDevice = NULL;
2943     NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
2944     PWCHAR   pStringZone = NULL;
2945     UNICODE_STRING uniRemoteName;
2946     DWORD    ulRequiredLen = 0;
2947     DWORD    dwPassedSize;
2948
2949
2950     __Enter
2951     {
2952         if ( lplpSystem)
2953         {
2954             *lplpSystem = NULL;
2955         }
2956
2957         ReadProviderNameString();
2958
2959         if ( NPIsFSDisabled())
2960         {
2961
2962 #ifdef AFS_DEBUG_TRACE
2963             AFSDbgPrint( L"NPGetResourceInformation AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
2964 #endif
2965
2966             try_return( dwStatus = WN_BAD_NETNAME);
2967         }
2968
2969         if ( lpNetResource == NULL ||
2970              lpBufferSize == NULL )
2971         {
2972
2973 #ifdef AFS_DEBUG_TRACE
2974             AFSDbgPrint( L"NPGetResourceInformaton Null lpNetResource or lpBufferSize\n");
2975 #endif
2976             return WN_BAD_VALUE;
2977         }
2978
2979         if( lpNetResource->lpRemoteName == NULL)
2980         {
2981 #ifdef AFS_DEBUG_TRACE
2982             AFSDbgPrint( L"NPGetResourceInformation No resource name\n");
2983 #endif
2984
2985             try_return( dwStatus = WN_NOT_CONNECTED);
2986         }
2987
2988         dwPassedSize = *lpBufferSize;
2989
2990         dwBufferSize = 0x1000;
2991
2992         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
2993
2994         if( pConnectCB == NULL)
2995         {
2996
2997             try_return( dwStatus = WN_OUT_OF_MEMORY);
2998         }
2999
3000         pConnectCB->RemoteNameLength = wcslen( lpNetResource->lpRemoteName) * sizeof( WCHAR);
3001
3002         StringCbCopy( pConnectCB->RemoteName,
3003                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
3004                       lpNetResource->lpRemoteName);
3005
3006         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
3007
3008         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
3009
3010 #ifdef AFS_DEBUG_TRACE
3011         AFSDbgPrint( L"NPGetResourceInformation Retrieved authentication id %08lX-%08lX\n",
3012                      pConnectCB->AuthenticationId.HighPart,
3013                      pConnectCB->AuthenticationId.LowPart);
3014 #endif
3015
3016         hControlDevice = OpenRedirector();
3017
3018         if( hControlDevice == NULL)
3019         {
3020
3021 #ifdef AFS_DEBUG_TRACE
3022             AFSDbgPrint( L"NPGetResourceInformation OpenRedirector failure, returning WN_NET_ERROR\n");
3023 #endif
3024
3025             try_return( dwStatus = WN_NET_ERROR);
3026         }
3027
3028         dwError = DeviceIoControl( hControlDevice,
3029                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
3030                                    pConnectCB,
3031                                    dwBufferSize,
3032                                    pConnectCB,
3033                                    dwBufferSize,
3034                                    lpBufferSize,
3035                                    NULL);
3036
3037         if( !dwError)
3038         {
3039 #ifdef AFS_DEBUG_TRACE
3040             DWORD gle = GetLastError();
3041
3042             AFSDbgPrint( L"NPGetResourceInformation Failed to get connection info from file system for local %s gle 0x%x\n",
3043                          lpNetResource->lpRemoteName, gle);
3044 #endif
3045             try_return( dwStatus = WN_BAD_NETNAME);
3046         }
3047
3048         uniRemoteName.Length = (USHORT)pConnectCB->RemoteNameLength;
3049         uniRemoteName.MaximumLength = uniRemoteName.Length;
3050         uniRemoteName.Buffer = pConnectCB->RemoteName;
3051
3052 #ifdef AFS_DEBUG_TRACE
3053         AFSDbgPrint( L"NPGetResourceInformation For remote name %wZ Scope %08lX Type %08lX Usage %08lX\n",
3054                      &uniRemoteName,
3055                      pConnectCB->Scope,
3056                      pConnectCB->Type,
3057                      pConnectCB->Usage);
3058 #endif
3059
3060         // Determine the space needed for this entry...
3061
3062         ulRequiredLen = sizeof( NETRESOURCE);
3063
3064         ulRequiredLen += pConnectCB->RemoteNameLength + sizeof( WCHAR);
3065
3066         ulRequiredLen += pConnectCB->CommentLength + sizeof( WCHAR);
3067
3068         ulRequiredLen += cbProviderNameLength + sizeof( WCHAR);
3069
3070         ulRequiredLen += pConnectCB->RemainingPathLength + sizeof( WCHAR);
3071
3072         if( pNetResource == NULL ||
3073             ulRequiredLen > dwPassedSize)
3074         {
3075
3076             *lpBufferSize = ulRequiredLen;
3077
3078             try_return( dwStatus = WN_MORE_DATA);
3079         }
3080
3081         pStringZone = (PWCHAR) ((char *)lpBuffer + sizeof( NETRESOURCE));
3082
3083         pNetResource->dwScope       = 0 /* pConnectCB->Scope*/;
3084         pNetResource->dwType        = 0 /* pConnectCB->Type */;
3085
3086         pNetResource->dwDisplayType = pConnectCB->DisplayType;
3087
3088         pNetResource->dwUsage       = pConnectCB->Usage;
3089
3090         pNetResource->lpLocalName = NULL;
3091
3092         // copy remote name
3093         pNetResource->lpRemoteName = pStringZone;
3094
3095         CopyMemory( pStringZone,
3096                     pConnectCB->RemoteName,
3097                     pConnectCB->RemoteNameLength);
3098
3099         pStringZone += (pConnectCB->RemoteNameLength / sizeof(WCHAR));
3100
3101         *pStringZone++ = L'\0';
3102
3103         // copy comment
3104         pNetResource->lpComment = pStringZone;
3105
3106         CopyMemory( pStringZone,
3107                     (void *)((char *)pConnectCB + pConnectCB->CommentOffset),
3108                     pConnectCB->CommentLength);
3109
3110         pStringZone += (pConnectCB->CommentLength / sizeof(WCHAR));
3111
3112         *pStringZone++ = L'\0';
3113
3114         // copy remaining path
3115         if (pConnectCB->RemainingPathLength > 0)
3116         {
3117             *lplpSystem = pStringZone;
3118
3119             CopyMemory( pStringZone,
3120                         (void *)((char *)pConnectCB + pConnectCB->RemainingPathOffset),
3121                         pConnectCB->RemainingPathLength);
3122
3123             pStringZone += (pConnectCB->RemainingPathLength / sizeof(WCHAR));
3124
3125             *pStringZone++ = L'\0';
3126
3127 #ifdef AFS_DEBUG_TRACE
3128             AFSDbgPrint( L"NPGetResourceInformation For remote name %s returning remaining path %s\n",
3129                          pNetResource->lpRemoteName,
3130                          *lplpSystem);
3131 #endif
3132         }
3133
3134         // copy provider name
3135         pNetResource->lpProvider = pStringZone;
3136
3137         StringCbCopy( pStringZone,
3138                       cbProviderNameLength + sizeof( WCHAR),
3139                       wszProviderName);
3140
3141         pStringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
3142
3143         *lpBufferSize = ulRequiredLen;
3144
3145         dwStatus = WN_SUCCESS;
3146
3147 try_exit:
3148
3149         if ( hControlDevice != NULL)
3150         {
3151
3152             CloseHandle( hControlDevice);
3153         }
3154
3155         if( pConnectCB != NULL)
3156         {
3157
3158             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3159         }
3160     }
3161
3162     return dwStatus;
3163 }
3164
3165 static VOID
3166 SeparateRemainingPath( WCHAR * lpConnectionName, WCHAR **lppRemainingPath)
3167 {
3168     WCHAR *pwch;
3169     WCHAR wch1, wch2;
3170     DWORD  dwCount;
3171
3172     //
3173     // at this point the lpConnectionName contains the full name.  We need to
3174     // truncate it to \\server\share and move the remaining path back one position.
3175     //
3176
3177     for ( pwch = lpConnectionName, dwCount = 0; *pwch; pwch++)
3178     {
3179         if ( *pwch == L'\\')
3180         {
3181             dwCount++;
3182         }
3183
3184         if ( dwCount == 4)
3185         {
3186             break;
3187         }
3188     }
3189
3190     if (*pwch == L'\\')
3191     {
3192         //
3193         // Found the remaining path that must be moved
3194         //
3195
3196         *lppRemainingPath = pwch + 1;
3197
3198         *pwch++ = 0;
3199
3200         //
3201         // Find the end
3202         //
3203         for ( ; *pwch; pwch++);
3204
3205         //
3206         // and work backwards moving the string
3207         // and then make sure that there is at least
3208         // a path separator.
3209         //
3210
3211         *(pwch + 1) = 0;
3212
3213         for ( ;pwch > *lppRemainingPath; pwch--)
3214         {
3215             *pwch = *(pwch - 1);
3216         }
3217
3218         *pwch = L'\\';
3219     }
3220 }
3221
3222 DWORD APIENTRY
3223 NPGetUniversalName( LPCWSTR lpLocalPath,
3224                     DWORD   dwInfoLevel,
3225                     LPVOID  lpBuffer,
3226                     LPDWORD lpBufferSize )
3227 {
3228     DWORD    dwStatus = WN_NOT_CONNECTED;
3229     WCHAR    wchLocalName[3];
3230     WCHAR   *pwchSubstName = NULL;
3231     DWORD    dwSubstNameLength = 0;
3232     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3233     DWORD    dwError = 0;
3234     DWORD    dwBufferSize = 0;
3235     DWORD    dwPassedSize = *lpBufferSize;
3236     DWORD    dwRemainingLength = *lpBufferSize;
3237     HANDLE   hControlDevice = NULL;
3238     DWORD    dwLocalPathLength = 0;
3239     DWORD    dwRemainingPathLength = 0;
3240     CHAR    *pch;
3241
3242     __Enter
3243     {
3244
3245 #ifdef AFS_DEBUG_TRACE
3246         AFSDbgPrint( L"NPGetUniversalName local path %s level 0x%X\n",
3247                      lpLocalPath ? lpLocalPath : L"(Null)",
3248                      dwInfoLevel);
3249 #endif
3250
3251         if ( NPIsFSDisabled())
3252         {
3253
3254 #ifdef AFS_DEBUG_TRACE
3255             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
3256 #endif
3257
3258             try_return( dwStatus = WN_NOT_CONNECTED);
3259         }
3260
3261         dwLocalPathLength = lstrlen( lpLocalPath);
3262
3263         dwRemainingPathLength = dwLocalPathLength - 2;          // no drive letter
3264
3265         if( dwLocalPathLength == 0)
3266         {
3267
3268 #ifdef AFS_DEBUG_TRACE
3269             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_BAD_LOCALNAME\n");
3270 #endif
3271
3272             try_return( dwStatus = WN_BAD_LOCALNAME);
3273         }
3274
3275         if( lpBuffer == NULL ||
3276             lpBufferSize == NULL)
3277         {
3278 #ifdef AFS_DEBUG_TRACE
3279             AFSDbgPrint( L"NPGetUniversalName No output buffer or size\n");
3280 #endif
3281             try_return( dwStatus = WN_BAD_VALUE);
3282         }
3283
3284         dwSubstNameLength = 4096;
3285
3286         pwchSubstName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSubstNameLength);
3287
3288         if ( pwchSubstName == NULL)
3289         {
3290 #ifdef AFS_DEBUG_TRACE
3291             AFSDbgPrint( L"NPGetUniversalName unable to allocate substitution name buffer.\n");
3292 #endif
3293             try_return( dwStatus = WN_OUT_OF_MEMORY);
3294         }
3295
3296         memset(lpBuffer, 0, dwPassedSize);
3297
3298         if ( !DriveSubstitution( lpLocalPath, pwchSubstName, dwSubstNameLength, &dwStatus))
3299         {
3300             wchLocalName[0] = towupper(lpLocalPath[0]);
3301             wchLocalName[1] = L':';
3302             wchLocalName[2] = L'\0';
3303
3304 #ifdef AFS_DEBUG_TRACE
3305             AFSDbgPrint( L"NPGetUniversalName Requesting UNC for %s level 0x%X\n",
3306                          wchLocalName,
3307                          dwInfoLevel);
3308 #endif
3309         }
3310         else
3311         {
3312
3313             ReadServerNameString();
3314
3315             if ( pwchSubstName[0] != L'\\' &&
3316                  pwchSubstName[1] == L':')
3317             {
3318
3319                 wchLocalName[0] = towupper(pwchSubstName[0]);
3320                 wchLocalName[1] = L':';
3321                 wchLocalName[2] = L'\0';
3322
3323 #ifdef AFS_DEBUG_TRACE
3324                 AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n",
3325                              pwchSubstName,
3326                              wchLocalName);
3327 #endif
3328             }
3329             else if ( _wcsnicmp( pwchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
3330                       ( pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
3331                         pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
3332             {
3333                 HRESULT hr;
3334
3335 #ifdef AFS_DEBUG_TRACE
3336                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n",
3337                              pwchSubstName,
3338                              dwInfoLevel,
3339                              dwPassedSize);
3340 #endif
3341
3342                 dwBufferSize = (wcslen( pwchSubstName) + 1) * sizeof( WCHAR);
3343
3344                 switch( dwInfoLevel)
3345                 {
3346
3347                 case UNIVERSAL_NAME_INFO_LEVEL:
3348                 {
3349
3350                     UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3351
3352                     *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize;
3353
3354                     if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3355                     {
3356
3357 #ifdef AFS_DEBUG_TRACE
3358                         AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3359 #endif
3360
3361                         try_return( dwStatus = WN_MORE_DATA);
3362                     }
3363
3364                     dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3365
3366                     pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3367
3368                     memcpy( pUniversalInfo->lpUniversalName,
3369                             pwchSubstName,
3370                             min( dwBufferSize, dwRemainingLength));
3371
3372                     dwRemainingLength -= min( dwBufferSize, dwRemainingLength);
3373
3374 #ifdef AFS_DEBUG_TRACE
3375                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3376                                  lpBuffer,
3377                                  pUniversalInfo->lpUniversalName,
3378                                  pUniversalInfo->lpUniversalName);
3379 #endif
3380
3381                     if ( dwPassedSize < *lpBufferSize)
3382                     {
3383
3384                         try_return( dwStatus = WN_MORE_DATA);
3385                     }
3386
3387                     try_return( dwStatus = WN_SUCCESS);
3388                 }
3389
3390                 case REMOTE_NAME_INFO_LEVEL:
3391                 {
3392
3393                     REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3394
3395                     *lpBufferSize = sizeof( REMOTE_NAME_INFO) + 2 * dwBufferSize + sizeof( WCHAR);
3396
3397                     if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3398                     {
3399
3400 #ifdef AFS_DEBUG_TRACE
3401                         AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3402 #endif
3403
3404                         try_return( dwStatus = WN_MORE_DATA);
3405                     }
3406
3407                     dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3408
3409                     pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3410
3411                     memcpy( pRemoteInfo->lpUniversalName,
3412                             pwchSubstName,
3413                             min( dwRemainingLength, dwBufferSize));
3414
3415                     dwRemainingLength -= min( dwRemainingLength, dwBufferSize);
3416
3417 #ifdef AFS_DEBUG_TRACE
3418                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3419                                  lpBuffer,
3420                                  pRemoteInfo->lpUniversalName,
3421                                  pRemoteInfo->lpUniversalName);
3422 #endif
3423
3424                     if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3425                     {
3426                         pRemoteInfo->lpConnectionName = (LPTSTR)((char *)pRemoteInfo->lpUniversalName + dwBufferSize);
3427
3428                         memcpy( pRemoteInfo->lpConnectionName,
3429                                 pwchSubstName,
3430                                 min( dwRemainingLength, dwBufferSize));
3431
3432                         dwRemainingLength -= min( dwRemainingLength, dwBufferSize) - sizeof( WCHAR);
3433
3434                         SeparateRemainingPath( pRemoteInfo->lpConnectionName,
3435                                                &pRemoteInfo->lpRemainingPath);
3436                     }
3437
3438 #ifdef AFS_DEBUG_TRACE
3439                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3440                                  lpBuffer,
3441                                  pRemoteInfo->lpConnectionName,
3442                                  pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3443
3444                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3445                                  lpBuffer,
3446                                  pRemoteInfo->lpRemainingPath,
3447                                  pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3448 #endif
3449
3450                     if ( dwPassedSize < *lpBufferSize)
3451                     {
3452
3453                         try_return( dwStatus = WN_MORE_DATA);
3454                     }
3455
3456                     try_return( dwStatus = WN_SUCCESS);
3457                 }
3458
3459                 default:
3460 #ifdef AFS_DEBUG_TRACE
3461                     AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3462                                  dwInfoLevel);
3463 #endif
3464                     try_return( dwStatus = WN_BAD_VALUE);
3465                 }
3466             }
3467             else
3468             {
3469
3470 #ifdef AFS_DEBUG_TRACE
3471                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is not AFS\n",
3472                              pwchSubstName);
3473 #endif
3474                 try_return( dwStatus = WN_NOT_CONNECTED);
3475             }
3476         }
3477