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