Przeglądaj źródła

Server: SMB2: Bugfix: Invalid change notify interim response was sent when the object store did not support change notifications

Tal Aloni 5 lat temu
rodzic
commit
a0a372dd16

+ 5 - 2
SMBLibrary/Server/SMB2/CancelHelper.cs

@@ -1,4 +1,4 @@
-/* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
+/* Copyright (C) 2017-2019 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  * 
  * You can redistribute this program and/or modify it under the terms of
  * the GNU Lesser Public License as published by the Free Software Foundation,
@@ -28,7 +28,9 @@ namespace SMBLibrary.Server.SMB2
                     {
                         state.LogToServer(Severity.Information, "Cancel: Requested cancel on '{0}{1}'. NTStatus: {2}, AsyncID: {3}.", share.Name, openFile.Path, status, context.AsyncID);
                     }
-                    if (status == NTStatus.STATUS_SUCCESS || status == NTStatus.STATUS_CANCELLED)
+                    if (status == NTStatus.STATUS_SUCCESS ||
+                        status == NTStatus.STATUS_CANCELLED ||
+                        status == NTStatus.STATUS_NOT_SUPPORTED) // See ChangeNotifyHelper.cs
                     {
                         state.RemoveAsyncContext(context);
                         // [MS-SMB2] If the target request is successfully canceled, the target request MUST be failed by sending
@@ -39,6 +41,7 @@ namespace SMBLibrary.Server.SMB2
                         return response;
                     }
                     // [MS-SMB2] If the target request is not successfully canceled [..] no response is sent.
+                    // Note: Failing to respond might cause the client to disconnect the connection as per [MS-SMB2] 3.2.6.1 Request Expiration Timer Event
                     return null;
                 }
                 else

+ 17 - 4
SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs

@@ -30,11 +30,24 @@ namespace SMBLibrary.Server.SMB2
                 {
                     state.LogToServer(Severity.Verbose, "NotifyChange: Monitoring of '{0}{1}' started. AsyncID: {2}.", share.Name, openFile.Path, asyncContext.AsyncID);
                 }
-                // [MS-SMB2] If the underlying object store does not support change notifications, the server MUST fail this request with STATUS_NOT_SUPPORTED
+                else if (status == NTStatus.STATUS_NOT_SUPPORTED)
+                {
+                    // [MS-SMB2] If the underlying object store does not support change notifications, the server MUST fail this request with STATUS_NOT_SUPPORTED.
+                    // Unfortunately, Windows 7 / 8 / 10 will immediately retry sending another ChangeNotify request upon getting STATUS_NOT_SUPPORTED,
+                    // To prevent flooding, we must return a valid interim response (Status set to STATUS_PENDING and SMB2_FLAGS_ASYNC_COMMAND bit is set in Flags).
+                    status = NTStatus.STATUS_PENDING;
+                }
+                else
+                {
+                    state.RemoveAsyncContext(asyncContext);
+                }
+
                 ErrorResponse response = new ErrorResponse(request.CommandName, status);
-                // Windows 7 / 8 / 10 will infinitely retry sending ChangeNotify requests if the response does not have SMB2_FLAGS_ASYNC_COMMAND set.
-                response.Header.IsAsync = true;
-                response.Header.AsyncID = asyncContext.AsyncID;
+                if (status == NTStatus.STATUS_PENDING)
+                {
+                    response.Header.IsAsync = true;
+                    response.Header.AsyncID = asyncContext.AsyncID;
+                }
                 return response;
             }
         }