[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-157]

change SubsystemHandler/SFTPServerInterface API
change the API of SubsystemHandler to accept a reference to the
ServerInstance object during construction.  this will break all code
that currently creates subsystem handlers (like sftp servers) -- sorry!

lots of little doc fixups (mostly indenting).
This commit is contained in:
Robey Pointer 2005-04-06 07:24:28 +00:00
parent 5d8d1938fa
commit 71a337ee08
5 changed files with 80 additions and 59 deletions

View File

@ -72,10 +72,10 @@ class ServerInterface (object):
C{OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED}. C{OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED}.
@param kind: the kind of channel the client would like to open @param kind: the kind of channel the client would like to open
(usually C{"session"}). (usually C{"session"}).
@type kind: str @type kind: str
@param chanid: ID of the channel, required to create a new L{Channel} @param chanid: ID of the channel, required to create a new L{Channel}
object. object.
@type chanid: int @type chanid: int
@return: a success or failure code (listed above). @return: a success or failure code (listed above).
@rtype: int @rtype: int
@ -115,7 +115,7 @@ class ServerInterface (object):
@param username: the username of the client. @param username: the username of the client.
@type username: str @type username: str
@return: L{AUTH_FAILED} if the authentication fails; @return: L{AUTH_FAILED} if the authentication fails;
L{AUTH_SUCCESSFUL} if it succeeds. L{AUTH_SUCCESSFUL} if it succeeds.
@rtype: int @rtype: int
""" """
return AUTH_FAILED return AUTH_FAILED
@ -140,9 +140,9 @@ class ServerInterface (object):
@param password: the password given by the client. @param password: the password given by the client.
@type password: str @type password: str
@return: L{AUTH_FAILED} if the authentication fails; @return: L{AUTH_FAILED} if the authentication fails;
L{AUTH_SUCCESSFUL} if it succeeds; L{AUTH_SUCCESSFUL} if it succeeds;
L{AUTH_PARTIALLY_SUCCESSFUL} if the password auth is L{AUTH_PARTIALLY_SUCCESSFUL} if the password auth is
successful, but authentication must continue. successful, but authentication must continue.
@rtype: int @rtype: int
""" """
return AUTH_FAILED return AUTH_FAILED
@ -173,9 +173,9 @@ class ServerInterface (object):
@param key: the key object provided by the client. @param key: the key object provided by the client.
@type key: L{PKey <pkey.PKey>} @type key: L{PKey <pkey.PKey>}
@return: L{AUTH_FAILED} if the client can't authenticate @return: L{AUTH_FAILED} if the client can't authenticate
with this key; L{AUTH_SUCCESSFUL} if it can; with this key; L{AUTH_SUCCESSFUL} if it can;
L{AUTH_PARTIALLY_SUCCESSFUL} if it can authenticate with L{AUTH_PARTIALLY_SUCCESSFUL} if it can authenticate with
this key but must continue with authentication. this key but must continue with authentication.
@rtype: int @rtype: int
""" """
return AUTH_FAILED return AUTH_FAILED
@ -230,13 +230,13 @@ class ServerInterface (object):
@param height: height of screen in characters. @param height: height of screen in characters.
@type height: int @type height: int
@param pixelwidth: width of screen in pixels, if known (may be C{0} if @param pixelwidth: width of screen in pixels, if known (may be C{0} if
unknown). unknown).
@type pixelwidth: int @type pixelwidth: int
@param pixelheight: height of screen in pixels, if known (may be C{0} @param pixelheight: height of screen in pixels, if known (may be C{0}
if unknown). if unknown).
@type pixelheight: int @type pixelheight: int
@return: C{True} if the psuedo-terminal has been allocated; C{False} @return: C{True} if the psuedo-terminal has been allocated; C{False}
otherwise. otherwise.
@rtype: bool @rtype: bool
""" """
return False return False
@ -253,7 +253,7 @@ class ServerInterface (object):
@param channel: the L{Channel} the pty request arrived on. @param channel: the L{Channel} the pty request arrived on.
@type channel: L{Channel} @type channel: L{Channel}
@return: C{True} if this channel is now hooked up to a shell; C{False} @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 @rtype: bool
""" """
return False return False
@ -292,21 +292,21 @@ class ServerInterface (object):
C{True}. Otherwise it returns C{False}. C{True}. Otherwise it returns C{False}.
@note: Because the default implementation uses the L{Transport} to @note: Because the default implementation uses the L{Transport} to
identify valid subsystems, you probably won't need to override this identify valid subsystems, you probably won't need to override this
method. method.
@param channel: the L{Channel} the pty request arrived on. @param channel: the L{Channel} the pty request arrived on.
@type channel: L{Channel} @type channel: L{Channel}
@param name: name of the requested subsystem. @param name: name of the requested subsystem.
@type name: str @type name: str
@return: C{True} if this channel is now hooked up to the requested @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 @rtype: bool
""" """
handler_class, larg, kwarg = channel.get_transport()._get_subsystem_handler(name) handler_class, larg, kwarg = channel.get_transport()._get_subsystem_handler(name)
if handler_class is None: if handler_class is None:
return False return False
handler = handler_class(channel, name, *larg, **kwarg) handler = handler_class(channel, name, self, *larg, **kwarg)
handler.start() handler.start()
return True return True
@ -324,10 +324,10 @@ class ServerInterface (object):
@param height: height of screen in characters. @param height: height of screen in characters.
@type height: int @type height: int
@param pixelwidth: width of screen in pixels, if known (may be C{0} if @param pixelwidth: width of screen in pixels, if known (may be C{0} if
unknown). unknown).
@type pixelwidth: int @type pixelwidth: int
@param pixelheight: height of screen in pixels, if known (may be C{0} @param pixelheight: height of screen in pixels, if known (may be C{0}
if unknown). if unknown).
@type pixelheight: int @type pixelheight: int
@return: C{True} if the terminal was resized; C{False} if not. @return: C{True} if the terminal was resized; C{False} if not.
@rtype: bool @rtype: bool
@ -353,7 +353,7 @@ class SubsystemHandler (threading.Thread):
@since: ivysaur @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} 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 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} @type channel: L{Channel}
@param name: name of the requested subsystem. @param name: name of the requested subsystem.
@type name: str @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) threading.Thread.__init__(self, target=self._run)
self.__channel = channel self.__channel = channel
self.__transport = channel.get_transport() self.__transport = channel.get_transport()
self.__name = name 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): def _run(self):
try: try:
@ -396,12 +409,11 @@ class SubsystemHandler (threading.Thread):
corresponds to exactly one L{Channel} on one L{Transport}. corresponds to exactly one L{Channel} on one L{Transport}.
@note: It is the responsibility of this method to exit if the @note: It is the responsibility of this method to exit if the
underlying L{Transport} is closed. This can be done by checking underlying L{Transport} is closed. This can be done by checking
L{Transport.is_active <BaseTransport.is_active>} or noticing an EOF L{Transport.is_active <BaseTransport.is_active>} or noticing an EOF
on the L{Channel}. on the L{Channel}. If this method loops forever without checking
If this method loops forever without checking for this case, your for this case, your python interpreter may refuse to exit because
python interpreter may refuse to exit because this thread will still this thread will still be running.
be running.
@param name: name of the requested subsystem. @param name: name of the requested subsystem.
@type name: str @type name: str

