Skip to content

Instantly share code, notes, and snippets.

@Girgitt
Created July 13, 2016 20:34
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Girgitt/2df036f9e26dba1baaddf4c5845a20a2 to your computer and use it in GitHub Desktop.
Save Girgitt/2df036f9e26dba1baaddf4c5845a20a2 to your computer and use it in GitHub Desktop.
multithreaded sftp server in python based on https://github.com/rspivak/sftpserver
import time
import socket
import optparse
import sys
import textwrap
import paramiko
from sftpserver.stub_sftp import StubServer, StubSFTPServer
import threading
HOST, PORT = 'localhost', 3373
BACKLOG = 10
class ConnHandlerThd(threading.Thread):
def __init__(self, conn, keyfile):
threading.Thread.__init__(self)
self._conn = conn
self._keyfile = keyfile
def run(self):
host_key = paramiko.RSAKey.from_private_key_file(self._keyfile)
transport = paramiko.Transport(self._conn)
transport.add_server_key(host_key)
transport.set_subsystem_handler(
'sftp', paramiko.SFTPServer, StubSFTPServer)
server = StubServer()
transport.start_server(server=server)
channel = transport.accept()
while transport.is_active():
time.sleep(1)
def start_server(host, port, keyfile, level):
paramiko_level = getattr(paramiko.common, level)
paramiko.common.logging.basicConfig(level=paramiko_level)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
server_socket.bind((host, port))
server_socket.listen(BACKLOG)
while True:
conn, addr = server_socket.accept()
srv_thd = ConnHandlerThd(conn, keyfile)
srv_thd.setDaemon(True)
srv_thd.start()
def main():
usage = """\
usage: sftpserver [options]
-k/--keyfile should be specified
"""
parser = optparse.OptionParser(usage=textwrap.dedent(usage))
parser.add_option(
'--host', dest='host', default=HOST,
help='listen on HOST [default: %default]')
parser.add_option(
'-p', '--port', dest='port', type='int', default=PORT,
help='listen on PORT [default: %default]'
)
parser.add_option(
'-l', '--level', dest='level', default='INFO',
help='Debug level: WARNING, INFO, DEBUG [default: %default]'
)
parser.add_option(
'-k', '--keyfile', dest='keyfile', metavar='FILE',
help='Path to private key, for example /tmp/test_rsa.key'
)
options, args = parser.parse_args()
if options.keyfile is None:
parser.print_help()
sys.exit(-1)
start_server(options.host, options.port, options.keyfile, options.level)
if __name__ == '__main__':
main()
@Girgitt
Copy link
Author

Girgitt commented Oct 15, 2018

Before using it please make sure the connection is actually authenticated against the configured key. I have not used this code for a while but remember a case when it was letting everyone in :)

Use at your own risk.

@cmsethi
Copy link

cmsethi commented Jan 17, 2024

yes, as you said, it's letting anybody in. Can it be set to authenticate with the key? If you have time, can you do it? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment