Windows: no drive subst for NPCancelConnection
[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
1257 #ifdef AFS_DEBUG_TRACE
1258                 AFSDbgPrint( L"NPGetConnection drive substitution %s is AFS\n",
1259                              wchSubstName);
1260 #endif
1261
1262                 if ( lpRemoteName == NULL ||
1263                      dwPassedSize == 0)
1264                 {
1265
1266                     *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
1267
1268                     try_return( dwStatus = WN_MORE_DATA);
1269
1270                 }
1271
1272                 hr = StringCbCopyN(lpRemoteName, *lpBufferSize, wchSubstName, sizeof( wchSubstName));
1273
1274                 if ( SUCCEEDED(hr))
1275                 {
1276
1277                     for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ )
1278                     {
1279                         if ( *pwch == L'\\' )
1280                         {
1281                             dwCount++;
1282
1283                             if ( dwCount == 4)
1284                             {
1285                                 *pwch = L'\0';
1286
1287                                 break;
1288                             }
1289                         }
1290
1291                     }
1292
1293                     *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR);
1294
1295                     try_return( dwStatus = WN_SUCCESS);
1296                 }
1297                 else if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER)
1298                 {
1299
1300                     *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
1301
1302                     for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ )
1303                     {
1304                         if ( *pwch == L'\\' )
1305                         {
1306                             dwCount++;
1307
1308                             if ( dwCount == 4)
1309                             {
1310                                 *pwch = L'\0';
1311
1312                                 *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR);
1313
1314                                 try_return( dwStatus = WN_SUCCESS);
1315                             }
1316                         }
1317
1318                     }
1319
1320                     try_return( dwStatus = WN_MORE_DATA);
1321                 }
1322                 else
1323                 {
1324
1325 #ifdef AFS_DEBUG_TRACE
1326                     AFSDbgPrint( L"NPGetConnection StringCbCopyN failure 0x%X\n",
1327                                  hr);
1328 #endif
1329                     try_return( dwStatus = WN_NET_ERROR);
1330                 }
1331             }
1332             else
1333             {
1334
1335 #ifdef AFS_DEBUG_TRACE
1336                 AFSDbgPrint( L"NPGetConnection drive substitution %s is not AFS\n",
1337                              wchSubstName);
1338 #endif
1339                 try_return( dwStatus = WN_NOT_CONNECTED);
1340             }
1341         }
1342
1343 #ifdef AFS_DEBUG_TRACE
1344         AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n",
1345                      wchLocalName);
1346 #endif
1347
1348         dwBufferSize = 0x1000;
1349
1350         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1351
1352         if( pConnectCB == NULL)
1353         {
1354
1355             try_return( dwStatus = WN_OUT_OF_MEMORY);
1356         }
1357
1358         pConnectCB->LocalName = towupper(wchLocalName[0]);
1359
1360         pConnectCB->RemoteNameLength = 0;
1361
1362         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1363
1364         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1365
1366 #ifdef AFS_DEBUG_TRACE
1367         AFSDbgPrint( L"NPGetConnection Retrieved authentication id %08lX-%08lX\n",
1368                      pConnectCB->AuthenticationId.HighPart,
1369                      pConnectCB->AuthenticationId.LowPart);
1370 #endif
1371
1372         hControlDevice = OpenRedirector();
1373
1374         if( hControlDevice == NULL)
1375         {
1376
1377 #ifdef AFS_DEBUG_TRACE
1378             AFSDbgPrint( L"NPGetConnection OpenRedirector failure, returning WN_NET_ERROR\n");
1379 #endif
1380
1381             try_return( dwStatus = WN_NET_ERROR);
1382         }
1383
1384         dwError = DeviceIoControl( hControlDevice,
1385                                    IOCTL_AFS_GET_CONNECTION,
1386                                    pConnectCB,
1387                                    dwBufferSize,
1388                                    pConnectCB,
1389                                    dwBufferSize,
1390                                    lpBufferSize,
1391                                    NULL);
1392
1393         if( !dwError)
1394         {
1395 #ifdef AFS_DEBUG_TRACE
1396             DWORD gle = GetLastError();
1397
1398             AFSDbgPrint( L"NPGetConnection Failed to get connection from file system for local %s gle 0x%x\n",
1399                          wchLocalName, gle);
1400 #endif
1401             try_return( dwStatus = WN_NOT_CONNECTED);
1402         }
1403
1404         //
1405         // IOCTL_AFS_GET_CONNECTION returns a counted string
1406         //
1407
1408         if( lpRemoteName == NULL ||
1409             *lpBufferSize + sizeof( WCHAR) > dwPassedSize)
1410         {
1411
1412             *lpBufferSize += sizeof( WCHAR);
1413
1414             try_return( dwStatus = WN_MORE_DATA);
1415         }
1416
1417         memcpy( lpRemoteName,
1418                 (void *)pConnectCB,
1419                 *lpBufferSize);
1420
1421         lpRemoteName[ *lpBufferSize/sizeof( WCHAR)] = L'\0';
1422
1423         *lpBufferSize += sizeof( WCHAR);
1424
1425 #ifdef AFS_DEBUG_TRACE
1426         AFSDbgPrint( L"NPGetConnection local %s remote %s\n",
1427                      wchLocalName,
1428                      lpRemoteName);
1429 #endif
1430         dwStatus = WN_SUCCESS;
1431
1432 try_exit:
1433
1434         if ( hControlDevice != NULL)
1435         {
1436
1437             CloseHandle( hControlDevice);
1438         }
1439
1440         if( pConnectCB != NULL)
1441         {
1442
1443             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1444         }
1445     }
1446
1447     return dwStatus;
1448 }
1449
1450 DWORD
1451 APIENTRY
1452 NPGetConnection3( IN     LPCWSTR lpLocalName,
1453                   IN     DWORD dwLevel,
1454                   OUT    LPVOID lpBuffer,
1455                   IN OUT LPDWORD lpBufferSize)
1456 {
1457
1458     DWORD    dwStatus = WN_NOT_CONNECTED;
1459     WCHAR    wchLocalName[3];
1460     WCHAR    wchSubstName[MAX_PATH + 1];
1461     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
1462     DWORD    dwError = 0;
1463     DWORD    dwBufferSize = 0;
1464     HANDLE   hControlDevice = NULL;
1465     DWORD    dwPassedSize;
1466     DWORD   *pConnectState =(DWORD *)lpBuffer;
1467
1468     __Enter
1469     {
1470
1471         if ( NPIsFSDisabled())
1472         {
1473
1474 #ifdef AFS_DEBUG_TRACE
1475             AFSDbgPrint( L"NPGetConnection3 AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
1476 #endif
1477
1478             try_return( dwStatus = WN_NOT_CONNECTED);
1479         }
1480
1481         if( lstrlen( lpLocalName) == 0)
1482         {
1483 #ifdef AFS_DEBUG_TRACE
1484             AFSDbgPrint( L"NPGetConnection3 No local name, returning WN_BAD_LOCALNAME\n");
1485 #endif
1486             try_return( dwStatus = WN_BAD_LOCALNAME);
1487         }
1488
1489         //
1490         // LanMan NPGetConnection3 only responds to level 1
1491         //
1492
1493         if ( dwLevel != 0x1)
1494         {
1495 #ifdef AFS_DEBUG_TRACE
1496             AFSDbgPrint( L"NPGetConnection3 Level 0x%X returning WN_BAD_LEVEL\n", dwLevel);
1497 #endif
1498             try_return( dwStatus = WN_BAD_LEVEL);
1499         }
1500
1501         if ( lpBufferSize == NULL)
1502         {
1503 #ifdef AFS_DEBUG_TRACE
1504             AFSDbgPrint( L"NPGetConnection3 No output size, returning WN_BAD_VALUE\n");
1505 #endif
1506             try_return( dwStatus = WN_BAD_VALUE);
1507         }
1508
1509         dwPassedSize = *lpBufferSize;
1510
1511         if ( dwPassedSize == 0 ||
1512              lpBuffer == NULL)
1513         {
1514
1515             *lpBufferSize = sizeof( DWORD);
1516
1517             try_return( dwStatus = WN_MORE_DATA);
1518         }
1519
1520         if ( !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName)))
1521         {
1522             wchLocalName[0] = towupper(lpLocalName[0]);
1523             wchLocalName[1] = L':';
1524             wchLocalName[2] = L'\0';
1525
1526 #ifdef AFS_DEBUG_TRACE
1527             AFSDbgPrint( L"NPGetConnection3 Requesting connection for %s level 0x%X\n",
1528                          wchLocalName,
1529                          dwLevel);
1530 #endif
1531         }
1532         else
1533         {
1534
1535             ReadServerNameString();
1536
1537             if ( wchSubstName[0] != L'\\' &&
1538                  wchSubstName[1] == L':')
1539             {
1540
1541                 wchLocalName[0] = towupper(wchSubstName[0]);
1542                 wchLocalName[1] = L':';
1543                 wchLocalName[2] = L'\0';
1544
1545 #ifdef AFS_DEBUG_TRACE
1546                 AFSDbgPrint( L"NPGetConnection3 Requesting connection for drive substitution %s -> %s level 0x%x\n",
1547                              wchSubstName,
1548                              wchLocalName,
1549                              dwLevel);
1550 #endif
1551             }
1552             else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
1553                       ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
1554                         wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
1555             {
1556
1557 #ifdef AFS_DEBUG_TRACE
1558                 AFSDbgPrint( L"NPGetConnection3 drive substitution %s is AFS return connected\n",
1559                              wchSubstName);
1560 #endif
1561                 *pConnectState = WNGETCON_CONNECTED;
1562
1563                 *lpBufferSize = sizeof( DWORD);
1564
1565                 try_return( dwStatus = WN_SUCCESS);
1566             }
1567             else
1568             {
1569
1570 #ifdef AFS_DEBUG_TRACE
1571                 AFSDbgPrint( L"NPGetConnection3 drive substitution %s is not AFS return not connected\n",
1572                              wchSubstName);
1573 #endif
1574                 try_return( dwStatus = WN_NOT_CONNECTED);
1575             }
1576         }
1577
1578         dwBufferSize = 0x1000;
1579
1580         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1581
1582         if( pConnectCB == NULL)
1583         {
1584
1585             try_return( dwStatus = WN_OUT_OF_MEMORY);
1586         }
1587
1588         pConnectCB->LocalName = towupper(wchLocalName[0]);
1589
1590         pConnectCB->RemoteNameLength = 0;
1591
1592         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1593
1594         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1595
1596 #ifdef AFS_DEBUG_TRACE
1597         AFSDbgPrint( L"NPGetConnection3 Retrieved authentication id %08lX-%08lX\n",
1598                      pConnectCB->AuthenticationId.HighPart,
1599                      pConnectCB->AuthenticationId.LowPart);
1600 #endif
1601
1602         hControlDevice = OpenRedirector();
1603
1604         if( hControlDevice == NULL)
1605         {
1606
1607 #ifdef AFS_DEBUG_TRACE
1608             AFSDbgPrint( L"NPGetConnection3 OpenRedirector failure, returning WN_NET_ERROR\n");
1609 #endif
1610
1611             try_return( dwStatus = WN_NET_ERROR);
1612         }
1613
1614         dwError = DeviceIoControl( hControlDevice,
1615                                    IOCTL_AFS_GET_CONNECTION,
1616                                    pConnectCB,
1617                                    dwBufferSize,
1618                                    pConnectCB,
1619                                    dwBufferSize,
1620                                    &dwBufferSize,
1621                                    NULL);
1622
1623         if( !dwError)
1624         {
1625 #ifdef AFS_DEBUG_TRACE
1626             DWORD gle = GetLastError();
1627
1628             AFSDbgPrint( L"NPGetConnection3 Failed to get connection from file system for local %s gle 0x%x\n",
1629                          wchLocalName, gle);
1630 #endif
1631             try_return( dwStatus = WN_NOT_CONNECTED);
1632         }
1633
1634         *lpBufferSize = sizeof( DWORD);
1635
1636         if( sizeof( DWORD) > dwPassedSize)
1637         {
1638
1639             try_return( dwStatus = WN_MORE_DATA);
1640         }
1641
1642         *pConnectState = WNGETCON_CONNECTED;
1643
1644 #ifdef AFS_DEBUG_TRACE
1645         AFSDbgPrint( L"NPGetConnection3 local %s connect-state 0x%x\n",
1646                      wchLocalName,
1647                      *pConnectState);
1648 #endif
1649         dwStatus = WN_SUCCESS;
1650
1651 try_exit:
1652
1653         if ( hControlDevice != NULL)
1654         {
1655
1656             CloseHandle( hControlDevice);
1657         }
1658
1659         if( pConnectCB != NULL)
1660         {
1661
1662             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1663         }
1664     }
1665
1666     return dwStatus;
1667 }
1668
1669 DWORD
1670 APIENTRY
1671 NPGetConnectionPerformance( LPCWSTR lpRemoteName,
1672                             LPNETCONNECTINFOSTRUCT lpNetConnectInfo)
1673 {
1674
1675     DWORD dwReturn = WN_SUCCESS;
1676     AFSNetworkProviderConnectionCB *pConnectCB = NULL;
1677     DWORD dwBufferSize = 0;
1678     HANDLE hControlDevice = NULL;
1679     DWORD dwError = 0;
1680
1681     __Enter
1682     {
1683
1684         if ( NPIsFSDisabled())
1685         {
1686
1687 #ifdef AFS_DEBUG_TRACE
1688             AFSDbgPrint( L"NPGetConnectionPerformance AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
1689 #endif
1690
1691             return WN_NO_NETWORK;
1692         }
1693
1694         AFSDbgPrint( L"NPGetConnectionPerformance Entry for remote connection %S\n",
1695                      lpRemoteName);
1696
1697         dwBufferSize = 0x1000;
1698
1699         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
1700
1701         if( pConnectCB == NULL)
1702         {
1703             try_return( dwReturn = WN_OUT_OF_MEMORY);
1704         }
1705
1706         pConnectCB->RemoteNameLength = wcslen( lpRemoteName) * sizeof( WCHAR);
1707
1708         StringCbCopy( pConnectCB->RemoteName,
1709                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
1710                       lpRemoteName);
1711
1712         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
1713
1714         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
1715
1716         hControlDevice = OpenRedirector();
1717
1718         if( hControlDevice == NULL)
1719         {
1720             AFSDbgPrint( L"NPGetConnectionPerformance OpenRedirector failure, returning WN_NET_ERROR\n");
1721
1722             try_return( dwReturn = WN_NET_ERROR);
1723         }
1724
1725         dwError = DeviceIoControl( hControlDevice,
1726                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
1727                                    pConnectCB,
1728                                    dwBufferSize,
1729                                    pConnectCB,
1730                                    dwBufferSize,
1731                                    &dwBufferSize,
1732                                    NULL);
1733
1734         if( !dwError)
1735         {
1736 #ifdef AFS_DEBUG_TRACE
1737             DWORD gle = GetLastError();
1738
1739             AFSDbgPrint( L"NPGetConnectionPerformance Failed to get connection info from file system for remote %S gle 0x%x\n",
1740                          lpRemoteName,
1741                          gle);
1742 #endif
1743             try_return( dwReturn = WN_NOT_CONNECTED);
1744         }
1745
1746         lpNetConnectInfo->dwFlags = WNCON_DYNAMIC;
1747
1748         lpNetConnectInfo->dwSpeed = 500;
1749
1750         lpNetConnectInfo->dwDelay = 0;
1751
1752         lpNetConnectInfo->dwOptDataSize = 0x1000;
1753
1754         AFSDbgPrint( L"NPGetConnectionPerformance Successfully returned information for remote connection %S\n",
1755                      lpRemoteName);
1756
1757 try_exit:
1758
1759         if ( hControlDevice != NULL)
1760         {
1761             CloseHandle( hControlDevice);
1762         }
1763
1764         if( pConnectCB != NULL)
1765         {
1766             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
1767         }
1768     }
1769
1770     return dwReturn;
1771 }
1772
1773 static LPCWSTR
1774 GetUsageString( DWORD dwUsage)
1775 {
1776     static WCHAR Buffer[128] = L"";
1777     //
1778     // RESOURCEUSAGE_CONNECTABLE   0x00000001
1779     // RESOURCEUSAGE_CONTAINER     0x00000002
1780     // RESOURCEUSAGE_NOLOCALDEVICE 0x00000004
1781     // RESOURCEUSAGE_SIBLING       0x00000008
1782     // RESOURCEUSAGE_ATTACHED      0x00000010
1783     // RESOURCEUSAGE_ALL           (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED)
1784     // RESOURCEUSAGE_RESERVED      0x80000000
1785     //
1786
1787     Buffer[0] = L'\0';
1788
1789     if ( dwUsage == RESOURCEUSAGE_ALL )
1790     {
1791         return L"ALL";
1792     }
1793
1794     if ( dwUsage == 0 )
1795     {
1796         return L"NONE";
1797     }
1798
1799     if ( dwUsage & RESOURCEUSAGE_CONNECTABLE )
1800     {
1801         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTABLE|");
1802     }
1803
1804     if ( dwUsage & RESOURCEUSAGE_CONTAINER )
1805     {
1806         StringCbCat( Buffer, sizeof(Buffer), L"CONTAINER|");
1807     }
1808
1809     if ( dwUsage & RESOURCEUSAGE_NOLOCALDEVICE )
1810     {
1811         StringCbCat( Buffer, sizeof(Buffer), L"NOLOCALDEVICE|");
1812     }
1813
1814     if ( dwUsage & RESOURCEUSAGE_SIBLING )
1815     {
1816         StringCbCat( Buffer, sizeof(Buffer), L"SIBLING|");
1817     }
1818
1819     if ( dwUsage & RESOURCEUSAGE_ATTACHED )
1820     {
1821         StringCbCat( Buffer, sizeof(Buffer), L"ATTACHED|");
1822     }
1823
1824     if ( dwUsage & RESOURCEUSAGE_RESERVED )
1825     {
1826         StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|");
1827     }
1828
1829     if ( dwUsage & ~(RESOURCEUSAGE_ALL|RESOURCEUSAGE_NOLOCALDEVICE|RESOURCEUSAGE_SIBLING|RESOURCEUSAGE_RESERVED) )
1830     {
1831         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
1832     }
1833
1834     Buffer[lstrlen(Buffer)-1] = L'\0';
1835
1836     return Buffer;
1837 }
1838
1839 static LPCWSTR
1840 GetTypeString( DWORD dwType)
1841 {
1842     static WCHAR Buffer[128] = L"";
1843
1844     //
1845     // RESOURCETYPE_ANY        0x00000000
1846     // RESOURCETYPE_DISK       0x00000001
1847     // RESOURCETYPE_PRINT      0x00000002
1848     // RESOURCETYPE_RESERVED   0x00000008
1849     // RESOURCETYPE_UNKNOWN    0xFFFFFFFF
1850     //
1851
1852     Buffer[0] = L'\0';
1853
1854     if ( dwType == RESOURCETYPE_ANY )
1855     {
1856         return L"ANY";
1857     }
1858
1859     if ( dwType == RESOURCETYPE_UNKNOWN )
1860     {
1861         return L"UNKNOWN";
1862     }
1863
1864     if ( dwType & RESOURCETYPE_DISK )
1865     {
1866         StringCbCat( Buffer, sizeof(Buffer), L"DISK|");
1867     }
1868
1869     if ( dwType & RESOURCETYPE_PRINT )
1870     {
1871         StringCbCat( Buffer, sizeof(Buffer), L"PRINT|");
1872     }
1873
1874     if ( dwType & RESOURCETYPE_RESERVED )
1875     {
1876         StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|");
1877     }
1878
1879     if ( dwType & ~(RESOURCETYPE_DISK|RESOURCETYPE_PRINT|RESOURCETYPE_RESERVED) )
1880     {
1881         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
1882     }
1883
1884     Buffer[lstrlen(Buffer)-1] = L'\0';
1885
1886     return Buffer;
1887 }
1888
1889 static LPCWSTR
1890 GetScopeString( DWORD dwScope)
1891 {
1892     static WCHAR Buffer[128] = L"";
1893
1894     //
1895     // RESOURCE_CONNECTED      0x00000001
1896     // RESOURCE_GLOBALNET      0x00000002
1897     // RESOURCE_REMEMBERED     0x00000003
1898     // RESOURCE_RECENT         0x00000004
1899     // RESOURCE_CONTEXT        0x00000005
1900     //
1901
1902     Buffer[0] = L'\0';
1903
1904     if ( dwScope == RESOURCE_CONNECTED )
1905     {
1906         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTED|");
1907     }
1908
1909     if ( dwScope == RESOURCE_GLOBALNET )
1910     {
1911         StringCbCat( Buffer, sizeof(Buffer), L"GLOBALNET|");
1912     }
1913
1914     if ( dwScope == RESOURCE_REMEMBERED )
1915     {
1916         StringCbCat( Buffer, sizeof(Buffer), L"REMEMBERED|");
1917     }
1918
1919     if ( dwScope == RESOURCE_RECENT )
1920     {
1921         StringCbCat( Buffer, sizeof(Buffer), L"RECENT|");
1922     }
1923
1924     if ( dwScope == RESOURCE_CONTEXT )
1925     {
1926         StringCbCat( Buffer, sizeof(Buffer), L"CONTEXT|");
1927     }
1928
1929     if ( dwScope & ~(RESOURCE_CONNECTED|RESOURCE_GLOBALNET|RESOURCE_REMEMBERED|RESOURCE_RECENT|RESOURCE_CONTEXT) )
1930     {
1931         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
1932     }
1933
1934     Buffer[lstrlen(Buffer)-1] = L'\0';
1935
1936     return Buffer;
1937 }
1938
1939 static LPCWSTR
1940 GetDisplayString( DWORD dwDisplay)
1941 {
1942     //
1943     // RESOURCEDISPLAYTYPE_GENERIC        0x00000000
1944     // RESOURCEDISPLAYTYPE_DOMAIN         0x00000001
1945     // RESOURCEDISPLAYTYPE_SERVER         0x00000002
1946     // RESOURCEDISPLAYTYPE_SHARE          0x00000003
1947     // RESOURCEDISPLAYTYPE_FILE           0x00000004
1948     // RESOURCEDISPLAYTYPE_GROUP          0x00000005
1949     // RESOURCEDISPLAYTYPE_NETWORK        0x00000006
1950     // RESOURCEDISPLAYTYPE_ROOT           0x00000007
1951     // RESOURCEDISPLAYTYPE_SHAREADMIN     0x00000008
1952     // RESOURCEDISPLAYTYPE_DIRECTORY      0x00000009
1953     // RESOURCEDISPLAYTYPE_TREE           0x0000000A
1954     // RESOURCEDISPLAYTYPE_NDSCONTAINER   0x0000000B
1955     //
1956
1957     switch ( dwDisplay ) {
1958     case RESOURCEDISPLAYTYPE_GENERIC:
1959         return L"GENERIC";
1960     case RESOURCEDISPLAYTYPE_DOMAIN:
1961         return L"DOMAIN";
1962     case RESOURCEDISPLAYTYPE_SERVER:
1963         return L"SERVER";
1964     case RESOURCEDISPLAYTYPE_SHARE:
1965         return L"SHARE";
1966     case RESOURCEDISPLAYTYPE_FILE:
1967         return L"FILE";
1968     case RESOURCEDISPLAYTYPE_GROUP:
1969         return L"GROUP";
1970     case RESOURCEDISPLAYTYPE_NETWORK:
1971         return L"NETWORK";
1972     case RESOURCEDISPLAYTYPE_ROOT:
1973         return L"ROOT";
1974     case RESOURCEDISPLAYTYPE_SHAREADMIN:
1975         return L"SHAREADMIN";
1976     case RESOURCEDISPLAYTYPE_DIRECTORY:
1977         return L"DIRECTORY";
1978     case RESOURCEDISPLAYTYPE_TREE:
1979         return L"TREE";
1980     case RESOURCEDISPLAYTYPE_NDSCONTAINER:
1981         return L"NDSCONTAINER";
1982     default:
1983         return L"UNKNOWN";
1984     }
1985 }
1986
1987 DWORD
1988 APIENTRY
1989 NPOpenEnum( DWORD          dwScope,
1990             DWORD          dwType,
1991             DWORD          dwUsage,
1992             LPNETRESOURCE  lpNetResource,
1993             LPHANDLE       lphEnum )
1994 {
1995
1996     DWORD   dwStatus = WN_SUCCESS;
1997     AFSEnumerationCB *pEnumCB = NULL;
1998
1999 #ifdef AFS_DEBUG_TRACE
2000     if ( lpNetResource == NULL)
2001     {
2002         AFSDbgPrint( L"NPOpenEnum Scope %s Type %s Usage %s NetResource: (Null)\n",
2003                      GetScopeString(dwScope), GetTypeString(dwType), GetUsageString(dwUsage));
2004     }
2005     else
2006     {
2007         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",
2008                      GetScopeString(dwScope),
2009                      GetTypeString(dwType),
2010                      GetUsageString(dwUsage),
2011                      lpNetResource,
2012                      GetScopeString(lpNetResource->dwScope),
2013                      GetTypeString(lpNetResource->dwType),
2014                      GetDisplayString(lpNetResource->dwDisplayType),
2015                      GetUsageString(lpNetResource->dwUsage),
2016                      lpNetResource->lpLocalName,
2017                      lpNetResource->lpRemoteName,
2018                      lpNetResource->lpComment);
2019     }
2020 #endif
2021
2022     if ( dwUsage == 0 )
2023     {
2024         dwUsage = RESOURCEUSAGE_ALL;
2025     }
2026
2027 #if 0
2028     if ( dwType == 0 || dwType == RESOURCEUSAGE_ATTACHED)
2029     {
2030         dwType |= RESOURCETYPE_DISK | RESOURCETYPE_PRINT;
2031     }
2032 #endif
2033
2034     *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( AFSEnumerationCB));
2035
2036     if( *lphEnum == NULL)
2037     {
2038
2039         return WN_OUT_OF_MEMORY;
2040     }
2041
2042     pEnumCB = (AFSEnumerationCB *)*lphEnum;
2043
2044     pEnumCB->CurrentIndex = 0;
2045
2046     pEnumCB->Type = dwType;
2047
2048     switch( dwScope )
2049     {
2050         case RESOURCE_CONNECTED:
2051         {
2052
2053             pEnumCB->Scope = RESOURCE_CONNECTED;
2054
2055             break;
2056         }
2057
2058         case RESOURCE_CONTEXT:
2059         {
2060
2061             pEnumCB->Scope = RESOURCE_CONTEXT;
2062
2063             break;
2064         }
2065
2066         case RESOURCE_GLOBALNET:
2067         {
2068
2069             if( lpNetResource != NULL &&
2070                 lpNetResource->lpRemoteName != NULL)
2071             {
2072
2073                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2074
2075                 if( pEnumCB->RemoteName == NULL)
2076                 {
2077
2078                     dwStatus = WN_OUT_OF_MEMORY;
2079                     HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2080                     *lphEnum = NULL;
2081                 }
2082                 else
2083                 {
2084
2085                     StringCbCopy( pEnumCB->RemoteName,
2086                                   0x1000,
2087                                   lpNetResource->lpRemoteName);
2088
2089                 }
2090             }
2091
2092             pEnumCB->Scope = RESOURCE_GLOBALNET;
2093
2094             break;
2095         }
2096
2097         default:
2098
2099 #ifdef AFS_DEBUG_TRACE
2100             AFSDbgPrint( L"NPOpenEnum Processing (Scope %s 0x%x) Type %s Usage %s, returning WN_NOT_SUPPORTED\n",
2101                          GetScopeString(dwScope), dwScope, GetTypeString(dwType), GetUsageString(dwUsage));
2102 #endif
2103
2104             dwStatus  = WN_NOT_SUPPORTED;
2105             HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum );
2106             *lphEnum = NULL;
2107
2108             break;
2109     }
2110
2111     return dwStatus;
2112 }
2113
2114
2115 DWORD
2116 APIENTRY
2117 NPEnumResource( HANDLE  hEnum,
2118                 LPDWORD lpcCount,
2119                 LPVOID  lpBuffer,
2120                 LPDWORD lpBufferSize)
2121 {
2122
2123     DWORD            dwStatus = WN_NO_MORE_ENTRIES; //WN_SUCCESS;
2124     ULONG            dwCopyBytes;
2125     ULONG            EntriesCopied;
2126     ULONG            EntriesRequested;
2127     ULONG            dwIndex;
2128     LPNETRESOURCE    pNetResource;
2129     ULONG            SpaceNeeded;
2130     ULONG            SpaceAvailable;
2131     PWCHAR           StringZone;
2132     AFSNetworkProviderConnectionCB *pConnectionCB = NULL;
2133     void            *pConnectionCBBase = NULL;
2134     DWORD            dwError = 0;
2135     UNICODE_STRING   uniRemoteName;
2136     HANDLE           hControlDevice = NULL;
2137     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2138
2139     __Enter
2140     {
2141
2142         if ( lpBufferSize == NULL)
2143         {
2144 #ifdef AFS_DEBUG_TRACE
2145             AFSDbgPrint( L"NPEnumResource No output size, returning WN_BAD_VALUE\n");
2146 #endif
2147             try_return( dwStatus = WN_BAD_VALUE);
2148         }
2149
2150         ReadProviderNameString();
2151
2152         pNetResource = (LPNETRESOURCE) lpBuffer;
2153         SpaceAvailable = *lpBufferSize;
2154         EntriesRequested = *lpcCount;
2155         *lpcCount = EntriesCopied = 0;
2156         StringZone = (PWCHAR) ((char *)lpBuffer + *lpBufferSize);
2157
2158 #ifdef AFS_DEBUG_TRACE
2159         AFSDbgPrint( L"NPEnumResource Processing Remote name %s Scope %s Type %s Usage %s Index %d SpaceAvailable 0x%lX RequestedEntries %lu\n",
2160                      pEnumCB->RemoteName ? pEnumCB->RemoteName : L"(Null)",
2161                      GetScopeString(pEnumCB->Scope),
2162                      GetTypeString(pEnumCB->Type),
2163                      GetUsageString(pEnumCB->Type),
2164                      pEnumCB->CurrentIndex,
2165                      SpaceAvailable,
2166                      EntriesRequested);
2167 #endif
2168
2169         if ( NPIsFSDisabled())
2170         {
2171
2172 #ifdef AFS_DEBUG_TRACE
2173             AFSDbgPrint( L"NPEnumResource AFSRDFS is disabled, returning WN_NO_MORE_ENTRIES\n");
2174 #endif
2175
2176             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2177         }
2178
2179         pConnectionCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
2180
2181         if( pConnectionCB == NULL)
2182         {
2183
2184 #ifdef AFS_DEBUG_TRACE
2185             AFSDbgPrint( L"NPEnumResource Out of Memory\n");
2186 #endif
2187
2188             try_return( dwStatus = WN_OUT_OF_MEMORY);
2189         }
2190
2191         pConnectionCBBase = (void *)pConnectionCB;
2192
2193         hControlDevice = OpenRedirector();
2194
2195         if( hControlDevice == NULL)
2196         {
2197
2198 #ifdef AFS_DEBUG_TRACE
2199             AFSDbgPrint( L"NPEnumResource OpenRedirector failure, returning WN_NET_ERROR\n");
2200 #endif
2201
2202             try_return( dwStatus = WN_NET_ERROR);
2203         }
2204
2205         //
2206         // Handle the special cases here
2207         //   0. Provider Network Root
2208         //   1. Server Root
2209         //
2210
2211 #if 0
2212         if ( pEnumCB->Scope == RESOURCE_GLOBALNET)
2213         {
2214
2215             ReadServerNameString();
2216
2217             if ( pEnumCB->CurrentIndex == 0 &&
2218                  pEnumCB->RemoteName == NULL)
2219             {
2220
2221                 // Determine the space needed for this entry...
2222
2223                 SpaceNeeded = 2 * ( cbProviderNameLength + sizeof( WCHAR));
2224
2225                 uniRemoteName.Length = (USHORT)cbProviderNameLength;
2226                 uniRemoteName.MaximumLength = uniRemoteName.Length;
2227                 uniRemoteName.Buffer = wszProviderName;
2228
2229                 if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2230                 {
2231
2232                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2233
2234 #ifdef AFS_DEBUG_TRACE
2235                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2236                                  &uniRemoteName,
2237                                  *lpBufferSize);
2238 #endif
2239                     try_return( dwStatus = WN_MORE_DATA);
2240                 }
2241
2242 #ifdef AFS_DEBUG_TRACE
2243                 AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2244                              &uniRemoteName);
2245 #endif
2246
2247                 SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2248
2249                 pNetResource->dwScope       = RESOURCE_GLOBALNET;
2250                 pNetResource->dwType        = RESOURCETYPE_ANY;
2251                 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
2252                 pNetResource->dwUsage       = RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_RESERVED;
2253
2254                 // setup string area at opposite end of buffer
2255                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2256
2257                 pNetResource->lpLocalName = NULL;
2258
2259                 // copy remote name
2260                 pNetResource->lpRemoteName = StringZone;
2261
2262                 StringCbCopy( StringZone,
2263                               cbProviderNameLength + sizeof( WCHAR),
2264                               wszProviderName);
2265
2266                 StringZone += cbProviderNameLength / sizeof(WCHAR) + 1;
2267
2268                 pNetResource->lpComment = NULL;
2269
2270                 // copy provider name
2271                 pNetResource->lpProvider = StringZone;
2272                 StringCbCopy( StringZone,
2273                               cbProviderNameLength + sizeof( WCHAR),
2274                               wszProviderName);
2275
2276                 StringZone += cbProviderNameLength / sizeof( WCHAR) + 1;
2277
2278 #ifdef AFS_DEBUG_TRACE
2279                 AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2280                              pNetResource,
2281                              GetScopeString(pNetResource->dwScope),
2282                              GetTypeString(pNetResource->dwType),
2283                              GetDisplayString(pNetResource->dwDisplayType),
2284                              GetUsageString(pNetResource->dwUsage),
2285                              pNetResource->lpLocalName,
2286                              pNetResource->lpRemoteName,
2287                              pNetResource->lpComment);
2288 #endif
2289
2290                 // setup the new end of buffer
2291                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2292
2293                 EntriesCopied++;
2294
2295                 pNetResource++;
2296
2297                 // do not change the index since we did not query the redirector
2298                 pEnumCB->CurrentIndex = 0;
2299
2300                 // remember that we returned the provider name
2301                 pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000);
2302
2303                 if( pEnumCB->RemoteName == NULL)
2304                 {
2305
2306                     try_return( dwStatus = WN_OUT_OF_MEMORY);
2307                 }
2308                 else
2309                 {
2310
2311                     StringCbCopy( pEnumCB->RemoteName,
2312                                    0x1000,
2313                                    wszProviderName);
2314                 }
2315             }
2316
2317             if ( pEnumCB->CurrentIndex == 0 &&
2318                  lstrlen( pEnumCB->RemoteName) == cbProviderNameLength / sizeof( WCHAR) &&
2319                  _wcsnicmp( pEnumCB->RemoteName, wszProviderName, cbProviderNameLength / sizeof( WCHAR)) == 0 &&
2320                  EntriesCopied < EntriesRequested)
2321             {
2322
2323                 //
2324                 // After the network provider entry comes the server entry
2325                 //
2326
2327                 // Determine the space needed for this entry...
2328
2329                 SpaceNeeded = cbProviderNameLength + cbServerNameUNCLength + cbServerCommentLength + 3 * sizeof( WCHAR);
2330
2331                 uniRemoteName.Length = (USHORT)cbServerNameUNCLength;
2332                 uniRemoteName.MaximumLength = uniRemoteName.Length;
2333                 uniRemoteName.Buffer = wszServerNameUNC;
2334
2335                 if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2336                 {
2337
2338                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2339
2340 #ifdef AFS_DEBUG_TRACE
2341                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2342                                  &uniRemoteName,
2343                                  *lpBufferSize);
2344 #endif
2345                     try_return( dwStatus = WN_MORE_DATA);
2346                 }
2347
2348 #ifdef AFS_DEBUG_TRACE
2349                 AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2350                              &uniRemoteName);
2351 #endif
2352
2353                 SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2354
2355                 pNetResource->dwScope       = 0;
2356                 pNetResource->dwType        = RESOURCETYPE_ANY;
2357                 pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2358                 pNetResource->dwUsage       = RESOURCEUSAGE_CONTAINER;
2359
2360                 // setup string area at opposite end of buffer
2361                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2362
2363                 pNetResource->lpLocalName = NULL;
2364
2365                 // copy remote name
2366                 pNetResource->lpRemoteName = StringZone;
2367
2368                 StringCbCopy( StringZone,
2369                               cbServerNameUNCLength + sizeof( WCHAR),
2370                               wszServerNameUNC);
2371
2372                 StringZone += cbServerNameUNCLength / sizeof(WCHAR) + 1;
2373
2374                 // copy comment
2375                 pNetResource->lpComment = StringZone;
2376
2377                 StringCbCopy( StringZone,
2378                               cbServerCommentLength + sizeof( WCHAR),
2379                               wszServerComment);
2380
2381                 StringZone += cbServerCommentLength / sizeof( WCHAR) + 1;
2382
2383                 // copy provider name
2384                 pNetResource->lpProvider = StringZone;
2385                 StringCbCopy( StringZone,
2386                               cbProviderNameLength + sizeof( WCHAR),
2387                               wszProviderName);
2388
2389                 StringZone += cbProviderNameLength / sizeof( WCHAR) + 1;
2390
2391 #ifdef AFS_DEBUG_TRACE
2392                 AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2393                              pNetResource,
2394                              GetScopeString(pNetResource->dwScope),
2395                              GetTypeString(pNetResource->dwType),
2396                              GetDisplayString(pNetResource->dwDisplayType),
2397                              GetUsageString(pNetResource->dwUsage),
2398                              pNetResource->lpLocalName,
2399                              pNetResource->lpRemoteName,
2400                              pNetResource->lpComment);
2401 #endif
2402
2403                 // setup the new end of buffer
2404                 StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2405
2406                 EntriesCopied++;
2407
2408                 pNetResource++;
2409
2410                 // do not update the index because we did not query the redirector
2411                 pEnumCB->CurrentIndex = 0;
2412
2413                 // remember that we returned the server
2414                 StringCbCopy( pEnumCB->RemoteName,
2415                               0x1000,
2416                               wszServerNameUNC);
2417             }
2418         }
2419 #endif
2420
2421         //
2422         // Setup what we are going to ask for
2423         //
2424
2425         pConnectionCB->Scope = pEnumCB->Scope;
2426
2427         pConnectionCB->Type = pEnumCB->Type;
2428
2429         pConnectionCB->CurrentIndex = pEnumCB->CurrentIndex;
2430
2431         pConnectionCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
2432
2433         //
2434         // If this is a RESOURCE_GLOBALNET enumeration then pass down the remote name if
2435         // there is one
2436         //
2437
2438         pConnectionCB->RemoteNameLength = 0;
2439
2440         if( pEnumCB->Scope == RESOURCE_GLOBALNET &&
2441             pEnumCB->RemoteName != NULL)
2442         {
2443
2444             pConnectionCB->RemoteNameLength = wcslen( pEnumCB->RemoteName) * sizeof( WCHAR);
2445
2446             StringCbCopy( pConnectionCB->RemoteName,
2447                           (0x1000 - sizeof(AFSNetworkProviderConnectionCB)) + sizeof(WCHAR),
2448                           pEnumCB->RemoteName);
2449         }
2450
2451         pConnectionCB->AuthenticationId = AFSRetrieveAuthId();
2452
2453 #ifdef AFS_DEBUG_TRACE
2454         AFSDbgPrint( L"NPEnumResource Retrieved authentication id %08lX-%08lX\n",
2455                      pConnectionCB->AuthenticationId.HighPart,
2456                      pConnectionCB->AuthenticationId.LowPart);
2457 #endif
2458
2459         dwError = DeviceIoControl( hControlDevice,
2460                                    IOCTL_AFS_LIST_CONNECTIONS,
2461                                    pConnectionCB,
2462                                    0x1000,
2463                                    pConnectionCB,
2464                                    0x1000,
2465                                    &dwCopyBytes,
2466                                    NULL);
2467
2468         if( !dwError)
2469         {
2470 #ifdef AFS_DEBUG_TRACE
2471             DWORD gle = GetLastError();
2472
2473             AFSDbgPrint( L"NPEnumResource Failed to list connections from file system - gle 0x%x\n",
2474                          gle);
2475 #endif
2476             try_return( dwStatus = WN_NOT_CONNECTED);
2477         }
2478
2479         if( dwCopyBytes == 0)
2480         {
2481
2482 #ifdef AFS_DEBUG_TRACE
2483             AFSDbgPrint( L"NPEnumResource No More Entries\n");
2484 #endif
2485             try_return( dwStatus = WN_NO_MORE_ENTRIES);
2486         }
2487
2488         dwIndex = pEnumCB->CurrentIndex;
2489
2490         while( EntriesCopied < EntriesRequested)
2491         {
2492
2493             uniRemoteName.Length = (USHORT)pConnectionCB->RemoteNameLength;
2494             uniRemoteName.MaximumLength = uniRemoteName.Length;
2495             uniRemoteName.Buffer = pConnectionCB->RemoteName;
2496
2497             // Determine the space needed for this entry...
2498
2499             SpaceNeeded  = 0;
2500
2501             if( pConnectionCB->LocalName != 0)
2502             {
2503
2504                 SpaceNeeded += 3 * sizeof(WCHAR);                // local name
2505             }
2506
2507             SpaceNeeded += pConnectionCB->RemoteNameLength + sizeof( WCHAR);        // remote name
2508
2509             if( pConnectionCB->CommentLength > 0)
2510             {
2511
2512                 SpaceNeeded += pConnectionCB->CommentLength + sizeof( WCHAR);           // comment
2513             }
2514
2515             SpaceNeeded += cbProviderNameLength + sizeof( WCHAR);           // provider name
2516
2517             if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable)
2518             {
2519
2520                 if (EntriesCopied == 0) {
2521
2522                     dwStatus = WN_MORE_DATA;
2523
2524                     *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE);
2525
2526 #ifdef AFS_DEBUG_TRACE
2527                     AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n",
2528                                  &uniRemoteName,
2529                                  *lpBufferSize);
2530 #endif
2531
2532                 } else {
2533
2534 #ifdef AFS_DEBUG_TRACE
2535                     AFSDbgPrint( L"NPEnumResource Return SUCCESS but more entries Index %d\n",
2536                                  dwIndex);
2537 #endif
2538
2539                     dwStatus = WN_SUCCESS;
2540                 }
2541
2542                 break;
2543             }
2544
2545             SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE));
2546
2547             pNetResource->dwScope       = pConnectionCB->Scope;
2548             pNetResource->dwType        = pConnectionCB->Type;
2549
2550             pNetResource->dwDisplayType = pConnectionCB->DisplayType;
2551
2552             if ( pNetResource->dwType == RESOURCETYPE_ANY &&
2553                  pNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE)
2554             {
2555
2556                 pNetResource->dwType = RESOURCETYPE_DISK;
2557             }
2558             pNetResource->dwUsage       = pConnectionCB->Usage;
2559
2560             // setup string area at opposite end of buffer
2561             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2562
2563             // copy local name
2564             if( pConnectionCB->LocalName != 0)
2565             {
2566
2567                 pNetResource->lpLocalName = StringZone;
2568                 *StringZone++ = towupper(pConnectionCB->LocalName);
2569                 *StringZone++ = L':';
2570                 *StringZone++ = L'\0';
2571             }
2572             else
2573             {
2574
2575                 pNetResource->lpLocalName = NULL;
2576             }
2577
2578 #ifdef AFS_DEBUG_TRACE
2579             AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n",
2580                          &uniRemoteName);
2581 #endif
2582
2583             // copy remote name
2584             pNetResource->lpRemoteName = StringZone;
2585
2586             CopyMemory( StringZone,
2587                         pConnectionCB->RemoteName,
2588                         pConnectionCB->RemoteNameLength);
2589
2590             StringZone += (pConnectionCB->RemoteNameLength / sizeof(WCHAR));
2591
2592             *StringZone++ = L'\0';
2593
2594             // copy comment
2595             if( pConnectionCB->CommentLength > 0)
2596             {
2597
2598                 pNetResource->lpComment = StringZone;
2599
2600                 CopyMemory( StringZone,
2601                             (void *)((char *)pConnectionCB + pConnectionCB->CommentOffset),
2602                             pConnectionCB->CommentLength);
2603
2604                 StringZone += (pConnectionCB->CommentLength / sizeof(WCHAR));
2605
2606                 *StringZone++ = L'\0';
2607             }
2608             else
2609             {
2610
2611                 pNetResource->lpComment = NULL;
2612             }
2613
2614             // copy provider name
2615             pNetResource->lpProvider = StringZone;
2616             StringCbCopy( StringZone,
2617                           cbProviderNameLength + sizeof( WCHAR),
2618                           wszProviderName);
2619
2620             StringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
2621
2622 #ifdef AFS_DEBUG_TRACE
2623             AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n",
2624                          pNetResource,
2625                          GetScopeString(pNetResource->dwScope),
2626                          GetTypeString(pNetResource->dwType),
2627                          GetDisplayString(pNetResource->dwDisplayType),
2628                          GetUsageString(pNetResource->dwUsage),
2629                          pNetResource->lpLocalName,
2630                          pNetResource->lpRemoteName,
2631                          pNetResource->lpComment);
2632 #endif
2633
2634             // setup the new end of buffer
2635             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
2636
2637             EntriesCopied++;
2638
2639             pNetResource++;
2640
2641             dwIndex++;
2642
2643             dwCopyBytes -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2644                            pConnectionCB->RemoteNameLength +
2645                            pConnectionCB->CommentLength;
2646
2647             if( dwCopyBytes == 0)
2648             {
2649
2650                 dwStatus = WN_SUCCESS;
2651
2652                 break;
2653             }
2654
2655             pConnectionCB = (AFSNetworkProviderConnectionCB *)((char *)pConnectionCB +
2656                             FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) +
2657                             pConnectionCB->RemoteNameLength +
2658                             pConnectionCB->CommentLength);
2659         }
2660
2661         *lpcCount = EntriesCopied;
2662
2663         // update entry index
2664         pEnumCB->CurrentIndex = dwIndex;
2665
2666 #ifdef AFS_DEBUG_TRACE
2667         AFSDbgPrint( L"NPEnumResource Completed Count %d Index %d\n",
2668                      EntriesCopied,
2669                      dwIndex);
2670 #endif
2671
2672 try_exit:
2673
2674         if ( hControlDevice != NULL)
2675         {
2676
2677             CloseHandle( hControlDevice);
2678         }
2679
2680         if( pConnectionCBBase != NULL)
2681         {
2682
2683             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectionCBBase);
2684         }
2685     }
2686
2687     return dwStatus;
2688 }
2689
2690 /*++
2691
2692 Routine Description:
2693
2694     This routine closes the handle for enumeration of resources.
2695
2696 Arguments:
2697
2698     hEnum  - the enumeration handle
2699
2700 Return Value:
2701
2702     WN_SUCCESS if successful, otherwise the appropriate error
2703
2704 Notes:
2705
2706     The sample only supports the notion of enumerating connected shares
2707
2708 --*/
2709
2710 DWORD APIENTRY
2711 NPCloseEnum( HANDLE hEnum )
2712 {
2713
2714     AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum;
2715
2716 #ifdef AFS_DEBUG_TRACE
2717     AFSDbgPrint( L"NPCloseEnum\n");
2718 #endif
2719
2720     if( pEnumCB->RemoteName != NULL)
2721     {
2722
2723         HeapFree( GetProcessHeap( ), 0, (PVOID) pEnumCB->RemoteName);
2724     }
2725
2726     HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum );
2727
2728     return WN_SUCCESS;
2729 }
2730
2731 DWORD APIENTRY
2732 NPGetResourceParent( LPNETRESOURCE   lpNetResource,
2733                      LPVOID  lpBuffer,
2734                      LPDWORD lpBufferSize )
2735 {
2736
2737     DWORD    dwStatus = WN_ACCESS_DENIED;
2738     WCHAR   *pwchRemoteName = NULL, *pwchSearch = NULL, *pwchSystem = NULL;
2739     LPNETRESOURCE lpOutResource = (LPNETRESOURCE) lpBuffer;
2740
2741     if ( lpNetResource == NULL)
2742     {
2743 #ifdef AFS_DEBUG_TRACE
2744         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2745 #endif
2746         return WN_MORE_DATA;
2747     }
2748
2749     if( lpNetResource->lpRemoteName == NULL)
2750     {
2751 #ifdef AFS_DEBUG_TRACE
2752         AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n");
2753 #endif
2754         return WN_BAD_NETNAME;
2755     }
2756
2757     if ( lpNetResource->dwType != 0 &&
2758          lpNetResource->dwType != RESOURCETYPE_DISK)
2759     {
2760 #ifdef AFS_DEBUG_TRACE
2761         AFSDbgPrint( L"NPGetResourceParent Bad dwType\n");
2762 #endif
2763         return WN_BAD_VALUE;
2764     }
2765
2766     if ( lpBufferSize == NULL )
2767     {
2768
2769 #ifdef AFS_DEBUG_TRACE
2770         AFSDbgPrint( L"NPGetResourceParent Null lpBufferSize\n");
2771 #endif
2772         return WN_BAD_VALUE;
2773     }
2774
2775 #ifdef AFS_DEBUG_TRACE
2776     AFSDbgPrint( L"NPGetResourceParent For remote name %s\n",
2777                  lpNetResource->lpRemoteName);
2778 #endif
2779
2780     pwchRemoteName = lpNetResource->lpRemoteName;
2781
2782     pwchSearch = pwchRemoteName + (wcslen( pwchRemoteName) - 1);
2783
2784     while( pwchSearch != pwchRemoteName)
2785     {
2786
2787         if( *pwchSearch == L'\\')
2788         {
2789
2790             *pwchSearch = L'\0';
2791
2792             break;
2793         }
2794
2795         pwchSearch--;
2796     }
2797
2798     if( pwchSearch != pwchRemoteName)
2799     {
2800
2801 #ifdef AFS_DEBUG_TRACE
2802         AFSDbgPrint( L"NPGetResourceParent Processing parent %s\n",
2803                      lpNetResource->lpRemoteName);
2804 #endif
2805
2806         dwStatus = NPGetResourceInformation( lpNetResource,
2807                                              lpBuffer,
2808                                              lpBufferSize,
2809                                              &pwchSystem);
2810     }
2811     else
2812     {
2813         if ( lpOutResource == NULL ||
2814              *lpBufferSize < sizeof( NETRESOURCE) )
2815         {
2816             *lpBufferSize = sizeof( NETRESOURCE);
2817
2818             return WN_MORE_DATA;
2819         }
2820
2821         memset( lpOutResource, 0, sizeof( NETRESOURCE));
2822
2823         return WN_SUCCESS;
2824
2825     }
2826
2827     return dwStatus;
2828 }
2829
2830 DWORD APIENTRY
2831 NPGetResourceInformation( LPNETRESOURCE   lpNetResource,
2832                           LPVOID  lpBuffer,
2833                           LPDWORD lpBufferSize,
2834                           LPWSTR  *lplpSystem )
2835 {
2836
2837     DWORD    dwStatus = WN_NOT_CONNECTED;
2838     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
2839     DWORD    dwError = 0;
2840     DWORD    dwBufferSize = 0;
2841     HANDLE   hControlDevice = NULL;
2842     NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
2843     PWCHAR   pStringZone = NULL;
2844     UNICODE_STRING uniRemoteName;
2845     DWORD    ulRequiredLen = 0;
2846     DWORD    dwPassedSize;
2847
2848
2849     __Enter
2850     {
2851         if ( lplpSystem)
2852         {
2853             *lplpSystem = NULL;
2854         }
2855
2856         ReadProviderNameString();
2857
2858         if ( NPIsFSDisabled())
2859         {
2860
2861 #ifdef AFS_DEBUG_TRACE
2862             AFSDbgPrint( L"NPGetResourceInformation AFSRDFS is disabled, returning WN_BAD_NETNAME\n");
2863 #endif
2864
2865             try_return( dwStatus = WN_BAD_NETNAME);
2866         }
2867
2868         if ( lpNetResource == NULL ||
2869              lpBufferSize == NULL )
2870         {
2871
2872 #ifdef AFS_DEBUG_TRACE
2873             AFSDbgPrint( L"NPGetResourceInformaton Null lpNetResource or lpBufferSize\n");
2874 #endif
2875             return WN_BAD_VALUE;
2876         }
2877
2878         if( lpNetResource->lpRemoteName == NULL)
2879         {
2880 #ifdef AFS_DEBUG_TRACE
2881             AFSDbgPrint( L"NPGetResourceInformation No resource name\n");
2882 #endif
2883
2884             try_return( dwStatus = WN_NOT_CONNECTED);
2885         }
2886
2887         dwPassedSize = *lpBufferSize;
2888
2889         dwBufferSize = 0x1000;
2890
2891         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
2892
2893         if( pConnectCB == NULL)
2894         {
2895
2896             try_return( dwStatus = WN_OUT_OF_MEMORY);
2897         }
2898
2899         pConnectCB->RemoteNameLength = wcslen( lpNetResource->lpRemoteName) * sizeof( WCHAR);
2900
2901         StringCbCopy( pConnectCB->RemoteName,
2902                       dwBufferSize - sizeof(AFSNetworkProviderConnectionCB),
2903                       lpNetResource->lpRemoteName);
2904
2905         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
2906
2907         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
2908
2909 #ifdef AFS_DEBUG_TRACE
2910         AFSDbgPrint( L"NPGetResourceInformation Retrieved authentication id %08lX-%08lX\n",
2911                      pConnectCB->AuthenticationId.HighPart,
2912                      pConnectCB->AuthenticationId.LowPart);
2913 #endif
2914
2915         hControlDevice = OpenRedirector();
2916
2917         if( hControlDevice == NULL)
2918         {
2919
2920 #ifdef AFS_DEBUG_TRACE
2921             AFSDbgPrint( L"NPGetResourceInformation OpenRedirector failure, returning WN_NET_ERROR\n");
2922 #endif
2923
2924             try_return( dwStatus = WN_NET_ERROR);
2925         }
2926
2927         dwError = DeviceIoControl( hControlDevice,
2928                                    IOCTL_AFS_GET_CONNECTION_INFORMATION,
2929                                    pConnectCB,
2930                                    dwBufferSize,
2931                                    pConnectCB,
2932                                    dwBufferSize,
2933                                    lpBufferSize,
2934                                    NULL);
2935
2936         if( !dwError)
2937         {
2938 #ifdef AFS_DEBUG_TRACE
2939             DWORD gle = GetLastError();
2940
2941             AFSDbgPrint( L"NPGetResourceInformation Failed to get connection info from file system for local %s gle 0x%x\n",
2942                          lpNetResource->lpRemoteName, gle);
2943 #endif
2944             try_return( dwStatus = WN_BAD_NETNAME);
2945         }
2946
2947         uniRemoteName.Length = (USHORT)pConnectCB->RemoteNameLength;
2948         uniRemoteName.MaximumLength = uniRemoteName.Length;
2949         uniRemoteName.Buffer = pConnectCB->RemoteName;
2950
2951 #ifdef AFS_DEBUG_TRACE
2952         AFSDbgPrint( L"NPGetResourceInformation For remote name %wZ Scope %08lX Type %08lX Usage %08lX\n",
2953                      &uniRemoteName,
2954                      pConnectCB->Scope,
2955                      pConnectCB->Type,
2956                      pConnectCB->Usage);
2957 #endif
2958
2959         // Determine the space needed for this entry...
2960
2961         ulRequiredLen = sizeof( NETRESOURCE);
2962
2963         ulRequiredLen += pConnectCB->RemoteNameLength + sizeof( WCHAR);
2964
2965         ulRequiredLen += pConnectCB->CommentLength + sizeof( WCHAR);
2966
2967         ulRequiredLen += cbProviderNameLength + sizeof( WCHAR);
2968
2969         ulRequiredLen += pConnectCB->RemainingPathLength + sizeof( WCHAR);
2970
2971         if( pNetResource == NULL ||
2972             ulRequiredLen > dwPassedSize)
2973         {
2974
2975             *lpBufferSize = ulRequiredLen;
2976
2977             try_return( dwStatus = WN_MORE_DATA);
2978         }
2979
2980         pStringZone = (PWCHAR) ((char *)lpBuffer + sizeof( NETRESOURCE));
2981
2982         pNetResource->dwScope       = 0 /* pConnectCB->Scope*/;
2983         pNetResource->dwType        = 0 /* pConnectCB->Type */;
2984
2985         pNetResource->dwDisplayType = pConnectCB->DisplayType;
2986
2987         pNetResource->dwUsage       = pConnectCB->Usage;
2988
2989         pNetResource->lpLocalName = NULL;
2990
2991         // copy remote name
2992         pNetResource->lpRemoteName = pStringZone;
2993
2994         CopyMemory( pStringZone,
2995                     pConnectCB->RemoteName,
2996                     pConnectCB->RemoteNameLength);
2997
2998         pStringZone += (pConnectCB->RemoteNameLength / sizeof(WCHAR));
2999
3000         *pStringZone++ = L'\0';
3001
3002         // copy comment
3003         pNetResource->lpComment = pStringZone;
3004
3005         CopyMemory( pStringZone,
3006                     (void *)((char *)pConnectCB + pConnectCB->CommentOffset),
3007                     pConnectCB->CommentLength);
3008
3009         pStringZone += (pConnectCB->CommentLength / sizeof(WCHAR));
3010
3011         *pStringZone++ = L'\0';
3012
3013         // copy remaining path
3014         if (pConnectCB->RemainingPathLength > 0)
3015         {
3016             *lplpSystem = pStringZone;
3017
3018             CopyMemory( pStringZone,
3019                         (void *)((char *)pConnectCB + pConnectCB->RemainingPathOffset),
3020                         pConnectCB->RemainingPathLength);
3021
3022             pStringZone += (pConnectCB->RemainingPathLength / sizeof(WCHAR));
3023
3024             *pStringZone++ = L'\0';
3025
3026 #ifdef AFS_DEBUG_TRACE
3027             AFSDbgPrint( L"NPGetResourceInformation For remote name %s returning remaining path %s\n",
3028                          pNetResource->lpRemoteName,
3029                          *lplpSystem);
3030 #endif
3031         }
3032
3033         // copy provider name
3034         pNetResource->lpProvider = pStringZone;
3035
3036         StringCbCopy( pStringZone,
3037                       cbProviderNameLength + sizeof( WCHAR),
3038                       wszProviderName);
3039
3040         pStringZone += (cbProviderNameLength / sizeof( WCHAR) + 1);
3041
3042         *lpBufferSize = ulRequiredLen;
3043
3044         dwStatus = WN_SUCCESS;
3045
3046 try_exit:
3047
3048         if ( hControlDevice != NULL)
3049         {
3050
3051             CloseHandle( hControlDevice);
3052         }
3053
3054         if( pConnectCB != NULL)
3055         {
3056
3057             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3058         }
3059     }
3060
3061     return dwStatus;
3062 }
3063
3064 static VOID
3065 SeparateRemainingPath( WCHAR * lpConnectionName, WCHAR **lppRemainingPath)
3066 {
3067     WCHAR *pwch;
3068     WCHAR wch1, wch2;
3069     DWORD  dwCount;
3070
3071     //
3072     // at this point the lpConnectionName contains the full name.  We need to
3073     // truncate it to \\server\share and move the remaining path back one position.
3074     //
3075
3076     for ( pwch = lpConnectionName, dwCount = 0; *pwch; pwch++)
3077     {
3078         if ( *pwch == L'\\')
3079         {
3080             dwCount++;
3081         }
3082
3083         if ( dwCount == 4)
3084         {
3085             break;
3086         }
3087     }
3088
3089     if (*pwch == L'\\')
3090     {
3091         //
3092         // Found the remaining path that must be moved
3093         //
3094
3095         *lppRemainingPath = pwch + 1;
3096
3097         *pwch++ = 0;
3098
3099         //
3100         // Find the end
3101         //
3102         for ( ; *pwch; pwch++);
3103
3104         //
3105         // and work backwards moving the string
3106         // and then make sure that there is at least
3107         // a path separator.
3108         //
3109
3110         *(pwch + 1) = 0;
3111
3112         for ( ;pwch > *lppRemainingPath; pwch--)
3113         {
3114             *pwch = *(pwch - 1);
3115         }
3116
3117         *pwch = L'\\';
3118     }
3119 }
3120
3121 DWORD APIENTRY
3122 NPGetUniversalName( LPCWSTR lpLocalPath,
3123                     DWORD   dwInfoLevel,
3124                     LPVOID  lpBuffer,
3125                     LPDWORD lpBufferSize )
3126 {
3127     DWORD    dwStatus = WN_NOT_CONNECTED;
3128     WCHAR    wchLocalName[3];
3129     WCHAR    wchSubstName[MAX_PATH + 1];
3130     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
3131     DWORD    dwError = 0;
3132     DWORD    dwBufferSize = 0;
3133     DWORD    dwPassedSize = *lpBufferSize;
3134     DWORD    dwRemainingLength = *lpBufferSize;
3135     HANDLE   hControlDevice = NULL;
3136     DWORD    dwLocalPathLength = 0;
3137     DWORD    dwRemainingPathLength = 0;
3138     CHAR    *pch;
3139
3140     __Enter
3141     {
3142
3143 #ifdef AFS_DEBUG_TRACE
3144         AFSDbgPrint( L"NPGetUniversalName local path %s level 0x%X\n",
3145                      lpLocalPath ? lpLocalPath : L"(Null)",
3146                      dwInfoLevel);
3147 #endif
3148
3149         if ( NPIsFSDisabled())
3150         {
3151
3152 #ifdef AFS_DEBUG_TRACE
3153             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_NOT_CONNECTED\n");
3154 #endif
3155
3156             try_return( dwStatus = WN_NOT_CONNECTED);
3157         }
3158
3159         dwLocalPathLength = lstrlen( lpLocalPath);
3160
3161         dwRemainingPathLength = dwLocalPathLength - 2;          // no drive letter
3162
3163         if( dwLocalPathLength == 0)
3164         {
3165
3166 #ifdef AFS_DEBUG_TRACE
3167             AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_BAD_LOCALNAME\n");
3168 #endif
3169
3170             try_return( dwStatus = WN_BAD_LOCALNAME);
3171         }
3172
3173         if( lpBuffer == NULL ||
3174             lpBufferSize == NULL)
3175         {
3176 #ifdef AFS_DEBUG_TRACE
3177             AFSDbgPrint( L"NPGetUniversalName No output buffer or size\n");
3178 #endif
3179             try_return( dwStatus = WN_BAD_VALUE);
3180         }
3181
3182         memset(lpBuffer, 0, dwPassedSize);
3183
3184         if ( !DriveSubstitution( lpLocalPath, wchSubstName, sizeof( wchSubstName)))
3185         {
3186             wchLocalName[0] = towupper(lpLocalPath[0]);
3187             wchLocalName[1] = L':';
3188             wchLocalName[2] = L'\0';
3189
3190 #ifdef AFS_DEBUG_TRACE
3191             AFSDbgPrint( L"NPGetUniversalName Requesting UNC for %s level 0x%X\n",
3192                          wchLocalName,
3193                          dwInfoLevel);
3194 #endif
3195         }
3196         else
3197         {
3198
3199             ReadServerNameString();
3200
3201             if ( wchSubstName[0] != L'\\' &&
3202                  wchSubstName[1] == L':')
3203             {
3204
3205                 wchLocalName[0] = towupper(wchSubstName[0]);
3206                 wchLocalName[1] = L':';
3207                 wchLocalName[2] = L'\0';
3208
3209 #ifdef AFS_DEBUG_TRACE
3210                 AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n",
3211                              wchSubstName,
3212                              wchLocalName);
3213 #endif
3214             }
3215             else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
3216                       ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
3217                         wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
3218             {
3219                 HRESULT hr;
3220
3221 #ifdef AFS_DEBUG_TRACE
3222                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n",
3223                              wchSubstName,
3224                              dwInfoLevel,
3225                              dwPassedSize);
3226 #endif
3227
3228                 dwBufferSize = (wcslen( wchSubstName) + 1) * sizeof( WCHAR);
3229
3230                 switch( dwInfoLevel)
3231                 {
3232
3233                 case UNIVERSAL_NAME_INFO_LEVEL:
3234                 {
3235
3236                     UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3237
3238                     *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize;
3239
3240                     if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3241                     {
3242
3243 #ifdef AFS_DEBUG_TRACE
3244                         AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3245 #endif
3246
3247                         try_return( dwStatus = WN_MORE_DATA);
3248                     }
3249
3250                     dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3251
3252                     pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3253
3254                     memcpy( pUniversalInfo->lpUniversalName,
3255                             wchSubstName,
3256                             min( dwBufferSize, dwRemainingLength));
3257
3258                     dwRemainingLength -= min( dwBufferSize, dwRemainingLength);
3259
3260 #ifdef AFS_DEBUG_TRACE
3261                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3262                                  lpBuffer,
3263                                  pUniversalInfo->lpUniversalName,
3264                                  pUniversalInfo->lpUniversalName);
3265 #endif
3266
3267                     if ( dwPassedSize < *lpBufferSize)
3268                     {
3269
3270                         try_return( dwStatus = WN_MORE_DATA);
3271                     }
3272
3273                     try_return( dwStatus = WN_SUCCESS);
3274                 }
3275
3276                 case REMOTE_NAME_INFO_LEVEL:
3277                 {
3278
3279                     REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3280
3281                     *lpBufferSize = sizeof( REMOTE_NAME_INFO) + 2 * dwBufferSize + sizeof( WCHAR);
3282
3283                     if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3284                     {
3285
3286 #ifdef AFS_DEBUG_TRACE
3287                         AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3288 #endif
3289
3290                         try_return( dwStatus = WN_MORE_DATA);
3291                     }
3292
3293                     dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3294
3295                     pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3296
3297                     memcpy( pRemoteInfo->lpUniversalName,
3298                             wchSubstName,
3299                             min( dwRemainingLength, dwBufferSize));
3300
3301                     dwRemainingLength -= min( dwRemainingLength, dwBufferSize);
3302
3303 #ifdef AFS_DEBUG_TRACE
3304                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3305                                  lpBuffer,
3306                                  pRemoteInfo->lpUniversalName,
3307                                  pRemoteInfo->lpUniversalName);
3308 #endif
3309
3310                     if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3311                     {
3312                         pRemoteInfo->lpConnectionName = (LPTSTR)((char *)pRemoteInfo->lpUniversalName + dwBufferSize);
3313
3314                         memcpy( pRemoteInfo->lpConnectionName,
3315                                 wchSubstName,
3316                                 min( dwRemainingLength, dwBufferSize));
3317
3318                         dwRemainingLength -= min( dwRemainingLength, dwBufferSize) - sizeof( WCHAR);
3319
3320                         SeparateRemainingPath( pRemoteInfo->lpConnectionName,
3321                                                &pRemoteInfo->lpRemainingPath);
3322                     }
3323
3324 #ifdef AFS_DEBUG_TRACE
3325                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3326                                  lpBuffer,
3327                                  pRemoteInfo->lpConnectionName,
3328                                  pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3329
3330                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3331                                  lpBuffer,
3332                                  pRemoteInfo->lpRemainingPath,
3333                                  pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3334 #endif
3335
3336                     if ( dwPassedSize < *lpBufferSize)
3337                     {
3338
3339                         try_return( dwStatus = WN_MORE_DATA);
3340                     }
3341
3342                     try_return( dwStatus = WN_SUCCESS);
3343                 }
3344
3345                 default:
3346 #ifdef AFS_DEBUG_TRACE
3347                     AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3348                                  dwInfoLevel);
3349 #endif
3350                     try_return( dwStatus = WN_BAD_VALUE);
3351                 }
3352             }
3353             else
3354             {
3355
3356 #ifdef AFS_DEBUG_TRACE
3357                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is not AFS\n",
3358                              wchSubstName);
3359 #endif
3360                 try_return( dwStatus = WN_NOT_CONNECTED);
3361             }
3362         }
3363
3364         dwBufferSize = 0x1000;
3365
3366         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
3367
3368         if( pConnectCB == NULL)
3369         {
3370             try_return( dwStatus = WN_OUT_OF_MEMORY);
3371         }
3372
3373         pConnectCB->LocalName = towupper(wchLocalName[0]);
3374
3375         pConnectCB->RemoteNameLength = 0;
3376
3377         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
3378
3379         pConnectCB->AuthenticationId = AFSRetrieveAuthId();
3380
3381 #ifdef AFS_DEBUG_TRACE
3382         AFSDbgPrint( L"NPGetUniversalName Retrieved authentication id %08lX-%08lX\n",
3383                      pConnectCB->AuthenticationId.HighPart,
3384                      pConnectCB->AuthenticationId.LowPart);
3385 #endif
3386
3387         hControlDevice = OpenRedirector();
3388
3389         if( hControlDevice == NULL)
3390         {
3391
3392             try_return( dwStatus = WN_NET_ERROR);
3393         }
3394
3395         dwError = DeviceIoControl( hControlDevice,
3396                                    IOCTL_AFS_GET_CONNECTION,
3397                                    pConnectCB,
3398                                    dwBufferSize,
3399                                    pConnectCB,
3400                                    dwBufferSize,
3401                                    &dwBufferSize,
3402                                    NULL);
3403
3404         if( !dwError)
3405         {
3406 #ifdef AFS_DEBUG_TRACE
3407             DWORD gle = GetLastError();
3408
3409             AFSDbgPrint( L"NPGetUniversalName Failed to get connection from file system for local %s gle 0x%x\n",
3410                          wchLocalName, gle);
3411 #endif
3412             try_return( dwStatus = WN_NOT_CONNECTED);
3413         }
3414
3415         switch( dwInfoLevel)
3416         {
3417
3418             case UNIVERSAL_NAME_INFO_LEVEL:
3419             {
3420
3421                 UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer;
3422
3423                 *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize + sizeof( WCHAR);
3424
3425                 *lpBufferSize += dwRemainingPathLength * sizeof( WCHAR);
3426
3427                 if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO))
3428                 {
3429
3430 #ifdef AFS_DEBUG_TRACE
3431                     AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n");
3432 #endif
3433
3434                     try_return( dwStatus = WN_MORE_DATA);
3435                 }
3436
3437                 dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO);
3438
3439                 pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
3440
3441                 pch = (char *)pUniversalInfo->lpUniversalName;
3442
3443                 memcpy( pch,
3444                         pConnectCB,
3445                         min( dwBufferSize, dwRemainingLength));
3446
3447                 pch += min( dwBufferSize, dwRemainingLength);
3448
3449                 dwRemainingLength -= min( dwBufferSize + sizeof(WCHAR), dwRemainingLength);
3450
3451                 memcpy( pch,
3452                         &lpLocalPath[2],
3453                         min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength));
3454
3455                 pch += min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength);
3456
3457                 dwRemainingLength -= min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength);
3458
3459 #ifdef AFS_DEBUG_TRACE
3460                 AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n",
3461                              lpBuffer,
3462                              pUniversalInfo->lpUniversalName,
3463                              pUniversalInfo->lpUniversalName);
3464 #endif
3465
3466                 if ( dwPassedSize < *lpBufferSize)
3467                 {
3468
3469                     try_return( dwStatus = WN_MORE_DATA);
3470                 }
3471
3472                 try_return( dwStatus = WN_SUCCESS);
3473             }
3474
3475             case REMOTE_NAME_INFO_LEVEL:
3476             {
3477
3478                 REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer;
3479
3480                 *lpBufferSize = sizeof( REMOTE_NAME_INFO) + (2 * dwBufferSize + sizeof( WCHAR)) + 2 * sizeof( WCHAR);
3481
3482                 *lpBufferSize += 2 * dwRemainingPathLength * sizeof( WCHAR);
3483
3484                 if( dwPassedSize <= sizeof( REMOTE_NAME_INFO))
3485                 {
3486
3487 #ifdef AFS_DEBUG_TRACE
3488                     AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n");
3489 #endif
3490
3491                     try_return( dwStatus = WN_MORE_DATA);
3492                 }
3493
3494                 dwRemainingLength -= sizeof( REMOTE_NAME_INFO);
3495
3496                 pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
3497
3498                 pch = (char *)pRemoteInfo->lpUniversalName;
3499
3500                 memcpy( pch,
3501                         pConnectCB,
3502                         min( dwBufferSize, dwRemainingLength));
3503
3504                 pch += min( dwBufferSize, dwRemainingLength);
3505
3506                 dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3507
3508                 memcpy( pch,
3509                         &lpLocalPath[2],
3510                         min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength));
3511
3512                 pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3513
3514                 dwRemainingLength -= min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3515
3516 #ifdef AFS_DEBUG_TRACE
3517                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n",
3518                              lpBuffer,
3519                              pRemoteInfo->lpUniversalName,
3520                              pRemoteInfo->lpUniversalName);
3521 #endif
3522
3523                 if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR))
3524                 {
3525                     pRemoteInfo->lpConnectionName = (LPWSTR)pch;
3526
3527                     memcpy( pch,
3528                             pConnectCB,
3529                             min( dwBufferSize, dwRemainingLength));
3530
3531                     pch += min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3532
3533                     dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength);
3534                 }
3535
3536
3537                 if ( dwRemainingLength > dwRemainingPathLength + sizeof( WCHAR))
3538                 {
3539                     pRemoteInfo->lpRemainingPath = (LPWSTR)pch;
3540
3541                     memcpy( pch,
3542                             &lpLocalPath[2],
3543                             min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength));
3544
3545                     pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3546
3547                     dwRemainingLength -= min((dwLocalPathLength + 1) * sizeof( WCHAR), dwRemainingLength);
3548                 }
3549
3550 #ifdef AFS_DEBUG_TRACE
3551                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n",
3552                              lpBuffer,
3553                              pRemoteInfo->lpConnectionName,
3554                              pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)");
3555
3556                 AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n",
3557                              lpBuffer,
3558                              pRemoteInfo->lpRemainingPath,
3559                              pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)");
3560 #endif
3561
3562                 if ( dwPassedSize < *lpBufferSize)
3563                 {
3564
3565                     try_return( dwStatus = WN_MORE_DATA);
3566                 }
3567
3568                 try_return( dwStatus = WN_SUCCESS);
3569             }
3570
3571             default:
3572 #ifdef AFS_DEBUG_TRACE
3573                 AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n",
3574                              dwInfoLevel);
3575 #endif
3576                 try_return( dwStatus = WN_BAD_VALUE);
3577         }
3578
3579 try_exit:
3580
3581 #ifdef AFS_DEBUG_TRACE
3582         AFSDbgPrint( L"NPGetUniversalName BufferSize 0x%X\n",
3583                      *lpBufferSize);
3584 #endif
3585         if ( hControlDevice != NULL)
3586         {
3587
3588             CloseHandle( hControlDevice);
3589         }
3590
3591         if( pConnectCB != NULL)
3592         {
3593
3594             HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB);
3595         }
3596     }
3597
3598     return dwStatus;
3599 }
3600
3601
3602 static LPCWSTR
3603 GetFormatFlags( DWORD dwFlags)
3604 {
3605     static WCHAR Buffer[128] = L"";
3606
3607     //
3608     // WNFMT_MULTILINE         0x01
3609     // WNFMT_ABBREVIATED       0x02
3610     // WNFMT_INENUM            0x10
3611     // WNFMT_CONNECTION        0x20
3612     //
3613
3614     Buffer[0] = L'\0';
3615
3616     if ( dwFlags & WNFMT_MULTILINE )
3617     {
3618         StringCbCat( Buffer, sizeof(Buffer), L"MULTILINE|");
3619     }
3620
3621     if ( dwFlags & WNFMT_INENUM )
3622     {
3623         StringCbCat( Buffer, sizeof(Buffer), L"ABBREVIATED|");
3624     }
3625
3626     if ( dwFlags & WNFMT_INENUM )
3627     {
3628         StringCbCat( Buffer, sizeof(Buffer), L"INENUM|");
3629     }
3630
3631     if ( dwFlags & WNFMT_CONNECTION )
3632     {
3633         StringCbCat( Buffer, sizeof(Buffer), L"CONNECTION|");
3634     }
3635
3636     if ( dwFlags & ~(WNFMT_MULTILINE|WNFMT_ABBREVIATED|WNFMT_INENUM|WNFMT_CONNECTION) )
3637     {
3638         StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|");
3639     }
3640
3641     Buffer[lstrlen(Buffer)-1] = L'\0';
3642
3643     return Buffer;
3644 }
3645
3646 DWORD
3647 NPFormatNetworkName( LPTSTR  lpRemoteName,
3648                      LPTSTR  lpFormattedName,
3649                      LPDWORD lpnLength,
3650                      DWORD dwFlags,
3651                      DWORD dwAveCharPerLine)
3652 {
3653
3654     DWORD dwLen = 0, dwCurrentLen = 0;
3655     LPTSTR pCurrentName = lpRemoteName;
3656
3657 #ifdef AFS_DEBUG_TRACE
3658     AFSDbgPrint( L"NPFormatNetworkName Remote %s Flags %s (0x%x) CharsPerLine %u\n",
3659                  lpRemoteName,
3660                  dwFlags,
3661                  GetFormatFlags( dwFlags),
3662                  dwAveCharPerLine);
3663 #endif
3664
3665
3666     //
3667     // Walk back in the name until we hit a \
3668     //
3669
3670     dwLen = wcslen( lpRemoteName);
3671
3672     pCurrentName += (dwLen - 1);
3673
3674     if ( pCurrentName[ 0] != L'\\')
3675     {
3676
3677         while( dwLen > 0)
3678         {
3679
3680             if( pCurrentName[ 0] == L'\\')
3681             {
3682
3683                 pCurrentName++;
3684
3685                 break;
3686             }
3687
3688             pCurrentName--;
3689
3690             dwLen--;
3691
3692             dwCurrentLen++;
3693         }
3694     }
3695
3696     if( *lpnLength  < dwCurrentLen * sizeof( WCHAR))
3697     {
3698
3699         *lpnLength = dwCurrentLen * sizeof( WCHAR);
3700
3701 #ifdef AFS_DEBUG_TRACE
3702         AFSDbgPrint( L"NPFormatNetworkName remote name %s WN_MORE_DATA\n",
3703                      lpRemoteName);
3704 #endif
3705
3706         return WN_MORE_DATA;
3707     }
3708
3709     StringCbCopy( lpFormattedName,
3710                   *lpnLength,
3711                   pCurrentName);
3712
3713     *lpnLength = dwCurrentLen * sizeof( WCHAR);
3714
3715 #ifdef AFS_DEBUG_TRACE
3716     AFSDbgPrint( L"NPFormatNetworkName remote name %s as %s\n",
3717                  lpRemoteName,
3718                  lpFormattedName);
3719 #endif
3720
3721     return WN_SUCCESS;
3722 }
3723
3724 /************************************************************
3725 /       Unsupported entry points
3726 /************************************************************/
3727
3728 //
3729 // AuthGroup processing is implemented in src/WINNT/afsd/afslogon.c
3730 //
3731 DWORD APIENTRY
3732 NPLogonNotify(
3733     PLUID   lpLogonId,
3734     LPCWSTR lpAuthentInfoType,
3735     LPVOID  lpAuthentInfo,
3736     LPCWSTR lpPreviousAuthentInfoType,
3737     LPVOID  lpPreviousAuthentInfo,
3738     LPWSTR  lpStationName,
3739     LPVOID  StationHandle,
3740     LPWSTR  *lpLogonScript)
3741 {
3742
3743 #ifdef AFS_DEBUG_TRACE
3744     AFSDbgPrint( L"NPLogonNotify, returning WN_NOT_SUPPORTED\n");
3745 #endif
3746
3747     return WN_NOT_SUPPORTED;
3748 }
3749
3750 DWORD APIENTRY
3751 NPPasswordChangeNotify (
3752     LPCWSTR    lpAuthentInfoType,
3753     LPVOID    lpAuthentInfo,
3754     LPCWSTR    lpPreviousAuthentInfoType,
3755     LPVOID    lpPreviousAuthentInfo,
3756     LPWSTR    lpStationName,
3757     LPVOID    StationHandle,
3758     DWORD    dwChangeInfo )
3759 {
3760
3761 #ifdef AFS_DEBUG_TRACE
3762     AFSDbgPrint( L"NPPasswordChangeNotify, returning WN_NOT_SUPPORTED\n");
3763 #endif
3764
3765     SetLastError( WN_NOT_SUPPORTED );
3766
3767     return WN_NOT_SUPPORTED;
3768 }
3769
3770 DWORD APIENTRY
3771 NPGetUser( LPTSTR lpName,
3772            LPTSTR lpUserName,
3773            LPDWORD lpBufferSize)
3774 {
3775
3776     DWORD rc = WN_NOT_SUPPORTED;
3777
3778     AFSDbgPrint( L"NPGetUser Entry Name %s\n", lpName);
3779
3780     return rc;
3781 }
3782
3783
3784 DWORD
3785 APIENTRY
3786 NPGetReconnectFlags( LPWSTR  lpRemoteName,
3787                      unsigned char *Parameter2)
3788 {
3789
3790     DWORD    dwStatus = WN_NOT_SUPPORTED;
3791
3792     AFSDbgPrint( L"NPGetReconnectFlags RemoteName %s\n",
3793                  lpRemoteName);
3794
3795     return dwStatus;
3796 }
3797
3798
3799 DWORD
3800 APIENTRY
3801 I_SystemFocusDialog( VOID)
3802 {
3803
3804     DWORD    dwStatus = WN_NOT_SUPPORTED;
3805
3806     AFSDbgPrint( L"I_SystemFocusDialog\n");
3807
3808     return dwStatus;
3809 }
3810
3811 /************************************************************
3812 /       END Unsupported entry points
3813 /************************************************************/
3814
3815
3816 HANDLE
3817 OpenRedirector()
3818 {
3819
3820     HANDLE hControlDevice = NULL;
3821     WCHAR wchError[ 256];
3822
3823     hControlDevice = CreateFile( AFS_SYMLINK_W,
3824                                  GENERIC_READ | GENERIC_WRITE,
3825                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
3826                                  NULL,
3827                                  OPEN_EXISTING,
3828                                  0,
3829                                  NULL );
3830
3831     if( hControlDevice == INVALID_HANDLE_VALUE)
3832     {
3833
3834         hControlDevice = NULL;
3835 #ifdef AFS_DEBUG_TRACE
3836         AFSDbgPrint( L"Failed to open control device error: %d\n",
3837                      GetLastError());
3838 #endif
3839     }
3840 #if 0
3841     //
3842     // only do this if you want network shares to fail to mount
3843     // when the file system is not yet ready
3844     //
3845     else {
3846
3847         AFSDriverStatusRespCB   respCB;
3848         DWORD                   dwBytes;
3849
3850         memset( &respCB, '\0', sizeof( AFSDriverStatusRespCB));
3851
3852         if ( !DeviceIoControl( hControlDevice,
3853                                IOCTL_AFS_STATUS_REQUEST,
3854                                NULL,
3855                                0,
3856                                (void *)&respCB,
3857                                sizeof( AFSDriverStatusRespCB),
3858                                &dwBytes,
3859                                NULL) ||
3860              dwBytes != sizeof(AFSDriverStatusRespCB) ||
3861              respCB.Status != AFS_DRIVER_STATUS_READY )
3862         {
3863
3864             CloseHandle( hControlDevice);
3865
3866             hControlDevice = NULL;
3867         }
3868     }
3869 #endif
3870
3871     return hControlDevice;
3872 }
3873
3874 LARGE_INTEGER
3875 AFSRetrieveAuthId()
3876 {
3877
3878     LARGE_INTEGER liAuthId = {0,0};
3879     HANDLE hToken = NULL;
3880     TOKEN_STATISTICS stTokenInfo;
3881     DWORD dwCopyBytes = 0;
3882
3883     if ( !OpenThreadToken( GetCurrentThread(),
3884                            TOKEN_QUERY,
3885                            FALSE,       // Impersonation
3886                            &hToken))
3887     {
3888         if( !OpenProcessToken( GetCurrentProcess(),
3889                                TOKEN_QUERY,
3890                                &hToken))
3891         {
3892
3893 #ifdef AFS_DEBUG_TRACE
3894             AFSDbgPrint( L"AFSRetrieveAuthId Failed to retrieve Thread and Process tokens 0x%X\n",
3895                          GetLastError());
3896 #endif
3897         }
3898         else
3899         {
3900
3901 #ifdef AFS_DEBUG_TRACE
3902             AFSDbgPrint( L"AFSRetrieveAuthId Retrieved Process Token\n");
3903 #endif
3904         }
3905     }
3906     else
3907     {
3908
3909 #ifdef AFS_DEBUG_TRACE
3910         AFSDbgPrint( L"AFSRetrieveAuthId Retrieved Thread Token\n");
3911 #endif
3912     }
3913
3914     if ( hToken != NULL)
3915     {
3916
3917         if( !GetTokenInformation( hToken,
3918                                   TokenStatistics,
3919                                   &stTokenInfo,
3920                                   sizeof( TOKEN_STATISTICS),
3921                                   &dwCopyBytes))
3922         {
3923
3924 #ifdef AFS_DEBUG_TRACE
3925             AFSDbgPrint( L"AFSRetrieveAuthId Failed to retrieve token information 0x%X\n",
3926                          GetLastError());
3927 #endif
3928         }
3929         else
3930         {
3931
3932             liAuthId.HighPart = stTokenInfo.AuthenticationId.HighPart;
3933             liAuthId.LowPart = stTokenInfo.AuthenticationId.LowPart;
3934         }
3935
3936         CloseHandle( hToken);
3937     }
3938
3939     return liAuthId;
3940 }
3941
3942 static BOOL
3943 Debug(void)
3944 {
3945     static int init = 0;
3946     static BOOL debug = 0;
3947
3948     if ( !init ) {
3949         HKEY hk;
3950
3951         if (RegOpenKey (HKEY_LOCAL_MACHINE,
3952                          TEXT("SYSTEM\\CurrentControlSet\\Services\\AFSRedirector\\NetworkProvider"), &hk) == 0)
3953         {
3954             DWORD dwSize = sizeof(BOOL);
3955             DWORD dwType = REG_DWORD;
3956             RegQueryValueEx (hk, TEXT("Debug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
3957             RegCloseKey (hk);
3958         }
3959         init = 1;
3960     }
3961
3962     return debug;
3963 }
3964
3965 ULONG
3966 _cdecl
3967 AFSDbgPrint(
3968     PWCHAR Format,
3969     ...
3970     )
3971 {
3972     HRESULT rc = S_OK;
3973     WCHAR wszbuffer[512];
3974     va_list marker;
3975
3976     if ( !Debug() )
3977         return 0;
3978
3979     va_start( marker, Format );
3980     {
3981         StringCbPrintf( wszbuffer, sizeof(wszbuffer), L"[%d-%08X] ",
3982 #ifdef AMD64
3983                            64,
3984 #else
3985                            32,
3986 #endif
3987                            GetCurrentThreadId());
3988
3989         rc = StringCbVPrintfW( &wszbuffer[ 14], sizeof(wszbuffer) - 14, Format, marker);
3990
3991         if (SUCCEEDED(rc))
3992             OutputDebugString( wszbuffer );
3993         else
3994             OutputDebugString(L"AFSDbgPrint Failed to create string\n");
3995     }
3996     return SUCCEEDED(rc) ? 1 : 0;
3997 }