[X2go-Commits] python-x2go.git - build-main (branch) updated: 0.1.1.8

X2go dev team git-admin at x2go.org
Wed Oct 12 10:56:11 CEST 2011


The branch, build-main has been updated
       via  a9f62e1eed7eb86b0cb74533055007e35f2f9ba3 (commit)
       via  4b731c0bdc8f0628ceeac6be8bf0300c638ce242 (commit)
       via  f8fce4fb41c7419eaaa1a2c06ae20913e7059d67 (commit)
       via  8ded9d358d19af42b0f1ae3b71160ebda7d2bd30 (commit)
       via  7e6a2ed8a4bcd1b3f8b34c9fc2efc87c8375878f (commit)
       via  4efe7f08c4ff3b7c09c997e365ca0f6c4e60d942 (commit)
       via  2eaa28d9aac14d7aa40f315084013bf2346665a5 (commit)
       via  c19244a46d5323607653a98d186d9f370efcbbd9 (commit)
       via  da6002f82aca5764b23e1bd0cf6b55fc50fe0be7 (commit)
       via  c4c01249d7b06320e284f33b53d00038c34a20fa (commit)
       via  ac72309392b1eb54273b47dc83f6af6828dee146 (commit)
       via  38414aa7189e0043d65911aebcd7ba4303ecfadb (commit)
       via  cdeb38f6ada3cdc38b5095e76993b6773b2a340b (commit)
       via  fa6659cc58faadf3f92a36b89bf19ec7668c253f (commit)
       via  9ad6a08f4cb48427f72ac0b5b72bb21291e824d2 (commit)
       via  37df497bbc529a327248c2655b3788691afda1bb (commit)
       via  9ea25b87eb8667eedc2a45cf27ff80d97256df62 (commit)
      from  539ca3ee9ed07ddfce6f2a6d90f876479c8f87a9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 debian/changelog                  |   17 +++++
 x2go/__init__.py                  |    2 +-
 x2go/backends/control/_stdout.py  |   29 ++++++---
 x2go/backends/info/_stdout.py     |   11 +++-
 x2go/backends/terminal/_stdout.py |   41 ++++++++++++-
 x2go/checkhosts.py                |    5 +-
 x2go/client.py                    |   35 ++++++++++-
 x2go/monkey_patch_paramiko.py     |  119 +++++++++++++++++++++++++++++++++++++
 x2go/session.py                   |   84 +++++++++++++++++++-------
 x2go/sshproxy.py                  |    9 ++-
 x2go/x2go_exceptions.py           |    1 +
 11 files changed, 309 insertions(+), 44 deletions(-)
 create mode 100644 x2go/monkey_patch_paramiko.py

The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index 918594b..9ea2e5a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,20 @@
+python-x2go (0.1.1.8-0-x2go1) unstable; urgency=low
+
+  [ Mike Gabriel ]
+  * New upstream version (0.1.1.8), bugfix release for 0.1.1.x series:
+    - Bugfix for: Test for existence of remote home directory on connect.
+    - Unshare local folders during session cleanup.
+    - Remove local session cache folders after sessions have terminated.
+    - Fix missing import of socket module in backends/control/_stdout.py.
+    - Catch failures on sftp_write in control session instance.
+    - Always disconnect from X2goSession instance.
+    - Use random passwords for checking SSH host keys.
+    - Fix duplication of SSH keys in known_hosts file, use hashed hostnames in
+      known_hosts file. Make sure SSH keys written to known_hosts file are 
+      available to other SSHClient instances immediately.
+
+ -- Mike Gabriel <mike.gabriel at das-netzwerkteam.de>  Wed, 12 Oct 2011 10:54:23 +0200
+
 python-x2go (0.1.1.7-0-x2go1) unstable; urgency=low
 
   [ Mike Gabriel ]
