summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/services
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2014-09-26 10:15:06 -0300
committerTomás Touceda <chiiph@leap.se>2014-09-26 10:15:06 -0300
commit6f7177f3ca359f8c3e74d094b0dcd0f9239fb069 (patch)
treef04b0eb5c4665a129c5c49719b2da65d325b111f /src/leap/bitmask/services
parente8c028f3eb6cd0681f039c456dc1ac45c98d598f (diff)
parent0db3d5a4aecc0a3c271b92c6187922c50d46df0a (diff)
Merge branch 'release-0.7.0'0.7.0rc20.7.0rc1
Diffstat (limited to 'src/leap/bitmask/services')
-rw-r--r--src/leap/bitmask/services/eip/conductor.py6
-rw-r--r--src/leap/bitmask/services/eip/eipconfig.py43
-rw-r--r--src/leap/bitmask/services/eip/linuxvpnlauncher.py99
-rw-r--r--src/leap/bitmask/services/eip/vpnprocess.py20
-rw-r--r--src/leap/bitmask/services/mail/conductor.py19
-rw-r--r--src/leap/bitmask/services/mail/emailfirewall.py115
-rw-r--r--src/leap/bitmask/services/mail/smtpbootstrapper.py2
7 files changed, 180 insertions, 124 deletions
diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py
index 0ee56628..01dd7449 100644
--- a/src/leap/bitmask/services/eip/conductor.py
+++ b/src/leap/bitmask/services/eip/conductor.py
@@ -124,6 +124,12 @@ class EIPConductor(object):
"""
self._backend.tear_fw_down()
+ def terminate(self):
+ """
+ Turn off VPN
+ """
+ self.qtsigs.do_disconnect_signal.emit()
+
@QtCore.Slot()
def _start_eip(self):
"""
diff --git a/src/leap/bitmask/services/eip/eipconfig.py b/src/leap/bitmask/services/eip/eipconfig.py
index 37c0c8ae..5b51d12e 100644
--- a/src/leap/bitmask/services/eip/eipconfig.py
+++ b/src/leap/bitmask/services/eip/eipconfig.py
@@ -113,39 +113,38 @@ class VPNGatewaySelector(object):
"""
Return the existing gateways, sorted by timezone proximity.
- :rtype: list of tuples (location, ip)
- (str, IPv4Address or IPv6Address object)
+ :rtype: list of tuples (label, ip, country_code)
+ (str, IPv4Address or IPv6Address object, str)
"""
gateways_timezones = []
locations = self._eipconfig.get_locations()
gateways = self._eipconfig.get_gateways()
for idx, gateway in enumerate(gateways):
- gateway_location = gateway.get('location')
- gateway_distance = 99 # if hasn't location -> should go last
-
- if gateway_location is not None:
- timezone = locations[gateway['location']]['timezone']
- gateway_name = locations[gateway['location']].get('name', None)
- if gateway_name is not None:
- gateway_location = gateway_name
-
- gw_offset = int(timezone)
- if gw_offset in self.equivalent_timezones:
- gw_offset = self.equivalent_timezones[gw_offset]
-
- gateway_distance = self._get_timezone_distance(gw_offset)
+ distance = 99 # if hasn't location -> should go last
+ location = locations.get(gateway.get('location'))
+ label = gateway.get('location', 'Unknown')
+ country = 'XX'
+ if location is not None:
+ country = location.get('country_code', 'XX')
+ label = location.get('name', label)
+ timezone = location.get('timezone')
+ if timezone is not None:
+ offset = int(timezone)
+ if offset in self.equivalent_timezones:
+ offset = self.equivalent_timezones[offset]
+ distance = self._get_timezone_distance(offset)
ip = self._eipconfig.get_gateway_ip(idx)
- gateways_timezones.append((ip, gateway_distance, gateway_location))
+ gateways_timezones.append((ip, distance, label, country))
gateways_timezones = sorted(gateways_timezones, key=lambda gw: gw[1])
- gateways = []
- for ip, distance, location in gateways_timezones:
- gateways.append((location, ip))
+ result = []
+ for ip, distance, label, country in gateways_timezones:
+ result.append((label, ip, country))
- return gateways
+ return result
def get_gateways(self):
"""
@@ -153,7 +152,7 @@ class VPNGatewaySelector(object):
:rtype: list of IPv4Address or IPv6Address object.
"""
- gateways = [ip for location, ip in self.get_gateways_list()][:4]
+ gateways = [gateway[1] for gateway in self.get_gateways_list()][:4]
return gateways
def get_gateways_country_code(self):
diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py
index b6e47f25..a3ab408b 100644
--- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py
+++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py
@@ -20,17 +20,15 @@ Linux VPN launcher implementation.
import commands
import logging
import os
-import subprocess
import sys
-import time
from leap.bitmask.config import flags
from leap.bitmask.util.privilege_policies import LinuxPolicyChecker
-from leap.common.files import which
+from leap.bitmask.util.privilege_policies import NoPolkitAuthAgentAvailable
+from leap.bitmask.util.privilege_policies import NoPkexecAvailable
from leap.bitmask.services.eip.vpnlauncher import VPNLauncher
from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException
from leap.bitmask.util import get_path_prefix, force_eval
-from leap.common.check import leap_assert
from leap.bitmask.util import first
logger = logging.getLogger(__name__)
@@ -46,66 +44,11 @@ class EIPNoPkexecAvailable(VPNLauncherException):
pass
-def _is_pkexec_in_system():
- """
- Checks the existence of the pkexec binary in system.
- """
- pkexec_path = which('pkexec')
- if len(pkexec_path) == 0:
- return False
- return True
-
-
-def _is_auth_agent_running():
- """
- Checks if a polkit daemon is running.
-
- :return: True if it's running, False if it's not.
- :rtype: boolean
- """
- # Note that gnome-shell does not uses a separate process for the
- # polkit-agent, it uses a polkit-agent within its own process so we can't
- # ps-grep a polkit process, we can ps-grep gnome-shell itself.
-
- # the [x] thing is to avoid grep match itself
- polkit_options = [
- 'ps aux | grep "polkit-[g]nome-authentication-agent-1"',
- 'ps aux | grep "polkit-[k]de-authentication-agent-1"',
- 'ps aux | grep "polkit-[m]ate-authentication-agent-1"',
- 'ps aux | grep "[l]xpolkit"',
- 'ps aux | grep "[g]nome-shell"',
- 'ps aux | grep "[f]ingerprint-polkit-agent"',
- ]
- is_running = [commands.getoutput(cmd) for cmd in polkit_options]
-
- return any(is_running)
-
-
-def _try_to_launch_agent():
- """
- Tries to launch a polkit daemon.
- """
- env = None
- if flags.STANDALONE:
- env = {"PYTHONPATH": os.path.abspath('../../../../lib/')}
- try:
- # We need to quote the command because subprocess call
- # will do "sh -c 'foo'", so if we do not quoute it we'll end
- # up with a invocation to the python interpreter. And that
- # is bad.
- logger.debug("Trying to launch polkit agent")
- subprocess.call(["python -m leap.bitmask.util.polkit_agent"],
- shell=True, env=env)
- except Exception as exc:
- logger.exception(exc)
-
-
SYSTEM_CONFIG = "/etc/leap"
leapfile = lambda f: "%s/%s" % (SYSTEM_CONFIG, f)
class LinuxVPNLauncher(VPNLauncher):
- PKEXEC_BIN = 'pkexec'
# The following classes depend on force_eval to be called against
# the classes, to get the evaluation of the standalone flag on runtine.
@@ -130,36 +73,6 @@ class LinuxVPNLauncher(VPNLauncher):
OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH)
@classmethod
- def maybe_pkexec(kls):
- """
- Checks whether pkexec is available in the system, and
- returns the path if found.
-
- Might raise:
- EIPNoPkexecAvailable,
- EIPNoPolkitAuthAgentAvailable.
-
- :returns: a list of the paths where pkexec is to be found
- :rtype: list
- """
- if _is_pkexec_in_system():
- if not _is_auth_agent_running():
- _try_to_launch_agent()
- time.sleep(2)
- if _is_auth_agent_running():
- pkexec_possibilities = which(kls.PKEXEC_BIN)
- leap_assert(len(pkexec_possibilities) > 0,
- "We couldn't find pkexec")
- return pkexec_possibilities
- else:
- logger.warning("No polkit auth agent found. pkexec " +
- "will use its own auth agent.")
- raise EIPNoPolkitAuthAgentAvailable()
- else:
- logger.warning("System has no pkexec")
- raise EIPNoPkexecAvailable()
-
- @classmethod
def get_vpn_command(kls, eipconfig, providerconfig, socket_host,
socket_port="unix", openvpn_verb=1):
"""
@@ -194,7 +107,13 @@ class LinuxVPNLauncher(VPNLauncher):
command.insert(1, "openvpn")
command.insert(2, "start")
- pkexec = kls.maybe_pkexec()
+ policyChecker = LinuxPolicyChecker()
+ try:
+ pkexec = policyChecker.maybe_pkexec()
+ except NoPolkitAuthAgentAvailable:
+ raise EIPNoPolkitAuthAgentAvailable()
+ except NoPkexecAvailable:
+ raise EIPNoPkexecAvailable()
if pkexec:
command.insert(0, first(pkexec))
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index c7159a93..8dc6021f 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -50,8 +50,7 @@ from leap.common.check import leap_assert, leap_assert_type
logger = logging.getLogger(__name__)
vpnlog = logging.getLogger('leap.openvpn')
-from twisted.internet import protocol
-from twisted.internet import defer
+from twisted.internet import defer, protocol, reactor
from twisted.internet import error as internet_error
from twisted.internet.task import LoopingCall
@@ -157,10 +156,8 @@ class VPN(object):
of a QObject containing the QSignals that we will pass along
to the VPNManager.
"""
- from twisted.internet import reactor
self._vpnproc = None
self._pollers = []
- self._reactor = reactor
self._signaler = kwargs['signaler']
self._openvpn_verb = flags.OPENVPN_VERBOSITY
@@ -217,14 +214,15 @@ class VPN(object):
# and abstract us away from anything else.
try:
cmd = vpnproc.getCommand()
- except Exception:
- logger.error("Error while getting vpn command...")
+ except Exception as e:
+ logger.error("Error while getting vpn command... {0!r}".format(e))
raise
+
env = os.environ
for key, val in vpnproc.vpn_env.items():
env[key] = val
- self._reactor.spawnProcess(vpnproc, cmd[0], cmd, env)
+ reactor.spawnProcess(vpnproc, cmd[0], cmd, env)
self._vpnproc = vpnproc
# add pollers for status and state
@@ -300,7 +298,6 @@ class VPN(object):
:param tries: counter of tries, used in recursion
:type tries: int
"""
- from twisted.internet import reactor
while tries < self.TERMINATE_MAXTRIES:
if self._vpnproc.transport.pid is None:
logger.debug("Process has been happily terminated.")
@@ -351,7 +348,6 @@ class VPN(object):
:param restart: whether this stop is part of a hard restart.
:type restart: bool
"""
- from twisted.internet import reactor
self._stop_pollers()
# First we try to be polite and send a SIGTERM...
@@ -375,6 +371,8 @@ class VPN(object):
logger.debug("Firewall down")
else:
logger.warning("Could not tear firewall down")
+ else:
+ logger.debug("VPN is not running.")
def _start_pollers(self):
"""
@@ -424,8 +422,6 @@ class VPNManager(object):
backend
:type signaler: backend.Signaler
"""
- from twisted.internet import reactor
- self._reactor = reactor
self._tn = None
self._signaler = signaler
self._aborted = False
@@ -602,7 +598,7 @@ class VPNManager(object):
logger.debug('trying to connect to management')
if not self.aborted and not self.is_connected():
self.connect_to_management(self._socket_host, self._socket_port)
- self._reactor.callLater(
+ reactor.callLater(
self.CONNECTION_RETRY_TIME,
self.try_to_connect_to_management, retry + 1)
diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py
index 5e85368f..416aff34 100644
--- a/src/leap/bitmask/services/mail/conductor.py
+++ b/src/leap/bitmask/services/mail/conductor.py
@@ -22,6 +22,7 @@ import logging
from leap.bitmask.config import flags
from leap.bitmask.gui import statemachines
from leap.bitmask.services.mail import connection as mail_connection
+from leap.bitmask.services.mail.emailfirewall import get_email_firewall
from leap.common.events import events_pb2 as leap_events
from leap.common.events import register as leap_register
@@ -211,6 +212,11 @@ class MailConductor(IMAPControl, SMTPControl):
self._mail_connection = mail_connection.MailConnection()
self._userid = None
+ try:
+ self._firewall = get_email_firewall()
+ except NotImplementedError:
+ self._firewall = None
+ logger.info("Email firewall is not implemented in this platform")
@property
def userid(self):
@@ -247,12 +253,25 @@ class MailConductor(IMAPControl, SMTPControl):
self._smtp_machine = smtp
self._smtp_machine.start()
+ def start_mail_service(self, download_if_needed=False, offline=False):
+ """
+ Start the IMAP and SMTP servcies.
+ """
+ if self._firewall is not None:
+ self._firewall.start()
+ if not offline:
+ logger.debug("not starting smtp in offline mode")
+ self.start_smtp_service(download_if_needed=download_if_needed)
+ self.start_imap_service()
+
def stop_mail_services(self):
"""
Stop the IMAP and SMTP services.
"""
self.stop_imap_service()
self.stop_smtp_service()
+ if self._firewall is not None:
+ self._firewall.stop()
def connect_mail_signals(self, widget):
"""
diff --git a/src/leap/bitmask/services/mail/emailfirewall.py b/src/leap/bitmask/services/mail/emailfirewall.py
new file mode 100644
index 00000000..2cd2ec31
--- /dev/null
+++ b/src/leap/bitmask/services/mail/emailfirewall.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+# emailfirewall.py
+# Copyright (C) 2014 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+Email firewall implementation.
+"""
+
+import os
+import subprocess
+
+from abc import ABCMeta, abstractmethod
+
+from leap.bitmask.config import flags
+from leap.bitmask.platform_init import IS_LINUX
+from leap.bitmask.util import first, force_eval
+from leap.bitmask.util.privilege_policies import LinuxPolicyChecker
+from leap.common.check import leap_assert
+
+
+def get_email_firewall():
+ """
+ Return the email firewall handler for the current platform.
+ """
+ if not (IS_LINUX):
+ error_msg = "Email firewall not implemented for this platform."
+ raise NotImplementedError(error_msg)
+
+ firewall = None
+ if IS_LINUX:
+ firewall = LinuxEmailFirewall
+
+ leap_assert(firewall is not None)
+
+ return firewall()
+
+
+class EmailFirewall(object):
+ """
+ Abstract email firwall class
+ """
+ __metaclass__ = ABCMeta
+
+ @abstractmethod
+ def start(self):
+ """
+ Start email firewall
+ """
+ return False
+
+ @abstractmethod
+ def stop(self):
+ """
+ Stop email firewall
+ """
+ return False
+
+
+class EmailFirewallException(Exception):
+ pass
+
+
+class LinuxEmailFirewall(EmailFirewall):
+
+ class BITMASK_ROOT(object):
+ def __call__(self):
+ return ("/usr/local/sbin/bitmask-root" if flags.STANDALONE else
+ "/usr/sbin/bitmask-root")
+
+ def start(self):
+ uid = str(os.getuid())
+ return True if self._run(["start", uid]) is 0 else False
+
+ def stop(self):
+ return True if self._run(["stop"]) is 0 else False
+
+ def _run(self, cmd):
+ """
+ Run an email firewall command with bitmask-root
+
+ Might raise:
+ NoPkexecAvailable,
+ NoPolkitAuthAgentAvailable,
+
+ :param cmd: command to send to bitmask-root fw-email
+ :type cmd: [str]
+ :returns: exit code of bitmask-root
+ :rtype: int
+ """
+ command = []
+
+ policyChecker = LinuxPolicyChecker()
+ pkexec = policyChecker.maybe_pkexec()
+ if pkexec:
+ command.append(first(pkexec))
+
+ command.append(force_eval(self.BITMASK_ROOT))
+ command.append("fw-email")
+ command += cmd
+
+ # XXX: will be nice to use twisted ProcessProtocol instead of
+ # subprocess to avoid blocking until it finish
+ return subprocess.call(command)
diff --git a/src/leap/bitmask/services/mail/smtpbootstrapper.py b/src/leap/bitmask/services/mail/smtpbootstrapper.py
index 3ef755e8..9dd61488 100644
--- a/src/leap/bitmask/services/mail/smtpbootstrapper.py
+++ b/src/leap/bitmask/services/mail/smtpbootstrapper.py
@@ -173,3 +173,5 @@ class SMTPBootstrapper(AbstractBootstrapper):
logger.debug('Stopping SMTP service.')
self._smtp_port.stopListening()
self._smtp_service.doStop()
+ else:
+ logger.debug('SMTP service not running.')