View File

@ -37,37 +37,35 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
Use L{Transport.set_subsystem_handler} to activate this class. 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 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} L{Transport} as a subsystem handler. C{server} and any additional
parameters are passed from the original call to parameters or keyword parameters are passed from the original call to
L{Transport.set_subsystem_handler}. L{Transport.set_subsystem_handler}.
@param channel: channel passed from the L{Transport}. @param channel: channel passed from the L{Transport}.
@type channel: L{Channel} @type channel: L{Channel}
@param name: name of the requested subsystem. @param name: name of the requested subsystem.
@type name: str @type name: str
@param server: a subclass of L{SFTPServerInterface} to use for handling @param server: the server object associated with this channel and
individual requests. subsystem
@type server: class @type server: L{ServerInterface}
@param server_args: keyword parameters to pass to C{server} when it's @param sftp_si: a subclass of L{SFTPServerInterface} to use for handling
constructed. individual requests.
@type server_args: dict @type sftp_si: class
""" """
BaseSFTP.__init__(self) BaseSFTP.__init__(self)
SubsystemHandler.__init__(self, channel, name) SubsystemHandler.__init__(self, channel, name, server)
transport = channel.get_transport() transport = channel.get_transport()
self.logger = util.get_logger(transport.get_log_channel() + '.' + self.logger = util.get_logger(transport.get_log_channel() + '.' +
channel.get_name() + '.sftp') channel.get_name() + '.sftp')
self.ultra_debug = transport.ultra_debug self.ultra_debug = transport.ultra_debug
self.next_handle = 1 self.next_handle = 1
# map of handle-string to SFTPHandle for files & folders: # map of handle-string to SFTPHandle for files & folders:
self.file_table = { } self.file_table = { }
self.folder_table = { } self.folder_table = { }
if server_args is None: self.server = sftp_si(server, *largs, **kwargs)
server_args = {}
self.server = server(**server_args)
def start_subsystem(self, name, transport, channel): def start_subsystem(self, name, transport, channel):
self.sock = channel self.sock = channel

View File