diff --git a/x2go/__init__.py b/x2go/__init__.py
index 100a162..54090c1 100644
--- a/x2go/__init__.py
+++ b/x2go/__init__.py
@@ -158,7 +158,7 @@ Contact
 """
 
 __NAME__    = 'python-x2go'
-__VERSION__ = '0.1.1.7'
+__VERSION__ = '0.1.1.8'
 
 from gevent import monkey
 monkey.patch_all()
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index e382493..35990ee 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -37,6 +37,8 @@ import binascii
 import string
 import random
 
+from gevent import socket
+
 # Python X2go modules
 import x2go.sshproxy as sshproxy
 import x2go.log as log
@@ -50,6 +52,9 @@ from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo
 from x2go.backends.info import X2goServerSessionList as _X2goServerSessionList
 from x2go.backends.proxy import X2goProxy as _X2goProxy
 
+from x2go.monkey_patch_paramiko import monkey_patch_paramiko
+monkey_patch_paramiko()
+
 def _rerewrite_blanks(cmd):
     # X2go run command replace X2GO_SPACE_CHAR string with blanks
     if cmd:
@@ -158,10 +163,13 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
     def _x2go_sftp_write(self, remote_path, content):
 
         self.logger('sFTP-write: opening remote file %s on host %s for writing' % (remote_path, self.get_transport().getpeername()), loglevel=log.loglevel_DEBUG)
-        remote_fileobj = self.sftp_client.open(remote_path, 'w')
-        self.logger('sFTP-write: writing content: %s' % content, loglevel=log.loglevel_DEBUG_SFTPXFER)
-        remote_fileobj.write(content)
-        remote_fileobj.close()
+        try:
+            remote_fileobj = self.sftp_client.open(remote_path, 'w')
+            self.logger('sFTP-write: writing content: %s' % content, loglevel=log.loglevel_DEBUG_SFTPXFER)
+            remote_fileobj.write(content)
+            remote_fileobj.close()
+        except SSHException:
+            self.logger('sFTP-write: opening remote file %s on host %s failed' % (remote_path, self.get_transport().getpeername()), loglevel=log.loglevel_WARN)
 
     def _x2go_sftp_remove(self, remote_path):
 
@@ -493,7 +501,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             self.session_died = False
 
         if not self.home_exists():
-            raise x2go_exceptions.X2goControlSessionException('remote home directory does not exist')
+            raise x2go_exceptions.X2goRemoteHomeException('remote home directory does not exist')
 
         return (self.get_transport() is not None)
 
@@ -550,7 +558,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
 
     def home_exists(self):
-        if self._x2go_exec_command('stat -tL "%s"', loglevel=log.loglevel_DEBUG):
+        (_stdin, _stdout, _stderr) = self._x2go_exec_command('stat -tL "%s"' % self._x2go_remote_home, loglevel=log.loglevel_DEBUG)
+        if _stdout.read():
             return True
         return False
 
@@ -756,7 +765,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
             return _listsessions
 
-    def clean_sessions(self):
+    def clean_sessions(self, destroy_terminals=True):
         """\
         Find X2go terminals that have previously been started by the
         connected user on the remote X2go server and terminate them.
@@ -764,7 +773,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         """
         session_list = self.list_sessions()
         for session_name in session_list.keys():
-            self.terminate(session_name=session_name)
+            self.terminate(session_name=session_name, destroy_terminals=destroy_terminals)
 
     def is_connected(self):
         """\
@@ -871,7 +880,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
         return _ret
 
-    def terminate(self, session_name):
+    def terminate(self, session_name, destroy_terminals=True):
         """\
         Terminate either this or another available X2go session on the connected
         server.
@@ -896,7 +905,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             dummy_stdout = stdout.read()
             dummy_stderr = stderr.read()
             if self.associated_terminals.has_key(session_name):
-                if self.associated_terminals[session_name] is not None:
+                if self.associated_terminals[session_name] is not None and destroy_terminals:
                     self.associated_terminals[session_name].__del__()
                 try: del self.associated_terminals[session_name]
                 except KeyError: pass
diff --git a/x2go/backends/info/_stdout.py b/x2go/backends/info/_stdout.py
index 5cae736..c03d1b3 100644
--- a/x2go/backends/info/_stdout.py
+++ b/x2go/backends/info/_stdout.py
@@ -27,6 +27,11 @@ via server-side STDOUT.
 """
 __NAME__ = 'x2goserversessioninfo-pylib'
 
+
+# modules
+import types
+
+
 class X2goServerSessionInfoSTDOUT(object):
     """\
     L{X2goServerSessionInfo} is used to store all information
@@ -37,7 +42,11 @@ class X2goServerSessionInfoSTDOUT(object):
     def __str__(self):
         return self.name
     def __repr__(self):
-        return "<%s instance: %s>" % (self.__class__, self.name)
+        result = 'X2goServerSessionInfoSTDOUT('
+        for p in dir(self):
+            if '__' in p or not p in self.__dict__ or type(p) is types.InstanceType: continue
+            result += p + '=' + str(self.__dict__[p]) +','
+        return result.strip(',') + ')'
 
     def _parse_x2golistsessions_line(self, x2go_output):
         """\
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 51bee99..e0eb3f1 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -35,6 +35,7 @@ import threading
 import signal
 import cStringIO
 import copy
+import shutil
 
 # Python X2go modules
 import x2go.rforward as rforward
@@ -325,6 +326,8 @@ class X2goTerminalSessionSTDOUT(object):
         else:
             self.session_info = info_backend()
 
+        self._cleaned_up = False
+
     def __del__(self):
         self._x2go_tidy_up()
 
@@ -363,6 +366,16 @@ class X2goTerminalSessionSTDOUT(object):
             else:
                 raise OSError, e
 
+    def _rm_session_dirtree(self):
+
+        if self.session_info.name:
+            shutil.rmtree('%s/S-%s' % (self.params.rootdir, self.session_info), ignore_errors=True)
+
+    def _rm_desktop_dirtree(self):
+
+        if self.session_info.display:
+            shutil.rmtree('%s/S-%s' % (self.params.rootdir, self.session_info.display), ignore_errors=True)
+
     def get_session_name(self):
         """\
         STILL UNDOCUMENTED
@@ -444,7 +457,7 @@ class X2goTerminalSessionSTDOUT(object):
         Initialize Paramiko/SSH reverse forwarding tunnel for X2go folder sharing.
 
         """
-        if self.control_session.is_folder_sharing_available():
+        if not self.control_session.is_folder_sharing_available():
             raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
 
         # start reverse SSH tunnel for sshfs (folder sharing, printing)
@@ -591,7 +604,7 @@ class X2goTerminalSessionSTDOUT(object):
         @rtype: bool
 
         """
-        if self.control_session.is_folder_sharing_available():
+        if not self.control_session.is_folder_sharing_available():
             raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
 
         if local_path is None:
@@ -1022,8 +1035,10 @@ class X2goTerminalSessionSTDOUT(object):
         @rtype: bool
 
         """
-        self.control_session.terminate(session_name=self.session_info.name)
+        self.control_session.terminate(session_name=self.session_info.name, destroy_terminals=False)
         self.release_proxy()
+        self.post_terminate_cleanup()
+        self.__del__()
 
         # TODO: check if session has really suspended
         _ret = True
@@ -1038,3 +1053,23 @@ class X2goTerminalSessionSTDOUT(object):
         if self.proxy is not None:
             self.proxy.__del__()
 
+    def post_terminate_cleanup(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        # this method might be called twice (directly and from update_status in the session
+        # registry instance. So we have to make sure, that this code will not fail
+        # if called twice.
+        if not self._cleaned_up and self.session_info.name:
+
+            # otherwise we wipe the session files locally
+            self.logger('cleaning up session %s after termination' % self.session_info, loglevel=log.loglevel_NOTICE)
+
+            # if we run in debug mode, we keep local session directories
+            if self.logger.get_loglevel() & log.loglevel_DEBUG != log.loglevel_DEBUG:
+
+                self._rm_session_dirtree()
+                self._rm_desktop_dirtree()
+
+            self._cleaned_up = True
diff --git a/x2go/checkhosts.py b/x2go/checkhosts.py
index d204527..1f0bea4 100644
--- a/x2go/checkhosts.py
+++ b/x2go/checkhosts.py
@@ -26,6 +26,7 @@ __NAME__ = 'x2gocheckhosts-pylib'
 # modules
 import paramiko
 import binascii
+import uuid
 
 # Python X2go modules
 import sshproxy
@@ -96,7 +97,7 @@ class X2goInteractiveAddPolicy(paramiko.MissingHostKeyPolicy):
                                                                   fingerprint_type=self.get_key_name(),
                                                                  )
             if _valid:
-                paramiko.AutoAddPolicy().missing_host_key(client, hostname, key)
+                paramiko.AutoAddPolicy().missing_host_key(client, self.hostname, key)
             else:
                 if type(self.caller) in (sshproxy.X2goSSHProxy, ):
                     raise x2go_exceptions.X2goSSHProxyHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname)
@@ -221,7 +222,7 @@ def check_ssh_host_key(x2go_sshclient_instance, hostname, port=22):
 
     host_ok = False
     try:
-        paramiko.SSHClient.connect(x2go_sshclient_instance, hostname=hostname, port=port, username='foo', password='bar')
+        paramiko.SSHClient.connect(x2go_sshclient_instance, hostname=hostname, port=port, username='foo', password="".join([random.choice(string.letters+string.digits) for x in range(1, 20)]))
     except x2go_exceptions.AuthenticationException:
         host_ok = True
         x2go_sshclient_instance.logger('SSH host key verification for host [%s]:%s succeeded. Host is already known to the client\'s Paramiko/SSH sub-system.' % (_hostname, _port), loglevel=log.loglevel_NOTICE)
diff --git a/x2go/client.py b/x2go/client.py
index 0d4061b..2af4230 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -319,6 +319,7 @@ class X2goClient(object):
                                                     refresh_interval=refresh_interval,
                                                     logger=self.logger
                                                    )
+        self.auto_update_sessionregistry = auto_update_sessionregistry
 
         if use_listsessions_cache:
             self.listsessions_cache = X2goListSessionsCache(self, logger=self.logger)
@@ -1042,10 +1043,38 @@ class X2goClient(object):
         return self.session_registry(session_uuid).check_host()
     __check_session_host = check_session_host
 
+    def session_uses_sshproxy(self, session_uuid):
+        """\
+        Check if session with unique identifier <session_uuid> is configured to use an
+        intermediate SSH proxy server.
+
+        @return: returns C{True} if the session is configured to use an SSH proxy, C{False} otherwise.
+        @rtype: C{bool}
+
+        """
+        return self.session_registry(session_uuid).uses_sshproxy()
+    __session_uses_sshproxy = session_uses_sshproxy
+
+    def session_can_sshproxy_auto_connect(self, session_uuid):
+        """\
+        Check if the SSH proxy of session with unique identifier <session_uuid> is configured adequately
+        to be able to auto-connect to the SSH proxy server (e.g. by public key authentication).
+
+        @param session_uuid: the X2go session's UUID registry hash
+        @type session_uuid: C{str}
+
+        @return: returns C{True} if the session's SSH proxy can auto-connect, C{False} otherwise, C{None}
+            if no control session has been set up yet.
+        @rtype: C{bool}
+
+        """
+        return self.session_registry(session_uuid).can_sshproxy_auto_connect()
+    __session_can_sshproxy_auto_connect = session_can_sshproxy_auto_connect
+
     def session_can_auto_connect(self, session_uuid):
         """\
         Check if session with unique identifier <session_uuid> is configured adequately
-        to be able to auto-connect to the X2go server (e.g. public key authentication).
+        to be able to auto-connect to the X2go server (e.g. by public key authentication).
 
         @param session_uuid: the X2go session's UUID registry hash
         @type session_uuid: C{str}
@@ -1102,6 +1131,7 @@ class X2goClient(object):
             self.session_registry.register_available_server_sessions(profile_name=self.get_session_profile_name(session_uuid),
                                                                      newly_connected=True,
                                                                     )
+        return _success
     __connect_session = connect_session
 
     def disconnect_session(self, session_uuid):
@@ -2009,8 +2039,9 @@ class X2goClient(object):
         @type session_uuid: C{str}
 
         """
