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