diff options
| -rw-r--r-- | changes/feature-install-local-path | 1 | ||||
| -rw-r--r-- | pkg/linux/polkit/se.leap.bitmask.bundle.policy | 23 | ||||
| -rw-r--r-- | src/leap/bitmask/backend.py | 4 | ||||
| -rw-r--r-- | src/leap/bitmask/platform_init/initializers.py | 18 | ||||
| -rw-r--r-- | src/leap/bitmask/services/eip/linuxvpnlauncher.py | 74 | ||||
| -rw-r--r-- | src/leap/bitmask/services/eip/vpnlauncher.py | 13 | ||||
| -rw-r--r-- | src/leap/bitmask/services/eip/vpnprocess.py | 8 | ||||
| -rw-r--r-- | src/leap/bitmask/util/__init__.py | 19 | ||||
| -rw-r--r-- | src/leap/bitmask/util/privilege_policies.py | 10 | 
9 files changed, 119 insertions, 51 deletions
| diff --git a/changes/feature-install-local-path b/changes/feature-install-local-path new file mode 100644 index 00000000..17e1d2d7 --- /dev/null +++ b/changes/feature-install-local-path @@ -0,0 +1 @@ +- Install helpers to /usr/local for bundle. Closes: #5741 diff --git a/pkg/linux/polkit/se.leap.bitmask.bundle.policy b/pkg/linux/polkit/se.leap.bitmask.bundle.policy new file mode 100644 index 00000000..58fcaaa8 --- /dev/null +++ b/pkg/linux/polkit/se.leap.bitmask.bundle.policy @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE policyconfig PUBLIC + "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" + "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd"> +<policyconfig> + +  <vendor>LEAP Project</vendor> +  <vendor_url>http://leap.se/</vendor_url> + +  <action id="se.leap.bitmask.bundle.policy"> +    <description>Runs bitmask helper to launch firewall and openvpn (bundle version)</description> +    <description xml:lang="es">Ejecuta el asistente de bitmask para lanzar el firewall y openvpn (version bundle)</description> +    <message>Bitmask needs that you authenticate to start</message> +    <message xml:lang="es">Bitmask necesita autorizacion para comenzar</message> +    <icon_name>package-x-generic</icon_name>  +    <defaults> +      <allow_any>yes</allow_any> +      <allow_inactive>yes</allow_inactive> +      <allow_active>yes</allow_active> +    </defaults> +    <annotate key="org.freedesktop.policykit.exec.path">/usr/local/sbin/bitmask-root</annotate> +  </action> +</policyconfig> diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 7ebe7f97..f7200dd7 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -54,6 +54,7 @@ from leap.bitmask.services.mail.smtpconfig import SMTPConfig  from leap.bitmask.services.soledad.soledadbootstrapper import \      SoledadBootstrapper +from leap.bitmask.util import force_eval  from leap.common import certs as leap_certs @@ -609,7 +610,8 @@ class EIP(object):          eip_loaded = eip_config.load(eipconfig.get_eipconfig_path(domain))          launcher = get_vpn_launcher() -        if not os.path.isfile(launcher.OPENVPN_BIN_PATH): +        ovpn_path = force_eval(launcher.OPENVPN_BIN_PATH) +        if not os.path.isfile(ovpn_path):              logger.error("Cannot start OpenVPN, binary not found")              return False diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index b282a229..79fdd554 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -70,10 +70,10 @@ NOTFOUND_MSG = ("Tried to install %s, but %s "  BADEXEC_MSG = ("Tried to install %s, but %s "                 "failed to %s.") -UPDOWN_NOTFOUND_MSG = NOTFOUND_MSG % ( -    "updown scripts", "those were") -UPDOWN_BADEXEC_MSG = BADEXEC_MSG % ( -    "updown scripts", "they", "be copied") +HELPERS_NOTFOUND_MSG = NOTFOUND_MSG % ( +    "helper files", "those were") +HELPERS_BADEXEC_MSG = BADEXEC_MSG % ( +    "helper files", "they", "be copied")  def get_missing_updown_dialog(): @@ -88,7 +88,7 @@ def get_missing_updown_dialog():                        "to install helper files. "                        "Do you want to proceed?")      msg = QtGui.QMessageBox() -    msg.setWindowTitle(msg.tr("Missing up/down scripts")) +    msg.setWindowTitle(msg.tr("Missing helper files"))      msg.setText(msg.tr(WE_NEED_POWERS))      # but maybe the user really deserve to know more      #msg.setInformativeText(msg.tr(BECAUSE)) @@ -123,8 +123,10 @@ def check_missing():                      "Installer not found for platform %s." % (_system,))                  return +            print "INSTALL FUN", install_missing_fun +              # XXX maybe move constants to fun -            ok = install_missing_fun(UPDOWN_BADEXEC_MSG, UPDOWN_NOTFOUND_MSG) +            ok = install_missing_fun(HELPERS_BADEXEC_MSG, HELPERS_NOTFOUND_MSG)              if not ok:                  msg = QtGui.QMessageBox()                  msg.setWindowTitle(msg.tr("Problem installing files")) @@ -385,7 +387,7 @@ def _linux_check_resolvconf():  def _linux_install_missing_scripts(badexec, notfound):      """ -    Try to install the missing up/down scripts. +    Try to install the missing helper files.      :param badexec: error for notifying execution error during command.      :type badexec: str @@ -405,6 +407,7 @@ def _linux_install_missing_scripts(badexec, notfound):          polfd, pol_tempfile = tempfile.mkstemp(prefix="leap_installer-")          try:              pkexec = first(launcher.maybe_pkexec()) +              scriptlines = launcher.cmd_for_missing_scripts(installer_path)              with os.fdopen(fd, 'w') as f:                  f.write(scriptlines) @@ -413,6 +416,7 @@ def _linux_install_missing_scripts(badexec, notfound):              os.chmod(tempscript, st.st_mode | stat.S_IEXEC | stat.S_IXUSR |                       stat.S_IXGRP | stat.S_IXOTH)              cmdline = ["%s %s" % (pkexec, tempscript)] +              ret = subprocess.call(                  cmdline, stdout=subprocess.PIPE,                  shell=True) diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py index 955768d1..8ec0c050 100644 --- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py +++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py @@ -29,7 +29,7 @@ from leap.bitmask.util.privilege_policies import LinuxPolicyChecker  from leap.common.files import which  from leap.bitmask.services.eip.vpnlauncher import VPNLauncher  from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException -from leap.bitmask.util import get_path_prefix +from leap.bitmask.util import get_path_prefix, force_eval  from leap.common.check import leap_assert  from leap.bitmask.util import first @@ -105,26 +105,34 @@ leapfile = lambda f: "%s/%s" % (SYSTEM_CONFIG, f)  class LinuxVPNLauncher(VPNLauncher):      PKEXEC_BIN = 'pkexec' -    BITMASK_ROOT = "/usr/sbin/bitmask-root" -    # We assume this is there by our openvpn dependency, and -    # we will put it there on the bundle too. -    if flags.STANDALONE: -        OPENVPN_BIN_PATH = "/usr/sbin/leap-openvpn" -    else: -        OPENVPN_BIN_PATH = "/usr/sbin/openvpn" - -    POLKIT_PATH = LinuxPolicyChecker.get_polkit_path() - -    if flags.STANDALONE: -        RESOLVCONF_BIN_PATH = "/usr/local/sbin/leap-resolvconf" -    else: +    # The following classes depend on force_eval to be called against +    # the classes, to get the evaluation of the standalone flag on runtine. +    # If we keep extending this kind of classes, we should abstract the +    # handling of the STANDALONE flag in a base class + +    class BITMASK_ROOT(object): +        def __call__(self): +            return ("/usr/local/sbin/bitmask-root" if flags.STANDALONE else +                    "/usr/sbin/bitmask-root") + +    class OPENVPN_BIN_PATH(object): +        def __call__(self): +            return ("/usr/local/sbin/leap-openvpn" if flags.STANDALONE else +                    "/usr/sbin/openvpn") + +    class POLKIT_PATH(object): +        def __call__(self): +            # LinuxPolicyChecker will give us the right path if standalone. +            return LinuxPolicyChecker.get_polkit_path() + +    class RESOLVCONF_BIN_PATH(object): +        def __call__(self): +            return ("/usr/local/sbin/leap-resolvconf" if flags.STANDALONE else +                    "/sbin/resolvconf")          # this only will work with debian/ubuntu distros. -        RESOLVCONF_BIN_PATH = "/sbin/resolvconf" -    # XXX openvpn binary TOO -    OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH, -                   RESOLVCONF_BIN_PATH) +    OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH)      @classmethod      def maybe_pkexec(kls): @@ -187,7 +195,7 @@ class LinuxVPNLauncher(VPNLauncher):          command = super(LinuxVPNLauncher, kls).get_vpn_command(              eipconfig, providerconfig, socket_host, socket_port, openvpn_verb) -        command.insert(0, kls.BITMASK_ROOT) +        command.insert(0, force_eval(kls.BITMASK_ROOT))          command.insert(1, "openvpn")          command.insert(2, "start") @@ -207,35 +215,37 @@ class LinuxVPNLauncher(VPNLauncher):          :rtype: str          """ +        bin_paths = force_eval( +            (LinuxVPNLauncher.POLKIT_PATH, +             LinuxVPNLauncher.OPENVPN_BIN_PATH, +             LinuxVPNLauncher.BITMASK_ROOT)) + +        polkit_path, openvpn_bin_path, bitmask_root = bin_paths +          # no system config for now          # sys_config = kls.SYSTEM_CONFIG          (polkit_file, openvpn_bin_file, -         bitmask_root_file, resolvconf_bin_file) = map( +         bitmask_root_file) = map(              lambda p: os.path.split(p)[-1], -            (kls.POLKIT_PATH, kls.OPENVPN_BIN_PATH, -             kls.BITMASK_ROOT, kls.RESOLVCONF_BIN_PATH)) +            bin_paths)          cmd = '#!/bin/sh\n'          cmd += 'mkdir -p /usr/local/sbin\n'          cmd += 'cp "%s" "%s"\n' % (os.path.join(frompath, polkit_file), -                                   kls.POLKIT_PATH) -        cmd += 'chmod 644 "%s"\n' % (kls.POLKIT_PATH, ) +                                   polkit_path) +        cmd += 'chmod 644 "%s"\n' % (polkit_path, )          cmd += 'cp "%s" "%s"\n' % (os.path.join(frompath, bitmask_root_file), -                                   kls.BITMASK_ROOT) -        cmd += 'chmod 744 "%s"\n' % (kls.BITMASK_ROOT, ) +                                   bitmask_root) +        cmd += 'chmod 744 "%s"\n' % (bitmask_root, )          if flags.STANDALONE:              cmd += 'cp "%s" "%s"\n' % (                  os.path.join(frompath, openvpn_bin_file), -                kls.OPENVPN_BIN_PATH) -            cmd += 'chmod 744 "%s"\n' % (kls.POLKIT_PATH, ) +                openvpn_bin_path) +            cmd += 'chmod 744 "%s"\n' % (openvpn_bin_path, ) -            cmd += 'cp "%s" "%s"\n' % ( -                os.path.join(frompath, resolvconf_bin_file), -                kls.RESOLVCONF_BIN_PATH) -            cmd += 'chmod 744 "%s"\n' % (kls.POLKIT_PATH, )          return cmd      @classmethod diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py index 9629afae..58ca0c33 100644 --- a/src/leap/bitmask/services/eip/vpnlauncher.py +++ b/src/leap/bitmask/services/eip/vpnlauncher.py @@ -30,6 +30,7 @@ from leap.bitmask.config.leapsettings import LeapSettings  from leap.bitmask.config.providerconfig import ProviderConfig  from leap.bitmask.platform_init import IS_LINUX  from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector +from leap.bitmask.util import force_eval  from leap.common.check import leap_assert, leap_assert_type @@ -179,12 +180,13 @@ class VPNLauncher(object):              #raise OpenVPNNotFoundException()          #openvpn = first(openvpn_possibilities)          # ----------------------------------------- -        if not os.path.isfile(kls.OPENVPN_BIN_PATH): +        openvpn_path = force_eval(kls.OPENVPN_BIN_PATH) + +        if not os.path.isfile(openvpn_path):              logger.warning("Could not find openvpn bin in path %s" % ( -                kls.OPENVPN_BIN_PATH)) +                openvpn_path))              raise OpenVPNNotFoundException() -        openvpn = kls.OPENVPN_BIN_PATH          args = []          args += [ @@ -248,7 +250,7 @@ class VPNLauncher(object):              '--ping', '10',              '--ping-restart', '30'] -        command_and_args = [openvpn] + args +        command_and_args = [openvpn_path] + args          return command_and_args      @classmethod @@ -293,7 +295,8 @@ class VPNLauncher(object):          leap_assert(kls.OTHER_FILES is not None,                      "Need to define OTHER_FILES for this particular "                      "auncher before calling this method") +        other = force_eval(kls.OTHER_FILES)          file_exist = partial(_has_other_files, warn=False) -        zipped = zip(kls.OTHER_FILES, map(file_exist, kls.OTHER_FILES)) +        zipped = zip(other, map(file_exist, other))          missing = filter(lambda (path, exists): exists is False, zipped)          return [path for path, exists in missing] diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index f56d464e..b54f2925 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -43,7 +43,7 @@ from leap.bitmask.services.eip import get_vpn_launcher  from leap.bitmask.services.eip import linuxvpnlauncher  from leap.bitmask.services.eip.eipconfig import EIPConfig  from leap.bitmask.services.eip.udstelnet import UDSTelnet -from leap.bitmask.util import first +from leap.bitmask.util import first, force_eval  from leap.bitmask.platform_init import IS_MAC, IS_LINUX  from leap.common.check import leap_assert, leap_assert_type @@ -233,7 +233,7 @@ class VPN(object):          # XXX could check for wrapper existence, check it's root owned etc.          # XXX could check that the iptables rules are in place. -        BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT +        BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)          cmd = ["pkexec", BM_ROOT, "firewall", "start"]          if restart:              cmd.append("restart") @@ -246,7 +246,7 @@ class VPN(object):          :rtype: bool          """ -        BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT +        BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)          fw_up_cmd = "pkexec {0} firewall isup".format(BM_ROOT)          fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256          return fw_is_down() @@ -255,7 +255,7 @@ class VPN(object):          """          Tear the firewall down using the privileged wrapper.          """ -        BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT +        BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)          exitCode = subprocess.call(["pkexec",                                      BM_ROOT, "firewall", "stop"])          return True if exitCode is 0 else False diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py index c35be99e..25b86874 100644 --- a/src/leap/bitmask/util/__init__.py +++ b/src/leap/bitmask/util/__init__.py @@ -110,3 +110,22 @@ def make_address(user, provider):      :type provider: basestring      """      return "%s@%s" % (user, provider) + + +def force_eval(items): +    """ +    Return a sequence that evaluates any callable in the sequence, +    instantiating it beforehand if the item is a class, and +    leaves the non-callable items without change. +    """ +    def do_eval(thing): +        if isinstance(thing, type): +            return thing()() +        if callable(thing): +            return thing() +        return thing + +    if isinstance(items, (list, tuple)): +        return map(do_eval, items) +    else: +        return do_eval(items) diff --git a/src/leap/bitmask/util/privilege_policies.py b/src/leap/bitmask/util/privilege_policies.py index 9d1e2c9a..adc3503f 100644 --- a/src/leap/bitmask/util/privilege_policies.py +++ b/src/leap/bitmask/util/privilege_policies.py @@ -24,6 +24,8 @@ import platform  from abc import ABCMeta, abstractmethod +from leap.bitmask.config import flags +  logger = logging.getLogger(__name__) @@ -71,6 +73,8 @@ class LinuxPolicyChecker(PolicyChecker):      """      LINUX_POLKIT_FILE = ("/usr/share/polkit-1/actions/"                           "se.leap.bitmask.policy") +    LINUX_POLKIT_FILE_BUNDLE = ("/usr/share/polkit-1/actions/" +                                "se.leap.bitmask.bundle.policy")      @classmethod      def get_polkit_path(self): @@ -79,7 +83,8 @@ class LinuxPolicyChecker(PolicyChecker):          :rtype: str          """ -        return self.LINUX_POLKIT_FILE +        return (self.LINUX_POLKIT_FILE_BUNDLE if flags.STANDALONE +                else self.LINUX_POLKIT_FILE)      def is_missing_policy_permissions(self):      # FIXME this name is quite confusing, it does not have anything to do with @@ -90,4 +95,5 @@ class LinuxPolicyChecker(PolicyChecker):          :rtype: bool          """ -        return not os.path.isfile(self.LINUX_POLKIT_FILE) +        path = self.get_polkit_path() +        return not os.path.isfile(path) | 
