diff options
-rw-r--r-- | src/leap/baseapp/dialogs.py | 11 | ||||
-rw-r--r-- | src/leap/baseapp/mainwindow.py | 14 | ||||
-rw-r--r-- | src/leap/eip/conductor.py | 21 | ||||
-rw-r--r-- | src/leap/eip/config.py | 56 | ||||
-rw-r--r-- | src/leap/util/fileutil.py | 24 |
5 files changed, 119 insertions, 7 deletions
diff --git a/src/leap/baseapp/dialogs.py b/src/leap/baseapp/dialogs.py index d4e51a39..4b1b5b62 100644 --- a/src/leap/baseapp/dialogs.py +++ b/src/leap/baseapp/dialogs.py @@ -20,3 +20,14 @@ class ErrorDialog(QDialog): self.warningLabel.setText("Save Again") else: self.warningLabel.setText("Continue") + + def criticalMessage(self, msg, label): + msgBox = QMessageBox(QMessageBox.Critical, + "QMessageBox.critical()", msg, + QMessageBox.NoButton, self) + msgBox.addButton("&Ok", QMessageBox.AcceptRole) + msgBox.addButton("&Cancel", QMessageBox.RejectRole) + if msgBox.exec_() == QMessageBox.AcceptRole: + self.warningLabel.setText("Save Again") + else: + self.warningLabel.setText("Continue") diff --git a/src/leap/baseapp/mainwindow.py b/src/leap/baseapp/mainwindow.py index d5251a5c..cbdd2d07 100644 --- a/src/leap/baseapp/mainwindow.py +++ b/src/leap/baseapp/mainwindow.py @@ -12,7 +12,12 @@ from PyQt4.QtGui import (QMainWindow, QWidget, QVBoxLayout, QMessageBox, from PyQt4.QtCore import (pyqtSlot, pyqtSignal, QTimer) from leap.baseapp.dialogs import ErrorDialog -from leap.eip.conductor import EIPConductor, EIPNoCommandError +from leap.eip.conductor import (EIPConductor, + EIPNoCommandError) + +from leap.eip.config import (EIPInitBadKeyFilePermError) +# from leap.eip import exceptions as eip_exceptions + from leap.gui import mainwindow_rc @@ -68,14 +73,17 @@ class LeapWindow(QMainWindow): # we pass a tuple of signals that will be # triggered when status changes. # - self.conductor = EIPConductor( watcher_cb=self.newLogLine.emit, config_file=config_file, status_signals=(self.statusChange.emit, ), debug=self.debugmode) - #print('debugmode:%s' % self.debugmode) + if self.conductor.bad_keyfile_perms is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'The vpn keys file has bad permissions', + 'error') if self.conductor.missing_auth_agent is True: dialog = ErrorDialog() diff --git a/src/leap/eip/conductor.py b/src/leap/eip/conductor.py index 243f1fde..3f40f068 100644 --- a/src/leap/eip/conductor.py +++ b/src/leap/eip/conductor.py @@ -5,15 +5,16 @@ from __future__ import (division, unicode_literals, print_function) #import threading from functools import partial import logging -import os from leap.util.coroutines import spawn_and_watch_process - +# XXX import eip.config as eipconfig from leap.eip.config import (get_config, build_ovpn_command, check_or_create_default_vpnconf, + check_vpn_keys, EIPNoPkexecAvailable, - EIPNoPolkitAuthAgentAvailable) + EIPNoPolkitAuthAgentAvailable, + EIPInitBadKeyFilePermError) from leap.eip.vpnwatcher import EIPConnectionStatus, status_watcher from leap.eip.vpnmanager import OpenVPNManager, ConnectionRefusedError @@ -21,6 +22,7 @@ logger = logging.getLogger(name=__name__) # TODO Move exceptions to their own module +# eip.exceptions class EIPNoCommandError(Exception): pass @@ -98,11 +100,14 @@ to be triggered for each one of them. self.missing_pkexec = False self.missing_auth_agent = False + self.bad_keyfile_perms = False + self.command = None self.args = None self.autostart = True self._get_or_create_config() + self._check_vpn_keys() def _set_autostart(self): config = self.config @@ -170,6 +175,16 @@ to be triggered for each one of them. self._set_ovpn_command() self._check_ovpn_config() + def _check_vpn_keys(self): + """ + checks for correct permissions on vpn keys + """ + try: + check_vpn_keys(self.config) + except EIPInitBadKeyFilePermError: + logger.error('error while checking vpn keys') + self.bad_keyfile_perms = True + def _launch_openvpn(self): """ invocation of openvpn binaries in a subprocess. diff --git a/src/leap/eip/config.py b/src/leap/eip/config.py index 9af6f57a..91c3953b 100644 --- a/src/leap/eip/config.py +++ b/src/leap/eip/config.py @@ -4,13 +4,17 @@ import logging import os import platform -from leap.util.fileutil import which, mkdir_p +from leap.util.fileutil import (which, mkdir_p, + check_and_fix_urw_only) from leap.baseapp.permcheck import (is_pkexec_in_system, is_auth_agent_running) logger = logging.getLogger(name=__name__) logger.setLevel('DEBUG') +# XXX move exceptions to +# from leap.eip import exceptions as eip_exceptions + class EIPNoPkexecAvailable(Exception): pass @@ -20,6 +24,14 @@ class EIPNoPolkitAuthAgentAvailable(Exception): pass +class EIPInitNoKeyFileError(Exception): + pass + + +class EIPInitBadKeyFilePermError(Exception): + pass + + OPENVPN_CONFIG_TEMPLATE = """#Autogenerated by eip-client wizard remote {VPN_REMOTE_HOST} {VPN_REMOTE_PORT} @@ -345,3 +357,45 @@ def get_config(config_file=None): config.readfp(config_file) return config + + +def check_vpn_keys(config): + """ + performs an existance and permission check + over the openvpn keys file. + Currently we're expecting a single file + per provider, containing the CA cert, + the provider key, and our client certificate + """ + + keyopt = ('provider', 'keyfile') + + # XXX at some point, + # should separate between CA, provider cert + # and our certificate. + # make changes in the default provider template + # accordingly. + + # get vpn keys + if config.has_option(*keyopt): + keyfile = config.get(*keyopt) + else: + keyfile = get_config_file( + 'openvpn.keys', + folder=get_default_provider_path()) + logger.debug('keyfile = %s', keyfile) + + # if no keys, raise error. + # should be catched by the ui and signal user. + + if not os.path.isfile(keyfile): + logger.error('key file %s not found. aborting.', + keyfile) + raise EIPInitNoKeyFileError + + # check proper permission on keys + # bad perms? try to fix them + try: + check_and_fix_urw_only(keyfile) + except OSError: + raise EIPInitBadKeyFilePermError diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py index bb2c243b..cc3bf34b 100644 --- a/src/leap/util/fileutil.py +++ b/src/leap/util/fileutil.py @@ -1,10 +1,14 @@ import errno from itertools import chain +import logging import os import platform import stat +logger = logging.getLogger() + + def is_user_executable(fpath): st = os.stat(fpath) return bool(st.st_mode & stat.S_IXUSR) @@ -85,3 +89,23 @@ def mkdir_p(path): pass else: raise + + +def check_and_fix_urw_only(_file): + """ + test for 600 mode and try + to set it if anything different found + """ + mode = os.stat(_file).st_mode + if mode != int('600', 8): + try: + logger.warning( + 'bad permission on %s ' + 'attempting to set 600', + _file) + os.chmod(_file, stat.S_IRUSR | stat.S_IWUSR) + except OSError: + logger.error( + 'error while trying to chmod 600 %s', + _file) + raise |