From a0a372dd167808f5dcab847b11b0142c6bc8e224 Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Sat, 13 Jul 2019 18:22:51 +0300 Subject: [PATCH] Server: SMB2: Bugfix: Invalid change notify interim response was sent when the object store did not support change notifications --- SMBLibrary/Server/SMB2/CancelHelper.cs | 7 +++++-- SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs | 21 ++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/SMBLibrary/Server/SMB2/CancelHelper.cs b/SMBLibrary/Server/SMB2/CancelHelper.cs index d78f996..95625c7 100644 --- a/SMBLibrary/Server/SMB2/CancelHelper.cs +++ b/SMBLibrary/Server/SMB2/CancelHelper.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2019 Tal Aloni . 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 diff --git a/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs b/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs index 6fcbed2..edebd3d 100644 --- a/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs +++ b/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; } }