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