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