Beispiel #1
0
        internal void OnInput(byte[] ee)
        {
            var input = Encoding.ASCII.GetString(ee);

            //uint32 length
            //byte type
            //byte[length - 1] data payload
            SshDataWorker reader = new SshDataWorker(ee);
            SshDataWorker writer = new SshDataWorker();

            if (reader.DataAvailable >= 5)
            {
                var msglength = reader.ReadUInt32();
                var msgtype   = (RequestPacketType)(int)reader.ReadByte();

                uint   requestId    = 0;
                string path         = "";
                string absolutepath = "";
                string handle       = Guid.NewGuid().ToString().Replace("-", "");

                switch (msgtype)
                {
                case RequestPacketType.SSH_FXP_INIT:
                    var sftpclientversion = reader.ReadUInt32();
                    writer.Write((byte)RequestPacketType.SSH_FXP_VERSION);
                    var version = Math.Max(3, sftpclientversion);
                    writer.Write((uint)version);     // SFTP protocol version
                    SendPacket(writer.ToByteArray());
                    break;

                case RequestPacketType.SSH_FXP_REALPATH:

                    requestId = reader.ReadUInt32();
                    path      = reader.ReadString(Encoding.UTF8);
                    // List files in root directory for this user
                    // foreach file create a response message
                    if (path == ".")
                    {
                        path = "/";     // replace with current filepath
                    }
                    writer.Write((byte)RequestPacketType.SSH_FXP_NAME);
                    writer.Write((uint)requestId);
                    writer.Write((uint)1);
                    // Dummy file for SSH_FXP_REALPATH request
                    writer.Write(path, Encoding.UTF8);
                    writer.Write(@"-rwxr-xr-x   1 mjos     staff      348911 Mar 25 14:29 " + path, Encoding.UTF8);

                    writer.Write((uint)requestId);
                    writer.Write(uint.MaxValue);                 // flags
                    writer.Write((ulong)0);                      // size
                    writer.Write(uint.MaxValue);                 // uid
                    writer.Write(uint.MaxValue);                 // gid
                    writer.Write(uint.MaxValue);                 // permissions
                    writer.Write(GetUnixFileTime(DateTime.Now)); //atime
                    writer.Write(GetUnixFileTime(DateTime.Now)); //mtime
                    writer.Write((uint)0);                       // extended_count
                                                                 //string   extended_type blank
                                                                 //string   extended_data blank


                    SendPacket(writer.ToByteArray());

                    break;

                case RequestPacketType.SSH_FXP_READDIR:
                    requestId = reader.ReadUInt32();
                    handle    = reader.ReadString(Encoding.UTF8);

                    if (HandleToPathDictionary.ContainsKey(handle))     // remove after handle is used first time
                    {
                        var relativepath = HandleToPathDictionary[handle];
                        absolutepath = UserRootDirectory + relativepath;

                        System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(absolutepath);
                        var allfiles = di.GetFiles();

                        // returns SSH_FXP_NAME or SSH_FXP_STATUS with SSH_FX_EOF
                        writer.Write((byte)RequestPacketType.SSH_FXP_NAME);
                        writer.Write((uint)requestId);
                        writer.Write((uint)allfiles.Count());     // all files at the same time

                        foreach (var file in allfiles)
                        {
                            writer.Write(GetFileWithAttributes(file));
                        }

                        SendPacket(writer.ToByteArray());

                        HandleToPathDictionary.Remove(handle);     // remove will return EOF next time
                    }
                    else
                    {
                        // return SSH_FXP_STATUS indicating SSH_FX_EOF  when all files have been listed
                        writer.Write((byte)RequestPacketType.SSH_FXP_STATUS);
                        writer.Write((uint)requestId);
                        writer.Write((uint)SftpStatusType.SSH_FX_EOF);     // status code
                        //writer.Write("", Encoding.UTF8);
                        //writer.Write("", Encoding.UTF8);
                        SendPacket(writer.ToByteArray());
                    }

                    break;

                case RequestPacketType.SSH_FXP_OPENDIR:
                    requestId = reader.ReadUInt32();
                    path      = reader.ReadString(Encoding.UTF8);

                    HandleToPathDictionary.Add(handle, path);

                    writer.Write((byte)RequestPacketType.SSH_FXP_HANDLE);
                    writer.Write((uint)requestId);
                    writer.Write(handle, Encoding.UTF8);
                    // returns SSH_FXP_HANDLE on success or a SSH_FXP_STATUS message on fail

                    SendPacket(writer.ToByteArray());

                    _logger.LogInformation($"sftp command {msgtype} request Id: \"{requestId}\". path: {path} on channel: {channel}");

                    break;

                case RequestPacketType.SSH_FXP_STAT:     // follows symbolic links
                case RequestPacketType.SSH_FXP_LSTAT:    // does not follow symbolic links
                    requestId = reader.ReadUInt32();
                    path      = reader.ReadString(Encoding.UTF8);

                    SendAttributes(requestId, path);

                    break;

                case RequestPacketType.SSH_FXP_FSTAT:     // SSH_FXP_FSTAT differs from the others in that it returns status information for an open file(identified by the file handle).
                    requestId = reader.ReadUInt32();
                    handle    = reader.ReadString(Encoding.UTF8);
                    if (HandleToPathDictionary.ContainsKey(handle))
                    {
                        path = HandleToPathDictionary[handle];
                        SendAttributes(requestId, path);
                    }
                    else
                    {
                        SendStatus(requestId, SftpStatusType.SSH_FX_NO_SUCH_FILE);
                    }

                    break;

                case RequestPacketType.SSH_FXP_CLOSE:
                    requestId = reader.ReadUInt32();
                    handle    = reader.ReadString(Encoding.UTF8);

                    if (HandleToPathDictionary.ContainsKey(handle))
                    {
                        HandleToPathDictionary.Remove(handle);
                    }

                    SendStatus(requestId, SftpStatusType.SSH_FX_OK);



                    break;

                case RequestPacketType.SSH_FXP_OPEN:

                    requestId = reader.ReadUInt32();              //uint32 request-id
                    path      = reader.ReadString(Encoding.UTF8); // //string filename [UTF-8]

                    HandleToPathDictionary.Add(handle, path);

                    var desired_access = reader.ReadUInt32();
                    var flags          = reader.ReadUInt32();

                    //uint32 desired-access
                    var write  = desired_access & (uint)FileSystemOperation.Write;
                    var read   = desired_access & (uint)FileSystemOperation.Read;
                    var create = desired_access & (uint)FileSystemOperation.Create;
                    //uint32 flags
                    //ATTRS  attrs
                    absolutepath = UserRootDirectory + path;
                    System.IO.FileInfo fi = new System.IO.FileInfo(absolutepath);

                    if (read > 0 && write == 0 && create == 0)
                    {
                        try
                        {
                            var fs = fi.OpenRead();
                            HandleToFileStreamDictionary.Add(handle, fs);
                        }
                        catch
                        {
                            SendStatus(requestId, SftpStatusType.SSH_FX_PERMISSION_DENIED);
                        }
                    }

                    writer.Write((byte)RequestPacketType.SSH_FXP_HANDLE);
                    writer.Write((uint)requestId);
                    writer.Write(handle, Encoding.UTF8);
                    // returns SSH_FXP_HANDLE on success or a SSH_FXP_STATUS message on fail

                    SendPacket(writer.ToByteArray());

                    break;

                case RequestPacketType.SSH_FXP_READ:
                    requestId = reader.ReadUInt32();     //uint32 request-id
                    handle    = reader.ReadString(Encoding.UTF8);
                    if (HandleToPathDictionary.ContainsKey(handle))
                    {
                        var fs     = HandleToFileStreamDictionary[handle];
                        var offset = (long)reader.ReadUInt64();
                        var length = (int)reader.ReadUInt32();
                        var buffer = new byte[length];



                        if (fs.Length - offset < 0)     // EOF already reached
                        {
                            SendStatus((uint)requestId, SftpStatusType.SSH_FX_EOF);

                            break;
                        }


                        writer.Write((byte)RequestPacketType.SSH_FXP_DATA);
                        writer.Write((uint)requestId);

                        if (fs.Length - offset < length)
                        {
                            buffer = new byte[fs.Length - offset];
                        }

                        fs.Seek(offset, SeekOrigin.Begin);
                        fs.Read(buffer);


                        writer.WriteBinary(buffer);


                        SendPacket(writer.ToByteArray());
                    }
                    else
                    {
                        // send invalid handle: SSH_FX_INVALID_HANDLE
                    }

                    break;

                default:
                    // unsupported command
                    _logger.LogWarning($"Unsupported sftp command {msgtype.ToString()} input: \"{input}\". on channel: {channel}");

                    SendStatus(requestId, SftpStatusType.SSH_FX_OP_UNSUPPORTED);
                    break;
                }
            }
        }