Windows: AFSRDFSProvider stack overrun
[openafs.git] / src / WINNT / afsrdr / npdll / AFS_Npdll.c
index 56e9ef1..f78f826 100644 (file)
 
 ULONG _cdecl AFSDbgPrint( PWCHAR Format, ... );
 
+static DWORD APIENTRY
+NPGetConnectionCommon( LPWSTR  lpLocalName,
+                       LPWSTR  lpRemoteName,
+                       LPDWORD lpBufferSize,
+                       BOOL    bDriveSubstOk);
+
 #define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor )
 
 #define OPENAFS_PROVIDER_NAME           L"OpenAFS Network"
@@ -254,7 +260,7 @@ static BOOL
 DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen)
 {
     WCHAR drive[3];
-    WCHAR device[MAX_PATH + 1];
+    WCHAR device[MAX_PATH + 26];
     HRESULT hr = S_OK;
 
     memset( subststr, 0, substlen);
@@ -262,7 +268,15 @@ DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen)
     drive[1] = drivestr[1];
     drive[2] = 0;
 
-    if ( QueryDosDevice(drive, device, MAX_PATH) )
+    if ( substlen < 3 * sizeof( WCHAR))
+    {
+        //
+        // Cannot represent "D:"
+        //
+        return FALSE;
+    }
+
+    if ( QueryDosDevice(drive, device, MAX_PATH + 26) )
     {
 #ifdef AFS_DEBUG_TRACE
         AFSDbgPrint( L"DriveSubstitution QueryDosDevice %s [%s -> %s]\n",
@@ -287,18 +301,17 @@ DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen)
                 subststr[0] = drive[0];
                 subststr[1] = L':';
                 subststr[2] = L'\0';
-
             }
 
             hr = S_OK;
 
             if ( device[6] )
             {
-                hr = StringCchCat( subststr, substlen, &device[6]);
+                hr = StringCbCat( subststr, substlen, &device[6]);
             }
             if ( SUCCEEDED(hr) && drivestr[2] )
             {
-                hr = StringCchCat( subststr, substlen, &drivestr[2]);
+                hr = StringCbCat( subststr, substlen, &drivestr[2]);
             }
 
             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
@@ -324,13 +337,13 @@ DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen)
 
             subststr[0] = L'\\';
 
