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