diff --git a/PUP/BSP/BSPChannel.cs b/PUP/BSP/BSPChannel.cs index 175129c..c8c9c5b 100644 --- a/PUP/BSP/BSPChannel.cs +++ b/PUP/BSP/BSPChannel.cs @@ -508,6 +508,20 @@ namespace IFS.BSP Log.Write(LogType.Verbose, LogComponent.BSP, "ACK sent."); } + public void RecvError(PUP errorPup) + { + // For now, just log this. + Log.Write(LogType.Error, LogComponent.BSP, + "Error from client, unhandled."); + } + + public void RecvInterrupt(PUP interruptPup) + { + // For now, just log this. No IFS protcols yet implemented require use of interrupts. + Log.Write(LogType.Error, LogComponent.BSP, + "Interrupt from client, unhandled."); + } + /// /// Sends a PUP. Will block if client is unable to receive data. If timeouts expire, channel will be shut down. /// diff --git a/PUP/BSP/BSPManager.cs b/PUP/BSP/BSPManager.cs index b2f0243..877bb23 100644 --- a/PUP/BSP/BSPManager.cs +++ b/PUP/BSP/BSPManager.cs @@ -17,17 +17,6 @@ namespace IFS.BSP public ushort BytesSent; } - public abstract class BSPProtocol : PUPProtocolBase - { - public abstract void InitializeServerForChannel(BSPChannel channel); - } - - public enum BSPState - { - Unconnected, - Connected - } - public delegate void WorkerExitDelegate(BSPWorkerBase destroyed); public abstract class BSPWorkerBase @@ -169,6 +158,18 @@ namespace IFS.BSP } break; + case PupType.Error: + { + channel.RecvError(p); + } + break; + + case PupType.Interrupt: + { + channel.RecvInterrupt(p); + } + break; + default: throw new NotImplementedException(String.Format("Unhandled BSP PUP type {0}.", p.Type)); diff --git a/PUP/Conf/ifs.cfg b/PUP/Conf/ifs.cfg index f946d25..99fce23 100644 --- a/PUP/Conf/ifs.cfg +++ b/PUP/Conf/ifs.cfg @@ -6,7 +6,7 @@ # Debug settings -LogTypes = Normal +LogTypes = All LogComponents = All # Normal configuration diff --git a/PUP/CopyDisk/CopyDiskServer.cs b/PUP/CopyDisk/CopyDiskServer.cs index 11a972c..275a4bb 100644 --- a/PUP/CopyDisk/CopyDiskServer.cs +++ b/PUP/CopyDisk/CopyDiskServer.cs @@ -34,6 +34,10 @@ namespace IFS.CopyDisk UnitWriteProtected = 2, OverwriteNotAllowed = 3, UnknownCommand = 4, + IllegalUserName = 16, + IllegalOrIncorrectPassword = 17, + IllegalConnectName = 18, + IllegalConnectPassword = 19, } struct VersionYesNoBlock @@ -280,21 +284,30 @@ namespace IFS.CopyDisk { LoginBlock login = (LoginBlock)Serializer.Deserialize(data, typeof(LoginBlock)); - Log.Write(LogType.Verbose, LogComponent.CopyDisk, "Login is for user {0}, password {1}, connection {2}, connection password {3}.", + Log.Write(LogType.Verbose, LogComponent.CopyDisk, "Login is for user '{0}', password '{1}', connection '{2}', connection password '{3}'.", login.UserName, login.UserPassword, login.ConnName, login.ConnPassword); - // - // TODO: for now we allow anyone in with any username and password, this needs to be fixed once - // an authentication mechanism is set up. - // + _userToken = AuthenticateUser(login.UserName.ToString(), login.UserPassword.ToString()); - // Send a "Yes" response back. - // - VersionYesNoBlock yes = new VersionYesNoBlock(CopyDiskBlock.Yes, 0, "Come on in, the water's fine."); - _channel.Send(Serializer.Serialize(yes)); + if (_userToken != null) + { + // + // Send a "Yes" response back. + // + VersionYesNoBlock yes = new VersionYesNoBlock(CopyDiskBlock.Yes, 0, "Come on in, the water's fine."); + _channel.Send(Serializer.Serialize(yes)); + } + else + { + // + // Send a "No" response back indicating the login failure. + // + VersionYesNoBlock no = new VersionYesNoBlock(CopyDiskBlock.No, (ushort)NoCode.IllegalOrIncorrectPassword, "Invalid username or password."); + _channel.Send(Serializer.Serialize(no), true); + } } break; @@ -408,6 +421,17 @@ namespace IFS.CopyDisk _startAddress = _pack.DiskAddressToVirtualAddress(transferParameters.StartAddress); _endAddress = _pack.DiskAddressToVirtualAddress(transferParameters.EndAddress); + // Validate that the user is allowed to store. + if (blockType == CopyDiskBlock.StoreDisk) + { + if (_userToken.Privileges != IFSPrivileges.ReadWrite) + { + VersionYesNoBlock no = new VersionYesNoBlock(CopyDiskBlock.No, (ushort)NoCode.UnitWriteProtected, "You do not have permission to store disk images."); + _channel.Send(Serializer.Serialize(no)); + break; + } + } + Log.Write(LogType.Verbose, LogComponent.CopyDisk, "Transfer is from block {0} to block {1}", transferParameters.StartAddress, transferParameters.EndAddress); // Validate start/end parameters @@ -419,7 +443,7 @@ namespace IFS.CopyDisk _channel.Send(Serializer.Serialize(no)); } else - { + { // We're OK. Save the parameters and send a Yes response. VersionYesNoBlock yes = new VersionYesNoBlock(CopyDiskBlock.Yes, 0, "You are cleared for launch."); _channel.Send(Serializer.Serialize(yes)); @@ -564,6 +588,22 @@ namespace IFS.CopyDisk } } + private UserToken AuthenticateUser(string userName, string password) + { + // + // If no username is specified then we default to the guest account. + // + if (string.IsNullOrEmpty(userName)) + { + return UserToken.Guest; + } + + UserToken user = Authentication.Authenticate(userName, password); + + return user; + + } + /// /// Builds a relative path to the directory that holds the disk images. /// @@ -577,6 +617,9 @@ namespace IFS.CopyDisk private Thread _workerThread; private bool _running; + // The user token for this transaction. We assume guest access by default. + private UserToken _userToken = UserToken.Guest; + // The pack being read / stored by this server private DiabloPack _pack = null; diff --git a/PUP/FTP/FTPServer.cs b/PUP/FTP/FTPServer.cs index 9f3ef62..c3892f5 100644 --- a/PUP/FTP/FTPServer.cs +++ b/PUP/FTP/FTPServer.cs @@ -839,6 +839,12 @@ namespace IFS.FTP /// private bool IsUserDirectory(UserToken userToken, string fullPath) { + if (string.IsNullOrEmpty(userToken.HomeDirectory)) + { + // No home directory, so by default this cannot be the user's home directory. + return false; + } + string userDirPath = Path.Combine(Configuration.FTPRoot, userToken.HomeDirectory); return fullPath.StartsWith(userDirPath, StringComparison.OrdinalIgnoreCase); }