diff --git a/paramiko/server.py b/paramiko/server.py index 8c268d2..5e47e69 100644 --- a/paramiko/server.py +++ b/paramiko/server.py @@ -72,10 +72,10 @@ class ServerInterface (object): C{OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED}. @param kind: the kind of channel the client would like to open - (usually C{"session"}). + (usually C{"session"}). @type kind: str @param chanid: ID of the channel, required to create a new L{Channel} - object. + object. @type chanid: int @return: a success or failure code (listed above). @rtype: int @@ -115,7 +115,7 @@ class ServerInterface (object): @param username: the username of the client. @type username: str @return: L{AUTH_FAILED} if the authentication fails; - L{AUTH_SUCCESSFUL} if it succeeds. + L{AUTH_SUCCESSFUL} if it succeeds. @rtype: int """ return AUTH_FAILED @@ -140,9 +140,9 @@ class ServerInterface (object): @param password: the password given by the client. @type password: str @return: L{AUTH_FAILED} if the authentication fails; - L{AUTH_SUCCESSFUL} if it succeeds; - L{AUTH_PARTIALLY_SUCCESSFUL} if the password auth is - successful, but authentication must continue. + L{AUTH_SUCCESSFUL} if it succeeds; + L{AUTH_PARTIALLY_SUCCESSFUL} if the password auth is + successful, but authentication must continue. @rtype: int """ return AUTH_FAILED @@ -173,9 +173,9 @@ class ServerInterface (object): @param key: the key object provided by the client. @type key: L{PKey } @return: L{AUTH_FAILED} if the client can't authenticate - with this key; L{AUTH_SUCCESSFUL} if it can; - L{AUTH_PARTIALLY_SUCCESSFUL} if it can authenticate with - this key but must continue with authentication. + with this key; L{AUTH_SUCCESSFUL} if it can; + L{AUTH_PARTIALLY_SUCCESSFUL} if it can authenticate with + this key but must continue with authentication. @rtype: int """ return AUTH_FAILED @@ -230,13 +230,13 @@ class ServerInterface (object): @param height: height of screen in characters. @type height: int @param pixelwidth: width of screen in pixels, if known (may be C{0} if - unknown). + unknown). @type pixelwidth: int @param pixelheight: height of screen in pixels, if known (may be C{0} - if unknown). + if unknown). @type pixelheight: int @return: C{True} if the psuedo-terminal has been allocated; C{False} - otherwise. + otherwise. @rtype: bool """ return False @@ -253,7 +253,7 @@ class ServerInterface (object): @param channel: the L{Channel} the pty request arrived on. @type channel: L{Channel} @return: C{True} if this channel is now hooked up to a shell; C{False} - if a shell can't or won't be provided. + if a shell can't or won't be provided. @rtype: bool """ return False @@ -292,21 +292,21 @@ class ServerInterface (object): C{True}. Otherwise it returns C{False}. @note: Because the default implementation uses the L{Transport} to - identify valid subsystems, you probably won't need to override this - method. + identify valid subsystems, you probably won't need to override this + method. @param channel: the L{Channel} the pty request arrived on. @type channel: L{Channel} @param name: name of the requested subsystem. @type name: str @return: C{True} if this channel is now hooked up to the requested - subsystem; C{False} if that subsystem can't or won't be provided. + subsystem; C{False} if that subsystem can't or won't be provided. @rtype: bool """ handler_class, larg, kwarg = channel.get_transport()._get_subsystem_handler(name) if handler_class is None: return False - handler = handler_class(channel, name, *larg, **kwarg) + handler = handler_class(channel, name, self, *larg, **kwarg) handler.start() return True @@ -324,10 +324,10 @@ class ServerInterface (object): @param height: height of screen in characters. @type height: int @param pixelwidth: width of screen in pixels, if known (may be C{0} if - unknown). + unknown). @type pixelwidth: int @param pixelheight: height of screen in pixels, if known (may be C{0} - if unknown). + if unknown). @type pixelheight: int @return: C{True} if the terminal was resized; C{False} if not. @rtype: bool @@ -353,7 +353,7 @@ class SubsystemHandler (threading.Thread): @since: ivysaur """ - def __init__(self, channel, name): + def __init__(self, channel, name, server): """ Create a new handler for a channel. This is used by L{ServerInterface} to start up a new handler when a channel requests this subsystem. You @@ -365,11 +365,24 @@ class SubsystemHandler (threading.Thread): @type channel: L{Channel} @param name: name of the requested subsystem. @type name: str + @param server: the server object for the session that started this + subsystem + @rtype server: L{ServerInterface} """ threading.Thread.__init__(self, target=self._run) self.__channel = channel self.__transport = channel.get_transport() self.__name = name + self.__server = server + + def get_server(self): + """ + Return the L{ServerInterface} object associated with this channel and + subsystem. + + @rtype: L{ServerInterface} + """ + return self.__server def _run(self): try: @@ -396,12 +409,11 @@ class SubsystemHandler (threading.Thread): corresponds to exactly one L{Channel} on one L{Transport}. @note: It is the responsibility of this method to exit if the - underlying L{Transport} is closed. This can be done by checking - L{Transport.is_active } or noticing an EOF - on the L{Channel}. - If this method loops forever without checking for this case, your - python interpreter may refuse to exit because this thread will still - be running. + underlying L{Transport} is closed. This can be done by checking + L{Transport.is_active } or noticing an EOF + on the L{Channel}. If this method loops forever without checking + for this case, your python interpreter may refuse to exit because + this thread will still be running. @param name: name of the requested subsystem. @type name: str diff --git a/paramiko/sftp_server.py b/paramiko/sftp_server.py index 232069d..6797184 100644 --- a/paramiko/sftp_server.py +++ b/paramiko/sftp_server.py @@ -37,37 +37,35 @@ class SFTPServer (BaseSFTP, SubsystemHandler): Use L{Transport.set_subsystem_handler} to activate this class. """ - def __init__(self, channel, name, server=SFTPServerInterface, server_args=None): + def __init__(self, channel, name, server, sftp_si=SFTPServerInterface, *largs, **kwargs): """ The constructor for SFTPServer is meant to be called from within the - L{Transport} as a subsystem handler. The C{server} and C{server_args} - parameters are passed from the original call to + L{Transport} as a subsystem handler. C{server} and any additional + parameters or keyword parameters are passed from the original call to L{Transport.set_subsystem_handler}. @param channel: channel passed from the L{Transport}. @type channel: L{Channel} @param name: name of the requested subsystem. @type name: str - @param server: a subclass of L{SFTPServerInterface} to use for handling - individual requests. - @type server: class - @param server_args: keyword parameters to pass to C{server} when it's - constructed. - @type server_args: dict - """ + @param server: the server object associated with this channel and + subsystem + @type server: L{ServerInterface} + @param sftp_si: a subclass of L{SFTPServerInterface} to use for handling + individual requests. + @type sftp_si: class + """ BaseSFTP.__init__(self) - SubsystemHandler.__init__(self, channel, name) + SubsystemHandler.__init__(self, channel, name, server) transport = channel.get_transport() self.logger = util.get_logger(transport.get_log_channel() + '.' + - channel.get_name() + '.sftp') + channel.get_name() + '.sftp') self.ultra_debug = transport.ultra_debug self.next_handle = 1 # map of handle-string to SFTPHandle for files & folders: self.file_table = { } self.folder_table = { } - if server_args is None: - server_args = {} - self.server = server(**server_args) + self.server = sftp_si(server, *largs, **kwargs) def start_subsystem(self, name, transport, channel): self.sock = channel diff --git a/paramiko/sftp_si.py b/paramiko/sftp_si.py index 93b7d06..262cc72 100644 --- a/paramiko/sftp_si.py +++ b/paramiko/sftp_si.py @@ -37,6 +37,17 @@ class SFTPServerInterface (object): session to abruptly end, so you will usually want to catch exceptions and return an appropriate error code. """ + + def __init__ (self, server, *largs, **kwargs): + """ + Create a new SFTPServerInterface object. This method does nothing by + default and is meant to be overridden by subclasses. + + @param server: the server object associated with this channel and + SFTP subsystem + @type server: L{ServerInterface} + """ + super(SFTPServerInterface, self).__init__(*largs, **kwargs) def session_started(self): """ @@ -80,13 +91,13 @@ class SFTPServerInterface (object): the client didn't specify them. @note: The SFTP protocol defines all files to be in "binary" mode. - There is no equivalent to python's "text" mode. + There is no equivalent to python's "text" mode. @param path: the requested path (relative or absolute) of the file - to be opened. + to be opened. @type path: str @param flags: flags or'd together from the C{os} module indicating the - requested mode for opening the file. + requested mode for opening the file. @type flags: int @param attr: requested attributes of the file if it is newly created. @type attr: L{SFTPAttributes} @@ -114,7 +125,7 @@ class SFTPServerInterface (object): @param path: the requested path (relative or absolute) to be listed. @type path: str @return: a list of the files in the given folder, using - L{SFTPAttributes} objects. + L{SFTPAttributes} objects. @rtype: list of L{SFTPAttributes} I{or error code} @note: You should normalize the given C{path} first (see the @@ -133,10 +144,10 @@ class SFTPServerInterface (object): call that doesn't follow symlinks/aliases.) @param path: the requested path (relative or absolute) to fetch - file statistics for. + file statistics for. @type path: str @return: an attributes object for the given file, or an SFTP error - code (like L{SFTP_PERMISSION_DENIED}). + code (like L{SFTP_PERMISSION_DENIED}). @rtype: L{SFTPAttributes} I{or error code} """ return SFTP_OP_UNSUPPORTED @@ -150,10 +161,10 @@ class SFTPServerInterface (object): corresponding call that follows symlinks/aliases.) @param path: the requested path (relative or absolute) to fetch - file statistics for. + file statistics for. @type path: str @return: an attributes object for the given file, or an SFTP error - code (like L{SFTP_PERMISSION_DENIED}). + code (like L{SFTP_PERMISSION_DENIED}). @rtype: L{SFTPAttributes} I{or error code} """ return SFTP_OP_UNSUPPORTED @@ -163,7 +174,7 @@ class SFTPServerInterface (object): Delete a file, if possible. @param path: the requested path (relative or absolute) of the file - to delete. + to delete. @type path: str @return: an SFTP error code like L{SFTP_OK}. @rtype: int @@ -179,11 +190,11 @@ class SFTPServerInterface (object): files that cross disk partition boundaries, if at all possible. @note: You should return an error if a file with the same name as - C{newpath} already exists. (The rename operation should be - non-desctructive.) + C{newpath} already exists. (The rename operation should be + non-desctructive.) @param oldpath: the requested path (relative or absolute) of the - existing file. + existing file. @type oldpath: str @param newpath: the requested new path of the file. @type newpath: str @@ -203,7 +214,7 @@ class SFTPServerInterface (object): object may be completely empty. @param path: requested path (relative or absolute) of the new - folder. + folder. @type path: str @param attr: requested attributes of the new folder. @type attr: L{SFTPAttributes} @@ -219,7 +230,7 @@ class SFTPServerInterface (object): error. @param path: requested path (relative or absolute) of the folder - to remove. + to remove. @type path: str @return: an SFTP error code like L{SFTP_OK}. @rtype: int @@ -233,7 +244,7 @@ class SFTPServerInterface (object): should check for the presence of fields before using them. @param path: requested path (relative or absolute) of the file to - change. + change. @type path: str @param attr: requested attributes to change on the file. @type attr: L{SFTPAttributes} diff --git a/paramiko/transport.py b/paramiko/transport.py index f8a5236..8b7784d 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -762,7 +762,7 @@ class BaseTransport (threading.Thread): def set_subsystem_handler(self, name, handler, *larg, **kwarg): """ - Set the handler class for a subsystem in server mode. If a reqeuest + Set the handler class for a subsystem in server mode. If a request for this subsystem is made on an open ssh channel later, this handler will be constructed and called -- see L{SubsystemHandler} for more detailed documentation. @@ -773,7 +773,7 @@ class BaseTransport (threading.Thread): @param name: name of the subsystem. @type name: str @param handler: subclass of L{SubsystemHandler} that handles this - subsystem. + subsystem. @type handler: class """ try: diff --git a/tests/stub_sftp.py b/tests/stub_sftp.py index 639477c..4b8b9c3 100644 --- a/tests/stub_sftp.py +++ b/tests/stub_sftp.py @@ -56,7 +56,7 @@ class StubSFTPServer (SFTPServerInterface): # assume current folder is a fine root # (the tests always create and eventualy delete a subfolder, so there shouldn't be any mess) ROOT = os.getcwd() - + def _realpath(self, path): return self.ROOT + self.canonicalize(path)