@ -37,6 +37,17 @@ class SFTPServerInterface (object):
session to abruptly end, so you will usually want to catch exceptions and session to abruptly end, so you will usually want to catch exceptions and
return an appropriate error code. 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): def session_started(self):
""" """
@ -80,13 +91,13 @@ class SFTPServerInterface (object):
the client didn't specify them. the client didn't specify them.
@note: The SFTP protocol defines all files to be in "binary" mode. @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 @param path: the requested path (relative or absolute) of the file
to be opened. to be opened.
@type path: str @type path: str
@param flags: flags or'd together from the C{os} module indicating the @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 @type flags: int
@param attr: requested attributes of the file if it is newly created. @param attr: requested attributes of the file if it is newly created.
@type attr: L{SFTPAttributes} @type attr: L{SFTPAttributes}
@ -114,7 +125,7 @@ class SFTPServerInterface (object):
@param path: the requested path (relative or absolute) to be listed. @param path: the requested path (relative or absolute) to be listed.
@type path: str @type path: str
@return: a list of the files in the given folder, using @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} @rtype: list of L{SFTPAttributes} I{or error code}
@note: You should normalize the given C{path} first (see the @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.) call that doesn't follow symlinks/aliases.)
@param path: the requested path (relative or absolute) to fetch @param path: the requested path (relative or absolute) to fetch
file statistics for. file statistics for.
@type path: str @type path: str
@return: an attributes object for the given file, or an SFTP error @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} @rtype: L{SFTPAttributes} I{or error code}
""" """
return SFTP_OP_UNSUPPORTED return SFTP_OP_UNSUPPORTED
@ -150,10 +161,10 @@ class SFTPServerInterface (object):
corresponding call that follows symlinks/aliases.) corresponding call that follows symlinks/aliases.)
@param path: the requested path (relative or absolute) to fetch @param path: the requested path (relative or absolute) to fetch
file statistics for. file statistics for.
@type path: str @type path: str
@return: an attributes object for the given file, or an SFTP error @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} @rtype: L{SFTPAttributes} I{or error code}
""" """
return SFTP_OP_UNSUPPORTED return SFTP_OP_UNSUPPORTED
@ -163,7 +174,7 @@ class SFTPServerInterface (object):
Delete a file, if possible. Delete a file, if possible.
@param path: the requested path (relative or absolute) of the file @param path: the requested path (relative or absolute) of the file
to delete. to delete.
@type path: str @type path: str
@return: an SFTP error code like L{SFTP_OK}. @return: an SFTP error code like L{SFTP_OK}.
@rtype: int @rtype: int
@ -179,11 +190,11 @@ class SFTPServerInterface (object):
files that cross disk partition boundaries, if at all possible. files that cross disk partition boundaries, if at all possible.
@note: You should return an error if a file with the same name as @note: You should return an error if a file with the same name as
C{newpath} already exists. (The rename operation should be C{newpath} already exists. (The rename operation should be
non-desctructive.) non-desctructive.)
@param oldpath: the requested path (relative or absolute) of the @param oldpath: the requested path (relative or absolute) of the
existing file. existing file.
@type oldpath: str @type oldpath: str
@param newpath: the requested new path of the file. @param newpath: the requested new path of the file.
@type newpath: str @type newpath: str
@ -203,7 +214,7 @@ class SFTPServerInterface (object):
object may be completely empty. object may be completely empty.
@param path: requested path (relative or absolute) of the new @param path: requested path (relative or absolute) of the new
folder. folder.
@type path: str @type path: str
@param attr: requested attributes of the new folder. @param attr: requested attributes of the new folder.
@type attr: L{SFTPAttributes} @type attr: L{SFTPAttributes}
@ -219,7 +230,7 @@ class SFTPServerInterface (object):
error. error.
@param path: requested path (relative or absolute) of the folder @param path: requested path (relative or absolute) of the folder
to remove. to remove.
@type path: str @type path: str
@return: an SFTP error code like L{SFTP_OK}. @return: an SFTP error code like L{SFTP_OK}.
@rtype: int @rtype: int
@ -233,7 +244,7 @@ class SFTPServerInterface (object):
should check for the presence of fields before using them. should check for the presence of fields before using them.
@param path: requested path (relative or absolute) of the file to @param path: requested path (relative or absolute) of the file to
change. change.
@type path: str @type path: str
@param attr: requested attributes to change on the file. @param attr: requested attributes to change on the file.
@type attr: L{SFTPAttributes} @type attr: L{SFTPAttributes}

View File

@ -762,7 +762,7 @@ class BaseTransport (threading.Thread):
def set_subsystem_handler(self, name, handler, *larg, **kwarg): 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 for this subsystem is made on an open ssh channel later, this handler
will be constructed and called -- see L{SubsystemHandler} for more will be constructed and called -- see L{SubsystemHandler} for more
detailed documentation. detailed documentation.
@ -773,7 +773,7 @@ class BaseTransport (threading.Thread):
@param name: name of the subsystem. @param name: name of the subsystem.
@type name: str @type name: str
@param handler: subclass of L{SubsystemHandler} that handles this @param handler: subclass of L{SubsystemHandler} that handles this
subsystem. subsystem.
@type handler: class @type handler: class
""" """
try: try:

View File

@ -56,7 +56,7 @@ class StubSFTPServer (SFTPServerInterface):
# assume current folder is a fine root # assume current folder is a fine root
# (the tests always create and eventualy delete a subfolder, so there shouldn't be any mess) # (the tests always create and eventualy delete a subfolder, so there shouldn't be any mess)
ROOT = os.getcwd() ROOT = os.getcwd()
def _realpath(self, path): def _realpath(self, path):
return self.ROOT + self.canonicalize(path) return self.ROOT + self.canonicalize(path)