-            hr = StringCbCopyN(&subststr[1], substlen - sizeof(WCHAR), &device[7], MAX_PATH);
+            hr = StringCbCopyN(&subststr[1], substlen - sizeof(WCHAR), &device[7], sizeof(device));
 
             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
             {
                 if ( drivestr[2] )
                 {
-                    hr = StringCchCat( subststr, substlen, &drivestr[2]);
+                    hr = StringCbCat( subststr, substlen, &drivestr[2]);
                 }
                 else
                 {
@@ -360,16 +373,15 @@ DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen)
             // \Device\AFSRedirector\;X:\\afs\cellname
             //
 
-            hr = StringCbCopyN( subststr, substlen,
-                                 &device[3 + sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR)],
-                                 MAX_PATH * sizeof( WCHAR));
+            hr = StringCbCopy( subststr, substlen,
+                               &device[3 + sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR)]);
 
             if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER)
             {
 
                 if ( drivestr[2] )
                 {
-                    hr = StringCchCat( subststr, substlen, &drivestr[2]);
+                    hr = StringCbCat( subststr, substlen, &drivestr[2]);
                 }
                 else
                 {
@@ -600,6 +612,7 @@ NPAddConnection3( HWND            hwndOwner,
     HANDLE   hControlDevice = NULL;
     HANDLE   hToken = NULL;
     LARGE_INTEGER liAuthId = {0,0};
+    HRESULT  hr;
 
     __Enter
     {
@@ -637,8 +650,15 @@ NPAddConnection3( HWND            hwndOwner,
             wchLocalName[2] = L'\0';
         }
 
-        StringCchCopy(wchRemoteName, MAX_PATH+1, lpNetResource->lpRemoteName);
-        wchRemoteName[MAX_PATH] = L'\0';
+        hr = StringCbCopy(wchRemoteName, sizeof( wchRemoteName), lpNetResource->lpRemoteName);
+        if ( FAILED(hr))
+        {
+
+#ifdef AFS_DEBUG_TRACE
+            AFSDbgPrint( L"NPAddConnection3 lpRemoteName longer than MAX_PATH, returning WN_BAD_NETNAME\n");
+#endif
+            return WN_BAD_NETNAME;
+        }
 
         //
         // Allocate our buffer to pass to the redirector filter
@@ -731,11 +751,11 @@ NPAddConnection3( HWND            hwndOwner,
             lpNetResource->lpLocalName != NULL)
         {
 
-            WCHAR TempBuf[MAX_PATH+1];
+            WCHAR TempBuf[MAX_PATH+26];
 
             if( !QueryDosDeviceW( wchLocalName,
                                   TempBuf,
-                                  MAX_PATH+1))
+                                  MAX_PATH+26))
             {
 
                 if( GetLastError() != ERROR_FILE_NOT_FOUND)
@@ -752,17 +772,12 @@ NPAddConnection3( HWND            hwndOwner,
                 {
 
                     UNICODE_STRING uniConnectionName;
-                    UNICODE_STRING uniDeviceName;
-
-                    uniDeviceName.Length = (wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR));
-                    uniDeviceName.MaximumLength = uniDeviceName.Length;
-                    uniDeviceName.Buffer = AFS_RDR_DEVICE_NAME;
 
                     //
                     // Create a symbolic link object to the device we are redirecting
                     //
 
-                    uniConnectionName.MaximumLength = (USHORT)( uniDeviceName.Length +
+                    uniConnectionName.MaximumLength = (USHORT)( wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR) +
                                                                 pConnectCB->RemoteNameLength +
                                                                 8 +              // Local name and \;
                                                                 sizeof(WCHAR));   //  Space for NULL-termination.
@@ -782,21 +797,49 @@ NPAddConnection3( HWND            hwndOwner,
                         try_return( dwStatus = GetLastError());
                     }
 
-                    CopyMemory( uniConnectionName.Buffer,
-                                uniDeviceName.Buffer,
-                                uniDeviceName.Length);
+                    hr = StringCbCopyW( uniConnectionName.Buffer,
+                                        uniConnectionName.MaximumLength,
+                                        AFS_RDR_DEVICE_NAME);
+                    if ( FAILED(hr))
+                    {
+#ifdef AFS_DEBUG_TRACE
+                        AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
+#endif
+                        try_return( dwStatus = WN_OUT_OF_MEMORY);
+                    }
 
-                    StringCchCatW( uniConnectionName.Buffer,
-                                   uniConnectionName.MaximumLength,
-                                   L"\\;" );
+                    hr = StringCbCatW( uniConnectionName.Buffer,
+                                       uniConnectionName.MaximumLength,
+                                       L"\\;" );
+                    if ( FAILED(hr))
+                    {
+#ifdef AFS_DEBUG_TRACE
+                        AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
+#endif
+                        try_return( dwStatus = WN_OUT_OF_MEMORY);
+                    }
 
-                    StringCchCatW( uniConnectionName.Buffer,
-                                   uniConnectionName.MaximumLength,
-                                   wchLocalName);
+                    hr = StringCbCatW( uniConnectionName.Buffer,
+                                       uniConnectionName.MaximumLength,
+                                       wchLocalName);
+                    if ( FAILED(hr))
+                    {
+#ifdef AFS_DEBUG_TRACE
+                        AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
+#endif
+                        try_return( dwStatus = WN_OUT_OF_MEMORY);
+                    }
 
-                    StringCchCatW( uniConnectionName.Buffer,
-                                   uniConnectionName.MaximumLength,
-                                   wchRemoteName);
+                    hr = StringCbCatW( uniConnectionName.Buffer,
+                                       uniConnectionName.MaximumLength,
+                                       wchRemoteName);
+                    if ( FAILED(hr))
+                    {
+#ifdef AFS_DEBUG_TRACE
+                        AFSDbgPrint( L"NPAddConnection3 uniConnectionBuffer too small\n");
+#endif
+                        try_return( dwStatus = WN_OUT_OF_MEMORY);
+                    }
 
 #ifdef AFS_DEBUG_TRACE
                     AFSDbgPrint( L"NPAddConnection3 DefineDosDevice Local %s connection name %s\n",
@@ -817,6 +860,10 @@ NPAddConnection3( HWND            hwndOwner,
                     else
                     {
 
+#ifdef AFS_DEBUG_TRACE
+                        AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW assigned drive %s\n", wchLocalName);
+#endif
+
                         dwStatus = WN_SUCCESS;
                     }
 
@@ -869,7 +916,9 @@ NPCancelConnection( LPWSTR  lpName,
     DWORD    dwBufferSize = 0;
     BOOL     bLocalName = TRUE;
     HANDLE   hControlDevice = NULL;
+    WCHAR    wchLocalName[ 3];
     WCHAR   *pwchLocalName = NULL;
+    HRESULT hr;
 
     __Enter
     {
@@ -889,18 +938,36 @@ NPCancelConnection( LPWSTR  lpName,
         {
 
             bLocalName = FALSE;
-        }
 
-        if( bLocalName)
+            wchLocalName[0] = L'\0';
+
+            hr = StringCbCopyW( wchRemoteName, sizeof( wchRemoteName), lpName);
+
+            if ( FAILED(hr))
+            {
+#ifdef AFS_DEBUG_TRACE
+                AFSDbgPrint( L"NPCancelConnection lpName longer than MAX_PATH\n");
+#endif
+                try_return( dwStatus = WN_OUT_OF_MEMORY);
+            }
+
+            dwRemoteNameLength = (wcslen( wchRemoteName) * sizeof( WCHAR));
+        }
+        else
         {
 
+            wchLocalName[0] = towupper(lpName[0]);
+            wchLocalName[1] = L':';
+            wchLocalName[2] = L'\0';
+
             //
             // Get the remote name for the connection, if we are handling it
             //
 
-            dwStatus = NPGetConnection( lpName,
-                                        wchRemoteName,
-                                        &dwRemoteNameLength);
+            dwStatus = NPGetConnectionCommon( wchLocalName,
+                                              wchRemoteName,
+                                              &dwRemoteNameLength,
+                                              FALSE);
 
             if( dwStatus != WN_SUCCESS ||
                 dwRemoteNameLength == 0)
@@ -912,17 +979,20 @@ NPCancelConnection( LPWSTR  lpName,
 #endif
                 try_return( dwStatus = WN_NOT_CONNECTED);
             }
-        }
-        else
-        {
-
-            StringCchCopyW( wchRemoteName, MAX_PATH+1, lpName);
 
-            dwRemoteNameLength = (wcslen( wchRemoteName) * sizeof( WCHAR));
+            //
+            // NPGetConnection returns the buffer size not the length without NUL
+            //
+            dwRemoteNameLength -= sizeof( WCHAR);
         }
 
         wchRemoteName[ dwRemoteNameLength/sizeof( WCHAR)] = L'\0';
 
+#ifdef AFS_DEBUG_TRACE
+        AFSDbgPrint( L"NPCancelConnection Attempting to cancel '%s' -> '%s'\n",
+                     wchLocalName, wchRemoteName);
+#endif
+
         dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + dwRemoteNameLength;
 
         pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
@@ -936,7 +1006,7 @@ NPCancelConnection( LPWSTR  lpName,
         if( bLocalName)
         {
 
-            pConnectCB->LocalName = towupper(lpName[0]);
+            pConnectCB->LocalName = wchLocalName[0];
         }
         else
         {
@@ -946,9 +1016,9 @@ NPCancelConnection( LPWSTR  lpName,
 
         pConnectCB->RemoteNameLength = (USHORT)dwRemoteNameLength;
 
-        StringCchCopyW( pConnectCB->RemoteName,
-                        MAX_PATH+1,
-                        wchRemoteName);
+        StringCbCopyW( pConnectCB->RemoteName,
+                       dwRemoteNameLength + sizeof( WCHAR),
+                       wchRemoteName);
 
         pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1;
 
@@ -990,7 +1060,7 @@ NPCancelConnection( LPWSTR  lpName,
 #ifdef AFS_DEBUG_TRACE
             DWORD gle = GetLastError();
 
-            AFSDbgPrint( L"NPCancelConnection Failed to cancel connection to file system - gle 0x%x\n", gle);
+            AFSDbgPrint( L"NPCancelConnection DeviceIoControl failed - gle 0x%x\n", gle);
 #endif
             try_return( dwStatus = WN_NOT_CONNECTED);
         }
@@ -998,10 +1068,19 @@ NPCancelConnection( LPWSTR  lpName,
         dwStatus = stCancelConn.Status;
 
 #ifdef AFS_DEBUG_TRACE
+        if ( dwStatus == WN_NOT_CONNECTED )
+        {
 
-        AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status %08lX\n",
-                     lpName,
-                     dwStatus);
+            AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status WN_NOT_CONNECTED\n",
+                         lpName);
+        }
+        else
+        {
+
+            AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status %08lX\n",
+                         lpName,
+                         dwStatus);
+        }
 #endif
 
         if( dwStatus == WN_SUCCESS &&
@@ -1010,17 +1089,12 @@ NPCancelConnection( LPWSTR  lpName,
         {
 
             UNICODE_STRING uniConnectionName;
-            UNICODE_STRING uniDeviceName;
-
-            uniDeviceName.Length = (wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR));
-            uniDeviceName.MaximumLength = uniDeviceName.Length;
-            uniDeviceName.Buffer = AFS_RDR_DEVICE_NAME;
 
             //
             // Create a symbolic link object to the device we are redirecting
             //
 
-            uniConnectionName.MaximumLength = (USHORT)( uniDeviceName.Length +
+            uniConnectionName.MaximumLength = (USHORT)( wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR) +
                                                         dwRemoteNameLength +
                                                         8 +             // Local name and \;
                                                         sizeof(WCHAR)); //  Space for NULL-termination.
@@ -1040,44 +1114,82 @@ NPCancelConnection( LPWSTR  lpName,
                 try_return( dwStatus = GetLastError());
             }
 
-            CopyMemory( uniConnectionName.Buffer,
-                        uniDeviceName.Buffer,
-                        uniDeviceName.Length);
+            hr = StringCbCopyW( uniConnectionName.Buffer,
+                                uniConnectionName.MaximumLength,
+                                AFS_RDR_DEVICE_NAME);
+
+            if ( FAILED(hr))
+            {
+#ifdef AFS_DEBUG_TRACE
+                AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (1)\n");
+#endif
+                try_return( dwStatus = WN_OUT_OF_MEMORY);
+            }
+
+            hr = StringCbCatW( uniConnectionName.Buffer,
+                               uniConnectionName.MaximumLength,
+                               L"\\;" );
 
-            StringCchCatW( uniConnectionName.Buffer,
-                           uniConnectionName.MaximumLength,
-                           L"\\;" );
+            if ( FAILED(hr))
+            {
+#ifdef AFS_DEBUG_TRACE
+                AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (2)\n");
+#endif
+                try_return( dwStatus = WN_OUT_OF_MEMORY);
+            }
 
             if( !bLocalName)
             {
 
-                WCHAR wchLocalName[ 3];
-
                 wchLocalName[ 0] = stCancelConn.LocalName;
 
                 wchLocalName[ 1] = L':';
 
                 wchLocalName[ 2] = L'\0';
 
-                StringCchCatW( uniConnectionName.Buffer,
-                               uniConnectionName.MaximumLength,
-                               wchLocalName);
+                hr = StringCbCatW( uniConnectionName.Buffer,
+                                   uniConnectionName.MaximumLength,
+                                   wchLocalName);
+
+                if ( FAILED(hr))
+                {
+#ifdef AFS_DEBUG_TRACE
+                    AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (3)\n");
+#endif
+                    try_return( dwStatus = WN_OUT_OF_MEMORY);
+                }
 
                 pwchLocalName = wchLocalName;
             }
             else
             {
 
-                StringCchCatW( uniConnectionName.Buffer,
-                               uniConnectionName.MaximumLength,
-                               lpName);
+                hr = StringCbCatW( uniConnectionName.Buffer,
+                                   uniConnectionName.MaximumLength,
+                                   lpName);
+
+                if ( FAILED(hr))
+                {
+#ifdef AFS_DEBUG_TRACE
+                    AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (4)\n");
+#endif
+                    try_return( dwStatus = WN_OUT_OF_MEMORY);
+                }
 
                 pwchLocalName = lpName;
             }
 
-            StringCchCatW( uniConnectionName.Buffer,
-                           uniConnectionName.MaximumLength,
-                           wchRemoteName);
+            hr = StringCbCatW( uniConnectionName.Buffer,
+                               uniConnectionName.MaximumLength,
+                               wchRemoteName);
+
+            if ( FAILED(hr))
+            {
+#ifdef AFS_DEBUG_TRACE
+                AFSDbgPrint( L"NPCancelConnection uniConnectionName buffer too small (5)\n");
+#endif
+                try_return( dwStatus = WN_OUT_OF_MEMORY);
+            }
 
             if( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
                                   pwchLocalName,
@@ -1131,9 +1243,23 @@ NPGetConnection( LPWSTR  lpLocalName,
                  LPDWORD lpBufferSize)
 {
 
+    return NPGetConnectionCommon( lpLocalName,
+                                  lpRemoteName,
+                                  lpBufferSize,
+                                  TRUE);
+}
+
+DWORD
+APIENTRY
+NPGetConnectionCommon( LPWSTR  lpLocalName,
+                       LPWSTR  lpRemoteName,
+                       LPDWORD lpBufferSize,
+                       BOOL    bDriveSubstOk)
+{
+
     DWORD    dwStatus = WN_NOT_CONNECTED;
     WCHAR    wchLocalName[3];
-    WCHAR    wchSubstName[MAX_PATH + 1];
+    WCHAR    wchSubstName[1024 + 26];
     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
     DWORD    dwError = 0;
     DWORD    dwBufferSize = 0;
@@ -1171,7 +1297,8 @@ NPGetConnection( LPWSTR  lpLocalName,
 
         dwPassedSize = *lpBufferSize;
 
-        if ( !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName)))
+        if ( !bDriveSubstOk ||
+             !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName)))
         {
             wchLocalName[0] = towupper(lpLocalName[0]);
             wchLocalName[1] = L':';
@@ -1207,17 +1334,21 @@ NPGetConnection( LPWSTR  lpLocalName,
                 HRESULT hr;
                 WCHAR  *pwch;
                 DWORD   dwCount = 0;
+                DWORD   dwRequiredSize;
 
 #ifdef AFS_DEBUG_TRACE
                 AFSDbgPrint( L"NPGetConnection drive substitution %s is AFS\n",
                              wchSubstName);
 #endif
 
+                dwRequiredSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
+
                 if ( lpRemoteName == NULL ||
-                     dwPassedSize == 0)
+                     dwPassedSize == 0 ||
+                     dwRequiredSize > *lpBufferSize)
                 {
 
-                    *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR);
+                    *lpBufferSize = dwRequiredSize;
 
                     try_return( dwStatus = WN_MORE_DATA);
 
@@ -1228,7 +1359,7 @@ NPGetConnection( LPWSTR  lpLocalName,
                 if ( SUCCEEDED(hr))
                 {
 
-                    for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ )
+                    for ( dwCount = 0, pwch = lpRemoteName; *pwch && pwch < lpRemoteName + (*lpBufferSize); pwch++ )
                     {
                         if ( *pwch == L'\\' )
                         {
@@ -1411,7 +1542,7 @@ NPGetConnection3( IN     LPCWSTR lpLocalName,
 
     DWORD    dwStatus = WN_NOT_CONNECTED;
     WCHAR    wchLocalName[3];
-    WCHAR    wchSubstName[MAX_PATH + 1];
+    WCHAR    wchSubstName[1024 + 26];
     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
     DWORD    dwError = 0;
     DWORD    dwBufferSize = 0;
@@ -2156,6 +2287,15 @@ NPEnumResource( HANDLE  hEnum,
             try_return( dwStatus = WN_NET_ERROR);
         }
 
+        if( pEnumCB->Type != RESOURCETYPE_ANY && pEnumCB->Type != RESOURCETYPE_DISK)
+        {
+
+#ifdef AFS_DEBUG_TRACE
+            AFSDbgPrint( L"NPEnumResource Non-DISK queries are not supported, returning WN_NO_MORE_ENTRIES\n");
+#endif
+            try_return( dwStatus = WN_NO_MORE_ENTRIES);
+        }
+
         //
         // Handle the special cases here
         //   0. Provider Network Root
@@ -2509,7 +2649,17 @@ NPEnumResource( HANDLE  hEnum,
 
                 pNetResource->dwType = RESOURCETYPE_DISK;
             }
-            pNetResource->dwUsage       = pConnectionCB->Usage;
+
+            if ( pEnumCB->Scope == RESOURCE_CONNECTED)
+            {
+
+                pNetResource->dwUsage       = 0;
+            }
+            else
+            {
+
+                pNetResource->dwUsage       = pConnectionCB->Usage;
+            }
 
             // setup string area at opposite end of buffer
             StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded);
@@ -3080,7 +3230,8 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
 {
     DWORD    dwStatus = WN_NOT_CONNECTED;
     WCHAR    wchLocalName[3];
-    WCHAR    wchSubstName[MAX_PATH + 1];
+    WCHAR   *pwchSubstName = NULL;
+    DWORD    dwSubstNameLength = 0;
     AFSNetworkProviderConnectionCB   *pConnectCB = NULL;
     DWORD    dwError = 0;
     DWORD    dwBufferSize = 0;
@@ -3133,9 +3284,21 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
             try_return( dwStatus = WN_BAD_VALUE);
         }
 
+        dwSubstNameLength = (dwLocalPathLength + 26) * sizeof( WCHAR);
+
+        pwchSubstName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSubstNameLength);
+
+        if ( pwchSubstName == NULL)
+        {
+#ifdef AFS_DEBUG_TRACE
+            AFSDbgPrint( L"NPGetUniversalName unable to allocate substitution name buffer.\n");
+#endif
+            try_return( dwStatus = WN_OUT_OF_MEMORY);
+        }
+
         memset(lpBuffer, 0, dwPassedSize);
 
-        if ( !DriveSubstitution( lpLocalPath, wchSubstName, sizeof( wchSubstName)))
+        if ( !DriveSubstitution( lpLocalPath, pwchSubstName, dwSubstNameLength))
         {
             wchLocalName[0] = towupper(lpLocalPath[0]);
             wchLocalName[1] = L':';
@@ -3152,34 +3315,34 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
 
             ReadServerNameString();
 
-            if ( wchSubstName[0] != L'\\' &&
-                 wchSubstName[1] == L':')
+            if ( pwchSubstName[0] != L'\\' &&
+                 pwchSubstName[1] == L':')
             {
 
-                wchLocalName[0] = towupper(wchSubstName[0]);
+                wchLocalName[0] = towupper(pwchSubstName[0]);
                 wchLocalName[1] = L':';
                 wchLocalName[2] = L'\0';
 
 #ifdef AFS_DEBUG_TRACE
                 AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n",
-                             wchSubstName,
+                             pwchSubstName,
                              wchLocalName);
 #endif
             }
-            else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
-                      ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
-                        wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
+            else if ( _wcsnicmp( pwchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 &&
+                      ( pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' ||
+                        pwchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0))
             {
                 HRESULT hr;
 
 #ifdef AFS_DEBUG_TRACE
                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n",
-                             wchSubstName,
+                             pwchSubstName,
                              dwInfoLevel,
                              dwPassedSize);
 #endif
 
-                dwBufferSize = (wcslen( wchSubstName) + 1) * sizeof( WCHAR);
+                dwBufferSize = (wcslen( pwchSubstName) + 1) * sizeof( WCHAR);
 
                 switch( dwInfoLevel)
                 {
@@ -3206,7 +3369,7 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
                     pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO));
 
                     memcpy( pUniversalInfo->lpUniversalName,
-                            wchSubstName,
+                            pwchSubstName,
                             min( dwBufferSize, dwRemainingLength));
 
                     dwRemainingLength -= min( dwBufferSize, dwRemainingLength);
@@ -3249,7 +3412,7 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
                     pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO));
 
                     memcpy( pRemoteInfo->lpUniversalName,
-                            wchSubstName,
+                            pwchSubstName,
                             min( dwRemainingLength, dwBufferSize));
 
                     dwRemainingLength -= min( dwRemainingLength, dwBufferSize);
@@ -3266,7 +3429,7 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
                         pRemoteInfo->lpConnectionName = (LPTSTR)((char *)pRemoteInfo->lpUniversalName + dwBufferSize);
 
                         memcpy( pRemoteInfo->lpConnectionName,
-                                wchSubstName,
+                                pwchSubstName,
                                 min( dwRemainingLength, dwBufferSize));
 
                         dwRemainingLength -= min( dwRemainingLength, dwBufferSize) - sizeof( WCHAR);
@@ -3309,7 +3472,7 @@ NPGetUniversalName( LPCWSTR lpLocalPath,
 
 #ifdef AFS_DEBUG_TRACE
                 AFSDbgPrint( L"NPGetUniversalName drive substitution %s is not AFS\n",
-                             wchSubstName);
+                             pwchSubstName);
 #endif
                 try_return( dwStatus = WN_NOT_CONNECTED);
             }
@@ -3542,6 +3705,12 @@ try_exit:
             CloseHandle( hControlDevice);
         }
 
+        if ( pwchSubstName)
+        {
+
+            HeapFree( GetProcessHeap(), 0, (PVOID) pwchSubstName);
+        }
+
         if( pConnectCB != NULL)
         {
 
@@ -3567,6 +3736,11 @@ GetFormatFlags( DWORD dwFlags)
 
     Buffer[0] = L'\0';
 
+    if ( dwFlags == 0)
+    {
+        return L"NONE";
+    }
+
     if ( dwFlags & WNFMT_MULTILINE )
     {
         StringCbCat( Buffer, sizeof(Buffer), L"MULTILINE|");
@@ -3772,7 +3946,6 @@ OpenRedirector()
 {
 
     HANDLE hControlDevice = NULL;
-    WCHAR wchError[ 256];
 
     hControlDevice = CreateFile( AFS_SYMLINK_W,
                                  GENERIC_READ | GENERIC_WRITE,
@@ -3893,11 +4066,11 @@ AFSRetrieveAuthId()
     return liAuthId;
 }
 
-static BOOL
+static DWORD
 Debug(void)
 {
     static int init = 0;
-    static BOOL debug = 0;
+    static DWORD debug = 0;
 
     if ( !init ) {
         HKEY hk;
@@ -3916,6 +4089,76 @@ Debug(void)
     return debug;
 }
 
+static char *
+cm_Utf16ToUtf8Alloc(const WCHAR * s, int cch_src, int *pcch_dest)
+{
+    int cch_dest;
+    char * dest;
+
+    if (s == NULL || cch_src == 0 || *s == L'\0') {
+        if (pcch_dest)
+            *pcch_dest = ((cch_src != 0)?1:0);
+        return NULL;
+    }
+
+    cch_dest = WideCharToMultiByte(CP_UTF8, 0, s, cch_src, NULL, 0, NULL, FALSE);
+
+    if (cch_dest == 0) {
+        if (pcch_dest)
+            *pcch_dest = cch_dest;
+        return NULL;
+    }
+
+    dest = HeapAlloc( GetProcessHeap(), 0, (cch_dest + 1) * sizeof(char));
+
+    WideCharToMultiByte(CP_UTF8, 0, s, cch_src, dest, cch_dest, NULL, FALSE);
+    dest[cch_dest] = 0;
+
+    if (pcch_dest)
+        *pcch_dest = cch_dest;
+
+    return dest;
+}
+
+static void
+AppendDebugStringToLogFile(WCHAR *wszbuffer)
+{
+    HANDLE hFile;
+    int len;
+    char * buffer;
+    DWORD dwWritten;
+    BOOL bRet;
+
+    if ( !wszbuffer || !wszbuffer[0] )
+        return;
+
+    len = (int)wcslen(wszbuffer);
+
+    buffer = cm_Utf16ToUtf8Alloc(wszbuffer, len, &len);
+
+    if (!buffer)
+        return;
+
+    hFile = CreateFileW( L"C:\\TEMP\\AFSRDFSProvider.log",
+                         FILE_APPEND_DATA,
+                         FILE_SHARE_WRITE,
+                         NULL,
+                         OPEN_ALWAYS,
+                         FILE_ATTRIBUTE_NORMAL,
+                         NULL);
+
+    if ( hFile == INVALID_HANDLE_VALUE ) {
+        OutputDebugString(L"C:\\AFSRDFSProvider.log cannot be opened.\n");
+        return;
+    }
+
+    bRet = WriteFile( hFile, buffer, len, &dwWritten, NULL);
+
+    bRet = CloseHandle(hFile);
+
+    HeapFree(GetProcessHeap(), 0, buffer);
+}
+
 ULONG
 _cdecl
 AFSDbgPrint(
@@ -3926,8 +4169,9 @@ AFSDbgPrint(
     HRESULT rc = S_OK;
     WCHAR wszbuffer[512];
     va_list marker;
+    DWORD debug = Debug();
 
-    if ( !Debug() )
+    if (debug == 0)
         return 0;
 
     va_start( marker, Format );
@@ -3942,10 +4186,14 @@ AFSDbgPrint(
 
         rc = StringCbVPrintfW( &wszbuffer[ 14], sizeof(wszbuffer) - 14, Format, marker);
 
-        if (SUCCEEDED(rc))
-            OutputDebugString( wszbuffer );
-        else
+        if (SUCCEEDED(rc)) {
+            if (debug & 1)
+                OutputDebugString( wszbuffer );
+            if (debug & 2)
+                AppendDebugStringToLogFile(wszbuffer);
+        } else {
             OutputDebugString(L"AFSDbgPrint Failed to create string\n");
+        }
     }
     return SUCCEEDED(rc) ? 1 : 0;
 }