diff --git a/SMBLibrary/Server/Helpers/NTFileSystemHelper.Find.cs b/SMBLibrary/Server/Helpers/NTFileSystemHelper.Find.cs
index d44fcb6..d2150bd 100644
--- a/SMBLibrary/Server/Helpers/NTFileSystemHelper.Find.cs
+++ b/SMBLibrary/Server/Helpers/NTFileSystemHelper.Find.cs
@@ -13,11 +13,6 @@ namespace SMBLibrary.Server
{
public partial class NTFileSystemHelper
{
- // Windows servers will return "." and ".." when enumerating directory files, Windows clients do not require it.
- // It seems that Ubuntu 10.04.4 and 13.10 expect at least one entry in the response (so empty directory listing cause a problem when omitting both).
- private const bool IncludeCurrentDirectoryInResults = true;
- private const bool IncludeParentDirectoryInResults = true;
-
// Filename pattern examples:
// '\Directory' - Get the directory entry
// '\Directory\*' - List the directory files
@@ -27,55 +22,75 @@ namespace SMBLibrary.Server
/// The filename pattern to search for. This field MAY contain wildcard characters
/// null if the path does not exist
///
- public static List FindEntries(IFileSystem fileSystem, string path)
+ public static NTStatus FindEntries(out List entries, IFileSystem fileSystem, string fileNamePattern)
{
- bool isDirectoryEnumeration = false;
- string searchPattern = String.Empty;
- if (path.Contains("*") || path.Contains("<"))
+ int separatorIndex = fileNamePattern.LastIndexOf('\\');
+ if (separatorIndex >= 0)
{
- isDirectoryEnumeration = true;
- int separatorIndex = path.LastIndexOf('\\');
- searchPattern = path.Substring(separatorIndex + 1);
- path = path.Substring(0, separatorIndex + 1);
- }
- bool exactNameWithoutExtension = searchPattern.Contains("\"");
-
- FileSystemEntry entry = fileSystem.GetEntry(path);
- if (entry == null)
- {
- return null;
- }
-
- List entries;
- if (isDirectoryEnumeration)
- {
- entries = fileSystem.ListEntriesInDirectory(path);
-
- if (searchPattern != String.Empty)
- {
- entries = GetFiltered(entries, searchPattern);
- }
-
- if (!exactNameWithoutExtension)
- {
- if (IncludeParentDirectoryInResults)
- {
- entries.Insert(0, fileSystem.GetEntry(FileSystem.GetParentDirectory(path)));
- entries[0].Name = "..";
- }
- if (IncludeCurrentDirectoryInResults)
- {
- entries.Insert(0, fileSystem.GetEntry(path));
- entries[0].Name = ".";
- }
- }
+ string path = fileNamePattern.Substring(0, separatorIndex + 1);
+ string expression = fileNamePattern.Substring(separatorIndex + 1);
+ return FindEntries(out entries, fileSystem, path, expression);
}
else
{
+ entries = null;
+ return NTStatus.STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /// Expression as described in [MS-FSA] 2.1.4.4
+ /// null if the path does not exist
+ public static NTStatus FindEntries(out List entries, IFileSystem fileSystem, string path, string expression)
+ {
+ entries = null;
+ FileSystemEntry entry = fileSystem.GetEntry(path);
+ if (entry == null)
+ {
+ return NTStatus.STATUS_NO_SUCH_FILE;
+ }
+
+ if (expression == String.Empty)
+ {
+ return NTStatus.STATUS_INVALID_PARAMETER;
+ }
+
+ bool findExactName = !ContainsWildcardCharacters(expression);
+
+ if (!findExactName)
+ {
+ try
+ {
+ entries = fileSystem.ListEntriesInDirectory(path);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ return NTStatus.STATUS_ACCESS_DENIED;
+ }
+
+ entries = GetFiltered(entries, expression);
+
+ // Windows will return "." and ".." when enumerating directory files.
+ // The SMB1 / SMB2 specifications mandate that when zero entries are found, the server SHOULD / MUST return STATUS_NO_SUCH_FILE.
+ // For this reason, we MUST include the current directory and/or parent directory when enumerating a directory
+ // in order to diffrentiate between a directory that does not exist and a directory with no entries.
+ FileSystemEntry currentDirectory = fileSystem.GetEntry(path);
+ currentDirectory.Name = ".";
+ FileSystemEntry parentDirectory = fileSystem.GetEntry(FileSystem.GetParentDirectory(path));
+ parentDirectory.Name = "..";
+ entries.Insert(0, parentDirectory);
+ entries.Insert(0, currentDirectory);
+ }
+ else
+ {
+ entry = fileSystem.GetEntry(path + expression);
+ if (entry == null)
+ {
+ return NTStatus.STATUS_NO_SUCH_FILE;
+ }
entries = new List();
entries.Add(entry);
}
- return entries;
+ return NTStatus.STATUS_SUCCESS;
}
/// Expression as described in [MS-FSA] 2.1.4.4
@@ -97,6 +112,11 @@ namespace SMBLibrary.Server
return result;
}
+ private static bool ContainsWildcardCharacters(string expression)
+ {
+ return (expression.Contains("?") || expression.Contains("*") || expression.Contains("\"") || expression.Contains(">") || expression.Contains("<"));
+ }
+
// [MS-FSA] 2.1.4.4
// The FileName is string compared with Expression using the following wildcard rules:
// * (asterisk) Matches zero or more characters.
diff --git a/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs b/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs
index ee2cfe7..fc3bc46 100644
--- a/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs
+++ b/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs
@@ -22,19 +22,17 @@ namespace SMBLibrary.Server.SMB1
string fileNamePattern = subcommand.FileName;
List entries;
- try
+ NTStatus searchStatus = NTFileSystemHelper.FindEntries(out entries, fileSystem, fileNamePattern);
+ if (searchStatus != NTStatus.STATUS_SUCCESS)
{
- entries = NTFileSystemHelper.FindEntries(fileSystem, fileNamePattern);
- }
- catch (UnauthorizedAccessException)
- {
- header.Status = NTStatus.STATUS_ACCESS_DENIED;
+ state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', NTStatus: {1}", fileNamePattern, searchStatus.ToString());
+ header.Status = searchStatus;
return null;
}
- state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', found {1} matching entries", fileNamePattern, entries != null ? entries.Count.ToString() : "no");
+ state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', found {1} matching entries", fileNamePattern, entries.Count);
// [MS-CIFS] If no matching entries are found, the server SHOULD fail the request with STATUS_NO_SUCH_FILE.
- if (entries == null || entries.Count == 0)
+ if (entries.Count == 0)
{
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
return null;