+        _destroy_terminals = not ( self.auto_update_sessionregistry == True)
         session = self.session_registry(session_uuid)
-        session.clean_sessions()
+        session.clean_sessions(destroy_terminals=_destroy_terminals)
     __clean_sessions = clean_sessions
 
     def list_sessions(self, session_uuid=None, 
diff --git a/x2go/monkey_patch_paramiko.py b/x2go/monkey_patch_paramiko.py
new file mode 100644
index 0000000..c9a460a
--- /dev/null
+++ b/x2go/monkey_patch_paramiko.py
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2010-2011 by Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
+#
+# Python X2go is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Python X2go is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+"""\
+Monkey Patch for Python Paramiko
+
+"""
+
+import paramiko
+
+def _SSHClient_save_host_keys(self, filename):
+    """\
+    FIXME!!! --- this method should become part of Paramiko
+
+    This method has been taken from SSHClient class in Paramiko and
+    has been improved and adapted to latest SSH implementations.
+
+    Save the host keys back to a file.
+    Only the host keys loaded with
+    L{load_host_keys} (plus any added directly) will be saved -- not any
+    host keys loaded with L{load_system_host_keys}.
+
+    @param filename: the filename to save to
+    @type filename: str
+
+    @raise IOError: if the file could not be written 
+
+    """
+    # update local host keys from file (in case other SSH clients
+    # have written to the known_hosts file meanwhile.
+    if self.known_hosts is not None:
+        self.load_host_keys(self.known_hosts)
+
+    f = open(filename, 'w')
+    #f.write('# SSH host keys collected by paramiko\n')
+    _host_keys = self.get_host_keys()
+    for hostname, keys in _host_keys.iteritems():
+
+        for keytype, key in keys.iteritems():
+            f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))
+
+    f.close()
+
+
+def _HostKeys_load(self, filename):
+    """\
+    Read a file of known SSH host keys, in the format used by openssh.
+    This type of file unfortunately doesn't exist on Windows, but on
+    posix, it will usually be stored in
+    C{os.path.expanduser("~/.ssh/known_hosts")}.
+
+    If this method is called multiple times, the host keys are merged,
+    not cleared. So multiple calls to C{load} will just call L{add},
+    replacing any existing entries and adding new ones.
+
+    @param filename: name of the file to read host keys from
+    @type filename: str
+
+    @raise IOError: if there was an error reading the file
+
+    """
+    f = open(filename, 'r')
+    for line in f:
+        line = line.strip()
+        if (len(line) == 0) or (line[0] == '#'):
+            continue
+        e = paramiko.hostkeys.HostKeyEntry.from_line(line)
+        if e is not None:
+            _hostnames = e.hostnames
+            for h in _hostnames:
+                if self.check(h, e.key):
+                    e.hostnames.remove(h)
+            if len(e.hostnames):
+                self._entries.append(e)
+    f.close() 
+
+
+def _HostKeys_add(self, hostname, keytype, key, hash_hostname=True):
+    """\
+    Add a host key entry to the table. Any existing entry for a
+    C{(hostname, keytype)} pair will be replaced.
+
+    @param hostname: the hostname (or IP) to add
+    @type hostname: str
+    @param keytype: key type (C{"ssh-rsa"} or C{"ssh-dss"})
+    @type keytype: str
+    @param key: the key to add
+    @type key: L{PKey}
+
+    """
+    for e in self._entries:
+        if (hostname in e.hostnames) and (e.key.get_name() == keytype):
+            e.key = key
+            return
+    if not hostname.startswith('|1|') and hash_hostname:
+        hostname = self.hash_host(hostname)
+    self._entries.append(paramiko.hostkeys.HostKeyEntry([hostname], key))
+
+
+def monkey_patch_paramiko():
+    paramiko.SSHClient.save_host_keys = _SSHClient_save_host_keys
+    paramiko.hostkeys.HostKeys.load = _HostKeys_load
+    paramiko.hostkeys.HostKeys.add = _HostKeys_add
diff --git a/x2go/session.py b/x2go/session.py
index ed1e8b5..88d2a73 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -681,6 +681,37 @@ class X2goSession(object):
         return _valid or self.HOOK_check_host_dialog(host=_host, port=_port, fingerprint=_fingerprint, fingerprint_type=_fingerprint_type)
     __check_host = check_host
 
+    def uses_sshproxy(self):
+        """\
+        Check if a session is configured to use an intermediate SSH proxy server.
+
+        @return: returns C{True} if the session is configured to use an SSH proxy, C{False} otherwise.
+        @rtype: C{bool}
+
+        """
+        return self.use_sshproxy
+
+    def can_sshproxy_auto_connect(self):
+        """\
+        Check if a session's SSH proxy (if used) is configured adequately to be able to auto-connect
+        to the SSH proxy server (e.g. by public key authentication).
+
+        @return: returns C{True} if the session's SSH proxy can auto-connect, C{False} otherwise, C{None}
+            if no SSH proxy is used for this session, C{None} is returned.
+        @rtype: C{bool}
+
+        """
+        if self.use_sshproxy:
+            if self.sshproxy_params.has_key('sshproxy_key_filename') and self.sshproxy_params['sshproxy_key_filename'] and os.path.exists(os.path.normpath(self.sshproxy_params['sshproxy_key_filename'])):
+                return True
+            elif self.sshproxy_params.has_key('sshproxy_pkey') and self.sshproxy_params['sshproxy_pkey']:
+                return True
+            else:
+                return False
+        else:
+            return None
+    __can_sshproxy_auto_connect = can_sshproxy_auto_connect
+
     def can_auto_connect(self):
         """\
         Check if a session is configured adequately to be able to auto-connect to the X2go
@@ -691,26 +722,24 @@ class X2goSession(object):
         @rtype: C{bool}
 
         """
-
-        def _can_sshproxy_autoconnect():
-
-            if self.use_sshproxy:
-                if self.sshproxy_params.has_key('sshproxy_key_filename') and self.sshproxy_params['sshproxy_key_filename'] and os.path.exists(os.path.normpath(self.sshproxy_params['sshproxy_key_filename'])):
-                    return True
-                elif self.sshproxy_params.has_key('sshproxy_pkey') and self.sshproxy_params['sshproxy_pkey']:
-                    return True
-                else:
-                    return False
-            else:
-                return True
+        if self.control_session is None:
+            return None
 
         # do we have a key file passed as control parameter?
         if self.control_params.has_key('key_filename') and self.control_params['key_filename'] and os.path.exists(os.path.normpath(self.control_params['key_filename'])):
-            return _can_sshproxy_autoconnect()
+            _can_sshproxy_auto_connect = self.can_sshproxy_auto_connect()
+            if _can_sshproxy_auto_connect is not None:
+                return _can_sshproxy_auto_connect
+            else:
+                return True
 
         # or a private key?
         elif self.control_params.has_key('pkey') and self.control_params['pkey']:
-            return _can_sshproxy_autoconnect()
+            _can_sshproxy_auto_connect = self.can_sshproxy_auto_connect()
+            if _can_sshproxy_auto_connect is not None:
+                return _can_sshproxy_auto_connect
+            else:
+                return True
 
         else:
             return False
@@ -773,6 +802,9 @@ class X2goSession(object):
                                                               **_params)
             except X2goControlSessionException, e:
                 raise X2goSessionException(str(e))
+            except X2goRemoteHomeException, e:
+                self.disconnect()
+                raise e
             except:
                 # remove credentials immediately
                 self.control_params['password'] = ''
@@ -853,13 +885,13 @@ class X2goSession(object):
         return self.connected
     __is_alive = is_alive
 
-    def clean_sessions(self):
+    def clean_sessions(self, destroy_terminals=True):
         """\
         Clean all running sessions for the authenticated user on the remote X2go server.
 
         """
         if self.is_alive():
-            self.control_session.clean_sessions()
+            self.control_session.clean_sessions(destroy_terminals=destroy_terminals)
         else:
             self._X2goSession__disconnect()
     __clean_sessions = clean_sessions
@@ -1180,9 +1212,6 @@ class X2goSession(object):
         if self.is_alive():
             if self.has_terminal_session():
 
-                # unshare mounted folders
-                self.unshare_all_local_folders()
-
                 if self.terminal_session.suspend():
 
                     self.running = False
@@ -1222,9 +1251,6 @@ class X2goSession(object):
         if self.is_alive():
             if self.has_terminal_session():
 
-                # unmount shared folders
-                self.unshare_all_local_folders()
-
                 if self.terminal_session.terminate():
                     self.running = False
                     self.suspended = False
@@ -1515,8 +1541,22 @@ class X2goSession(object):
         Clean up X2go session.
 
         """
+        # release terminal session's proxy
         if self.has_terminal_session():
             self.terminal_session.release_proxy()
+
+        # unmount shared folders
+        try:
+            self.unshare_all_local_folders()
+        except X2goSessionException:
+            pass
+
+        # remove client-side session cache
+        if self.terminated and self.has_terminal_session():
+            self.terminal_session.post_terminate_cleanup()
+
+        # destroy terminal session
         if self.has_terminal_session():
             self.terminal_session.__del__()
+
         self.terminal_session = None
diff --git a/x2go/sshproxy.py b/x2go/sshproxy.py
index cd51afe..b61f9cf 100644
--- a/x2go/sshproxy.py
+++ b/x2go/sshproxy.py
@@ -45,6 +45,8 @@ from x2go.defaults import CURRENT_LOCAL_USER as _CURRENT_LOCAL_USER
 from x2go.defaults import LOCAL_HOME as _LOCAL_HOME
 from x2go.defaults import X2GO_SSH_ROOTDIR as _X2GO_SSH_ROOTDIR
 
+from monkey_patch_paramiko import monkey_patch_paramiko
+monkey_patch_paramiko()
 
 class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
     """\
@@ -173,9 +175,10 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
         self.ssh_rootdir = ssh_rootdir
         paramiko.SSHClient.__init__(self)
 
-        if known_hosts:
-            utils.touch_file(known_hosts)
-            self.load_host_keys(known_hosts)
+        self.known_hosts = known_hosts
+        if self.known_hosts:
+            utils.touch_file(self.known_hosts)
+            self.load_host_keys(self.known_hosts)
 
         if not add_to_known_hosts and session_instance:
             self.set_missing_host_key_policy(checkhosts.X2goInteractiveAddPolicy(caller=self, session_instance=session_instance))
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index c068b6c..d3a2eeb 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -45,6 +45,7 @@ class X2goClientPrintingException(_X2goException): pass
 class X2goClientSettingsException(_X2goException): pass
 class X2goSessionException(_X2goException): pass
 class X2goControlSessionException(_X2goException): pass
+class X2goRemoteHomeException(_X2goException): pass
 class X2goHostKeyException(_X2goException): pass
 class X2goSSHProxyHostKeyException(_X2goException): pass
 class X2goTerminalSessionException(_X2goException): pass


hooks/post-receive
-- 
python-x2go.git (Python X2go Client API)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2go Client API).




More information about the x2go-commits mailing list