module HrrRbSftp
hrr_rb_sftp is a pure Ruby SFTP server implementation. hrr_rb_sftp now supports SFTP protocol version 1, 2, and 3. hrr_rb_sftp can be run on SSH 2.0 server like OpenSSH or hrr_rb_ssh.
It is straightforward to implement SFTP server on SSH 2.0 server library written in Ruby like hrr_rb_ssh. There are two ways to work with hrr_rb_ssh, on same process or spawning child process. On both cases, hrr_rb_ssh's request handler mechanism is used.
To run hrr_rb_sftp server on the same process that hrr_rb_ssh is running, instantiate and start the hrr_rb_sftp server in a sftp subsystem request. On the other hand, because the arguments for the hrr_rb_sftp server can be standard input, output, and error, so hrr_rb_sftp can be a independent program and be spawned as a child process.
OpenSSH has capability to run user-defined subsystems. Subsystems that the OpenSSH server recognizes are listed in /etc/ssh/sshd_config file. Usually SFTP subsystem is defined by default to use OpenSSH's SFTP server implementation. hrr_rb_sftp can be an alternative with replacing the line in the config file. (After editing the config, reloading or restarting sshd is required.)
The following extensions are supported.
- hardlink@openssh.com - fsync@openssh.com - posix-rename@openssh.com - lsetstat@openssh.com
@note
- Reversal of SSH_FXP_SYMLINK arguments Because OpenSSH's sftp-server implementation takes SSH_FXP_SYMLINK request linkpath and targetpath arguments in reverse order, this library follows it. The SSH_FXP_SYMLINK request format is as follows: uint32 id string targetpath string linkpath
@example On the same process that hrr_rb_ssh is running
subsys = HrrRbSsh::Connection::RequestHandler.new { |ctx| ctx.chain_proc { |chain| case ctx.subsystem_name when 'sftp' begin sftp_server = HrrRbSftp::Server.new(logger: nil) sftp_server.start(ctx.io[0], ctx.io[1], ctx.io[2]) exitstatus = 0 rescue exitstatus = 1 end else # Do something for other subsystem, or just return exitstatus exitstatus = 0 end exitstatus } } options['connection_channel_request_subsystem'] = subsys
@example Spawnning SFTP server process
subsys = HrrRbSsh::Connection::RequestHandler.new { |ctx| ctx.chain_proc { |chain| case ctx.subsystem_name when 'sftp' pid = spawn("/path/to/hrr_rb_sftp_server.rb", {in: ctx.io[0], out: ctx.io[1], err: ctx.io[2]}) exitstatus = Process.waitpid(pid).to_i else # Do something for other subsystem, or just return exitstatus exitstatus = 0 end exitstatus } } options['connection_channel_request_subsystem'] = subsys
@example hrr_rb_sftp_server.rb
#!/usr/bin/env ruby require "hrr_rb_sftp" server = HrrRbSftp::Server.new(logger: nil) server.start($stdin, $stdout, $stderr)
@example Replacing OpenSSH's sftp-server
$ cat /etc/ssh/sshd_config | grep Subsystem #Subsystem sftp /usr/lib/openssh/sftp-server # Comment out the original line Subsystem sftp /path/to/hrr_rb_sftp_server.rb
Constants
- VERSION
hrr_rb_sftp library version.